diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ *.BASE.* *.LOCAL.* *.REMOTE.* + +# do not ignore .kdev4 files from test data +!projectmanagers/custom-buildsystem/tests/projects/**/.kdev4 diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,11 @@ +cmake_minimum_required(VERSION 2.8.12) + # KDevelop version set(KDEVELOP_VERSION_MAJOR 5) -set(KDEVELOP_VERSION_MINOR 0) -set(KDEVELOP_VERSION_PATCH 80) +set(KDEVELOP_VERSION_MINOR 1) +set(KDEVELOP_VERSION_PATCH 40) set( KDEVELOP_VERSION "${KDEVELOP_VERSION_MAJOR}.${KDEVELOP_VERSION_MINOR}.${KDEVELOP_VERSION_PATCH}" ) -################################################################################ - -cmake_minimum_required(VERSION 2.8.12) - project(KDevelop) # we need some parts of the ECM CMake helpers @@ -92,6 +90,9 @@ if (HAVE_TUC_FLAG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=tautological-undefined-compare") endif() +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdocumentation") +endif() include_directories(${KDevelop_SOURCE_DIR} ${KDevelop_BINARY_DIR} ) diff --git a/analyzers/cppcheck/config/globalconfigpage.ui b/analyzers/cppcheck/config/globalconfigpage.ui --- a/analyzers/cppcheck/config/globalconfigpage.ui +++ b/analyzers/cppcheck/config/globalconfigpage.ui @@ -11,6 +11,9 @@ + + 0 + diff --git a/analyzers/cppcheck/job.h b/analyzers/cppcheck/job.h --- a/analyzers/cppcheck/job.h +++ b/analyzers/cppcheck/job.h @@ -43,7 +43,7 @@ Q_OBJECT public: - Job(const Parameters& params, QObject* parent = nullptr); + explicit Job(const Parameters& params, QObject* parent = nullptr); ~Job() override; void start() override; diff --git a/analyzers/cppcheck/parameters.cpp b/analyzers/cppcheck/parameters.cpp --- a/analyzers/cppcheck/parameters.cpp +++ b/analyzers/cppcheck/parameters.cpp @@ -46,8 +46,11 @@ child->type() == KDevelop::ProjectBaseItem::ProjectItemType::LibraryTarget || child->type() == KDevelop::ProjectBaseItem::ProjectItemType::Target) { - foreach (auto dir, child->project()->buildSystemManager()->includeDirectories(child)) - includes.insert(dir); + if (auto buildSystemManager = child->project()->buildSystemManager()) { + foreach (auto dir, buildSystemManager->includeDirectories(child)) { + includes.insert(dir); + } + } } includesForItem(child, includes); @@ -107,7 +110,10 @@ extraParameters = projectSettings.extraParameters(); m_projectRootPath = m_project->path(); - m_projectBuildPath = m_project->buildSystemManager()->buildDirectory(m_project->projectItem()); + + if (auto buildSystemManager = m_project->buildSystemManager()) { + m_projectBuildPath = buildSystemManager->buildDirectory(m_project->projectItem()); + } m_includeDirectories = includesForProject(project); } @@ -124,7 +130,7 @@ const QString mocMessage = i18n( "It seems that this project uses Qt library. For correctly work of cppcheck " - "the value for define Q_MOC_OUTPUT_REVISION must be set. Unfortunatly, the plugin is unable " + "the value for define Q_MOC_OUTPUT_REVISION must be set. Unfortunately, the plugin is unable " "to find this value automatically - you should set it manually by adding " "'-DQ_MOC_OUTPUT_REVISION=XX' to extra parameters. The 'XX' value can be found in any project's " "moc-generated file or in the header file."); @@ -198,12 +204,12 @@ if (m_project && useProjectIncludes) { QList ignored; - foreach (QString element, applyPlaceholders(ignoredIncludes).split(';')) { + foreach (const QString& element, applyPlaceholders(ignoredIncludes).split(';')) { if (!element.trimmed().isEmpty()) ignored.append(KDevelop::Path(element)); } - foreach (auto dir, m_includeDirectories) { + foreach (const auto& dir, m_includeDirectories) { if (ignored.contains(dir)) continue; diff --git a/analyzers/cppcheck/parser.cpp b/analyzers/cppcheck/parser.cpp --- a/analyzers/cppcheck/parser.cpp +++ b/analyzers/cppcheck/parser.cpp @@ -42,19 +42,19 @@ }; /** - * Convert the value of attribute of element from cppcheck's + * Convert the value of \ attribute of \ element from cppcheck's * XML-output to 'good-looking' HTML-version. This is necessary because the * displaying of the original message is performed without line breaks - such * tooltips are uncomfortable to read, and large messages will not fit into the * screen. * - * This function put the original message into tag that automatically + * This function put the original message into \ tag that automatically * provides line wrapping by builtin capabilities of Qt library. The source text * also can contain tokens '\012' (line break) - they are present in the case of * source code examples. In such cases, the entire text between the first and - * last tokens (i.e. source code) is placed into
 tag.
+ * last tokens (i.e. source code) is placed into \ tag.
  *
- * @param[in] input the original value of  attribute
+ * @param[in] input the original value of \ attribute
  * @return HTML version for displaying in problem's tooltip
  */
 QString verboseMessageToHtml( const QString & input )
diff --git a/analyzers/cppcheck/plugin.h b/analyzers/cppcheck/plugin.h
--- a/analyzers/cppcheck/plugin.h
+++ b/analyzers/cppcheck/plugin.h
@@ -42,7 +42,7 @@
     Q_OBJECT
 
 public:
-    Plugin(QObject* parent, const QVariantList& = QVariantList());
+    explicit Plugin(QObject* parent, const QVariantList& = QVariantList());
 
     ~Plugin() override;
 
diff --git a/analyzers/cppcheck/plugin.cpp b/analyzers/cppcheck/plugin.cpp
--- a/analyzers/cppcheck/plugin.cpp
+++ b/analyzers/cppcheck/plugin.cpp
@@ -300,18 +300,12 @@
 
 KDevelop::ConfigPage* Plugin::perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent)
 {
-    if (number)
-        return nullptr;
-    else
-        return new ProjectConfigPage(this, options.project, parent);
+    return number ? nullptr : new ProjectConfigPage(this, options.project, parent);
 }
 
 KDevelop::ConfigPage* Plugin::configPage(int number, QWidget* parent)
 {
-    if (number)
-        return nullptr;
-    else
-        return new GlobalConfigPage(this, parent);
+    return number ? nullptr : new GlobalConfigPage(this, parent);
 }
 
 }
diff --git a/app/main.cpp b/app/main.cpp
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -120,10 +120,7 @@
         : QApplication(argc, argv, GUIenabled)
 #endif
         {
-#if KDEVELOP_SINGLE_APP
             Q_UNUSED(GUIenabled);
-#endif
-
             connect(this, &QGuiApplication::saveStateRequest, this, &KDevelopApplication::saveState);
         }
 
@@ -166,7 +163,7 @@
             }
 
             QString kdevelopSessionId = activeSession->id().toString();
-            sm.setRestartCommand(QStringList() << QCoreApplication::applicationFilePath() << "-session" << x11SessionId << "-s" << kdevelopSessionId);
+            sm.setRestartCommand({QCoreApplication::applicationFilePath(), "-session", x11SessionId, "-s", kdevelopSessionId});
         }
     }
 };
@@ -211,7 +208,7 @@
     QDBusMessage makeVisible = QDBusMessage::createMethodCall( service, "/kdevelop/MainWindow", "org.kdevelop.MainWindow",
                                                                "ensureVisible" );
     QDBusConnection::sessionBus().asyncCall( makeVisible );
-    return errors_occured ? 1 : 0;
+    return errors_occured;
 }
 
 /// Gets the PID of a running KDevelop instance, eventually asking the user if there is more than one.
@@ -313,7 +310,7 @@
 
     static const char description[] = I18N_NOOP( "The KDevelop Integrated Development Environment" );
     KAboutData aboutData( "kdevelop", i18n( "KDevelop" ), QByteArray(VERSION), i18n(description), KAboutLicense::GPL,
-                          i18n("Copyright 1999-2016, The KDevelop developers"), QString(), "http://www.kdevelop.org/");
+                          i18n("Copyright 1999-2017, The KDevelop developers"), QString(), "https://www.kdevelop.org/");
     aboutData.setDesktopFileName(QStringLiteral("org.kde.kdevelop.desktop"));
     aboutData.addAuthor( i18n("Kevin Funk"), i18n( "Co-maintainer, C++/Clang, QA, Windows Support" ), "kfunk@kde.org" );
     aboutData.addAuthor( i18n("Sven Brauch"), i18n( "Co-maintainer, AppImage, Python Support, User Interface improvements" ), "svenbrauch@gmail.com" );
@@ -387,13 +384,11 @@
         for (int i=0; i < c; ++i) {
             if (debugFound) {
                 debugArgs << argv[i];
-            } else if (qstrcmp(argv[i], "--debug") == 0 || qstrcmp(argv[i], "-d") == 0) {
-                if (argc <= i+1) {
-                    argc = i + 1;
-                } else {
+            } else if ((qstrcmp(argv[i], "--debug") == 0) || (qstrcmp(argv[i], "-d") == 0)) {
+                if (argc > (i + 1)) {
                     i++;
-                    argc = i + 1;
                 }
+                argc = i + 1;
                 debugFound = true;
             } else if (QString(argv[i]).startsWith("--debug=")) {
                 argc = i + 1;
@@ -646,7 +641,7 @@
 
     KDevIDEExtension::init();
 
-    if(!Core::initialize(nullptr, Core::Default, session))
+    if(!Core::initialize(Core::Default, session))
         return 5;
 
     // register a DBUS service for this process, so that we can open files in it from other invocations
@@ -660,29 +655,27 @@
     }
 
     QStringList projectNames = parser.values("project");
-    if(!projectNames.isEmpty())
+    foreach(const QString& projectName, projectNames)
     {
-        foreach(const QString& p, projectNames)
-        {
-            QFileInfo info( p );
-            if( info.suffix() == "kdev4" ) {
-                // make sure the project is not already opened by the session controller
-                bool shouldOpen = true;
-                Path path(info.absoluteFilePath());
-                foreach(KDevelop::IProject* p, core->projectController()->projects()) {
-                    if (p->projectFile() == path) {
-                        shouldOpen = false;
-                        break;
-                    }
-                }
-                if (shouldOpen) {
-                    core->projectController()->openProject( path.toUrl() );
+        QFileInfo info( projectName );
+        if( info.suffix() == "kdev4" ) {
+            // make sure the project is not already opened by the session controller
+            bool shouldOpen = true;
+            Path path(info.absoluteFilePath());
+            foreach(KDevelop::IProject* project, core->projectController()->projects()) {
+                if (project->projectFile() == path) {
+                    shouldOpen = false;
+                    break;
                 }
             }
+            if (shouldOpen) {
+                core->projectController()->openProject( path.toUrl() );
+            }
         }
     }
 
-    if ( parser.isSet("debug") ) {
+    const QString debugStr = QStringLiteral("debug");
+    if ( parser.isSet(debugStr) ) {
         Q_ASSERT( !debugeeName.isEmpty() );
         QString launchName = debugeeName;
 
@@ -710,21 +703,21 @@
         }
 
         if (launch && launch->type()->id() != "Native Application") launch = nullptr;
-        if (launch && launch->launcherForMode("debug") != parser.value("debug")) launch = nullptr;
+        if (launch && launch->launcherForMode(debugStr) != parser.value(debugStr)) launch = nullptr;
         if (!launch) {
             qCDebug(APP) << launchName << "not found, creating a new one";
             QPair launcher;
-            launcher.first = "debug";
+            launcher.first = debugStr;
             foreach (KDevelop::ILauncher *l, type->launchers()) {
-                if (l->id() == parser.value("debug")) {
-                    if (l->supportedModes().contains("debug")) {
+                if (l->id() == parser.value(debugStr)) {
+                    if (l->supportedModes().contains(debugStr)) {
                         launcher.second = l->id();
                     }
                 }
             }
             if (launcher.second.isEmpty()) {
                 QTextStream qerr(stderr);
-                qerr << endl << i18n("Cannot find launcher %1", parser.value("debug")) << endl;
+                qerr << endl << i18n("Cannot find launcher %1", parser.value(debugStr)) << endl;
                 return 1;
             }
             KDevelop::ILaunchConfiguration* ilaunch = core->runController()->createLaunchConfiguration(type, launcher, nullptr, launchName);
@@ -735,7 +728,7 @@
         launch->config().writeEntry("Break on Start", true);
         core->runControllerInternal()->setDefaultLaunch(launch);
 
-        core->runControllerInternal()->execute("debug", launch);
+        core->runControllerInternal()->execute(debugStr, launch);
     } else {
         openFiles(initialFiles);
     }
diff --git a/app/urlinfo.h b/app/urlinfo.h
--- a/app/urlinfo.h
+++ b/app/urlinfo.h
@@ -21,9 +21,9 @@
 #ifndef URLINFO_H
 #define URLINFO_H
 
+#include 
 #include 
 
-#include 
 #include 
 #include 
 #include 
@@ -39,7 +39,7 @@
      * Parses a file path argument and determines its line number and column and full path
      * @param path path passed on e.g. command line to parse into an URL
      */
-    UrlInfo(QString path = QString())
+    explicit UrlInfo(QString path = QString())
         : cursor(KTextEditor::Cursor::invalid())
     {
         /**
@@ -58,20 +58,13 @@
          * ok, the path as is, is no existing file, now, cut away :xx:yy stuff as cursor
          * this will make test:50 to test with line 50
          */
-        const auto match = QRegularExpression(QStringLiteral(":(\\d+)(?::(\\d+))?:?$")).match(path);
-        if (match.isValid()) {
+        int pathLength;
+        cursor = KDevelop::KTextEditorHelpers::extractCursor(path, &pathLength);
+        if (cursor.isValid()) {
             /**
              * cut away the line/column specification from the path
              */
-            path.chop(match.capturedLength());
-
-            /**
-             * set right cursor position
-             * don't use an invalid column when the line is valid
-             */
-            const int line = match.captured(1).toInt() - 1;
-            const int column = qMax(0, match.captured(2).toInt() - 1);
-            cursor.setPosition(line, column);
+            path.truncate(pathLength);
         }
 
         /**
diff --git a/debuggers/common/dialogs/processselection.h b/debuggers/common/dialogs/processselection.h
--- a/debuggers/common/dialogs/processselection.h
+++ b/debuggers/common/dialogs/processselection.h
@@ -32,7 +32,7 @@
 {
     Q_OBJECT
     public:
-        ProcessSelectionDialog( QWidget *parent=nullptr );
+        explicit ProcessSelectionDialog( QWidget *parent=nullptr );
         ~ProcessSelectionDialog() override;
         long int pidSelected();
         QSize sizeHint() const override;
diff --git a/debuggers/common/dialogs/selectcoredialog.h b/debuggers/common/dialogs/selectcoredialog.h
--- a/debuggers/common/dialogs/selectcoredialog.h
+++ b/debuggers/common/dialogs/selectcoredialog.h
@@ -32,7 +32,7 @@
 class SelectCoreDialog : public QDialog
 {
 public:
-    SelectCoreDialog(QWidget *parent = nullptr);
+    explicit SelectCoreDialog(QWidget *parent = nullptr);
     QUrl binary() const;
     QUrl core() const;
 
diff --git a/debuggers/common/mi/mi.h b/debuggers/common/mi/mi.h
--- a/debuggers/common/mi/mi.h
+++ b/debuggers/common/mi/mi.h
@@ -250,7 +250,7 @@
 
     struct StringLiteralValue : public Value
     {
-        StringLiteralValue(const QString &lit)
+        explicit StringLiteralValue(const QString &lit)
             : literal_(lit) { Value::kind = StringLiteral; }
 
     public: // Value overrides
@@ -305,7 +305,7 @@
 
     struct ResultRecord : public TupleRecord
     {
-        ResultRecord(const QString& reason)
+        explicit ResultRecord(const QString& reason)
             : token(0)
             , reason(reason)
         {
@@ -357,7 +357,7 @@
             Log
         };
 
-        StreamRecord(Subkind subkind)
+        explicit StreamRecord(Subkind subkind)
             : subkind(subkind)
         {
             Record::kind = Stream;
diff --git a/debuggers/common/mi/micommand.h b/debuggers/common/mi/micommand.h
--- a/debuggers/common/mi/micommand.h
+++ b/debuggers/common/mi/micommand.h
@@ -82,7 +82,7 @@
 public:
     typedef std::function Function;
 
-    FunctionCommandHandler(const Function& callback, CommandFlags flags = nullptr);
+    explicit FunctionCommandHandler(const Function& callback, CommandFlags flags = nullptr);
 
     void handle(const ResultRecord&) override;
     bool handlesError() override;
@@ -99,7 +99,7 @@
 class MICommand
 {
 protected:
-    MICommand(CommandType type, const QString& arguments = QString(), CommandFlags flags = nullptr);
+    explicit MICommand(CommandType type, const QString& arguments = QString(), CommandFlags flags = nullptr);
     friend class KDevMI::MIDebugSession;
 
 public:
@@ -280,7 +280,7 @@
         };
     }
 
-    SentinelCommand(const Function& handler, CommandFlags flags = nullptr)
+    explicit SentinelCommand(const Function& handler, CommandFlags flags = nullptr)
         : MICommand(NonMI, QString(), flags)
         , handler(handler)
     {
diff --git a/debuggers/common/mibreakpointcontroller.h b/debuggers/common/mibreakpointcontroller.h
--- a/debuggers/common/mibreakpointcontroller.h
+++ b/debuggers/common/mibreakpointcontroller.h
@@ -64,7 +64,7 @@
 {
     Q_OBJECT
 public:
-    MIBreakpointController(MIDebugSession* parent);
+    explicit MIBreakpointController(MIDebugSession* parent);
 
     using IBreakpointController::breakpointModel;
 
diff --git a/debuggers/common/mibreakpointcontroller.cpp b/debuggers/common/mibreakpointcontroller.cpp
--- a/debuggers/common/mibreakpointcontroller.cpp
+++ b/debuggers/common/mibreakpointcontroller.cpp
@@ -167,7 +167,7 @@
 };
 
 struct MIBreakpointController::IgnoreChanges {
-    IgnoreChanges(MIBreakpointController& controller)
+    explicit IgnoreChanges(MIBreakpointController& controller)
         : controller(controller)
     {
         ++controller.m_ignoreChanges;
diff --git a/debuggers/common/midebugjobs.h b/debuggers/common/midebugjobs.h
--- a/debuggers/common/midebugjobs.h
+++ b/debuggers/common/midebugjobs.h
@@ -66,7 +66,7 @@
 {
     Q_OBJECT
 public:
-    MIExamineCoreJob(MIDebuggerPlugin *plugin, QObject *parent = nullptr);
+    explicit MIExamineCoreJob(MIDebuggerPlugin *plugin, QObject *parent = nullptr);
 
     void start() override;
 
diff --git a/debuggers/common/midebugsession.cpp b/debuggers/common/midebugsession.cpp
--- a/debuggers/common/midebugsession.cpp
+++ b/debuggers/common/midebugsession.cpp
@@ -1177,7 +1177,7 @@
     if (m_tty){
         m_tty->readRemaining();
         // Tty is no longer usable, delete it. Without this, QSocketNotifier
-        // will continiously bomd STTY with signals, so we need to either disable
+        // will continuously bomd STTY with signals, so we need to either disable
         // QSocketNotifier, or delete STTY. The latter is simpler, since we can't
         // reuse it for future debug sessions anyway.
         m_tty.reset(nullptr);
@@ -1249,7 +1249,7 @@
     if (m_tty){
         m_tty->readRemaining();
         // Tty is no longer usable, delete it. Without this, QSocketNotifier
-        // will continiously bomd STTY with signals, so we need to either disable
+        // will continuously bomd STTY with signals, so we need to either disable
         // QSocketNotifier, or delete STTY. The latter is simpler, since we can't
         // reuse it for future debug sessions anyway.
         m_tty.reset(nullptr);
diff --git a/debuggers/common/miframestackmodel.h b/debuggers/common/miframestackmodel.h
--- a/debuggers/common/miframestackmodel.h
+++ b/debuggers/common/miframestackmodel.h
@@ -34,7 +34,7 @@
 class MIFrameStackModel : public KDevelop::FrameStackModel
 {
 public:
-    MIFrameStackModel( MIDebugSession* session);
+    explicit MIFrameStackModel( MIDebugSession* session);
 
     MIDebugSession* session();
 
diff --git a/debuggers/common/mivariable.h b/debuggers/common/mivariable.h
--- a/debuggers/common/mivariable.h
+++ b/debuggers/common/mivariable.h
@@ -43,7 +43,7 @@
 
     ~MIVariable();
 
-    /* FIXME: should eventually remove, so that existance of
+    /* FIXME: should eventually remove, so that existence of
         varobjs is fully encapsulalated inside GdbVariable.  */
     const QString& varobj() const;
     void handleUpdate(const MI::Value& var);
diff --git a/debuggers/common/mivariable.cpp b/debuggers/common/mivariable.cpp
--- a/debuggers/common/mivariable.cpp
+++ b/debuggers/common/mivariable.cpp
@@ -321,7 +321,7 @@
 class SetFormatHandler : public MICommandHandler
 {
 public:
-    SetFormatHandler(MIVariable *var)
+    explicit SetFormatHandler(MIVariable *var)
         : m_variable(var)
     {}
 
diff --git a/debuggers/common/mivariablecontroller.h b/debuggers/common/mivariablecontroller.h
--- a/debuggers/common/mivariablecontroller.h
+++ b/debuggers/common/mivariablecontroller.h
@@ -42,7 +42,7 @@
     Q_OBJECT
 
 public:
-    MIVariableController( MIDebugSession* parent);
+    explicit MIVariableController( MIDebugSession* parent);
 
     KDevelop::Variable* createVariable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
                                        const QString& expression,
diff --git a/debuggers/common/mivariablecontroller.cpp b/debuggers/common/mivariablecontroller.cpp
--- a/debuggers/common/mivariablecontroller.cpp
+++ b/debuggers/common/mivariablecontroller.cpp
@@ -110,7 +110,7 @@
 class StackListArgumentsHandler : public MICommandHandler
 {
 public:
-    StackListArgumentsHandler(QStringList localsName)
+    explicit StackListArgumentsHandler(QStringList localsName)
         : m_localsName(localsName)
     {}
 
@@ -139,7 +139,7 @@
 class StackListLocalsHandler : public MICommandHandler
 {
 public:
-    StackListLocalsHandler(MIDebugSession *session)
+    explicit StackListLocalsHandler(MIDebugSession *session)
         : m_session(session)
     {}
 
diff --git a/debuggers/common/registers/registercontroller.h b/debuggers/common/registers/registercontroller.h
--- a/debuggers/common/registers/registercontroller.h
+++ b/debuggers/common/registers/registercontroller.h
@@ -157,7 +157,7 @@
     virtual void setRegisterValue(const Register& reg);
 
 protected:
-    IRegisterController(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
+    explicit IRegisterController(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
 
     ///Returns registers from the @p group, or empty registers group if @p group is invalid.
     virtual RegistersGroup registersFromGroup(const GroupsName& group) const = 0;
diff --git a/debuggers/common/registers/registercontroller_arm.h b/debuggers/common/registers/registercontroller_arm.h
--- a/debuggers/common/registers/registercontroller_arm.h
+++ b/debuggers/common/registers/registercontroller_arm.h
@@ -31,7 +31,7 @@
 {
 public:
 
-    RegisterController_Arm(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
+    explicit RegisterController_Arm(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
 
     QVector namesOfRegisterGroups() const override;
 
diff --git a/debuggers/common/registers/registercontroller_x86.h b/debuggers/common/registers/registercontroller_x86.h
--- a/debuggers/common/registers/registercontroller_x86.h
+++ b/debuggers/common/registers/registercontroller_x86.h
@@ -36,7 +36,7 @@
     void updateRegisters(const GroupsName& group = GroupsName()) override;
 
 protected:
-    RegisterControllerGeneral_x86(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
+    explicit RegisterControllerGeneral_x86(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
 
     RegistersGroup registersFromGroup(const GroupsName& group) const override;
 
@@ -71,7 +71,7 @@
 {
 
 public:
-    RegisterController_x86(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
+    explicit RegisterController_x86(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
 
 private:
     void initRegisterNames();
@@ -81,7 +81,7 @@
 {
 
 public:
-    RegisterController_x86_64(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
+    explicit RegisterController_x86_64(MIDebugSession* debugSession = nullptr, QObject* parent = nullptr);
 
 private:
     void initRegisterNames();
diff --git a/debuggers/common/registers/registersmanager.h b/debuggers/common/registers/registersmanager.h
--- a/debuggers/common/registers/registersmanager.h
+++ b/debuggers/common/registers/registersmanager.h
@@ -46,7 +46,7 @@
 
 public:
 
-    ArchitectureParser(QObject* parent);
+    explicit ArchitectureParser(QObject* parent);
 
     ///Asynchronously determines current architecture. emits @p architectureParsed when ready.
     void determineArchitecture(MIDebugSession* debugSession);
@@ -68,7 +68,7 @@
     Q_OBJECT
 
 public:
-    RegistersManager(QWidget* parent);
+    explicit RegistersManager(QWidget* parent);
 
 public Q_SLOTS:
     void setSession(MIDebugSession* debugSession);
diff --git a/debuggers/common/registers/registersview.h b/debuggers/common/registers/registersview.h
--- a/debuggers/common/registers/registersview.h
+++ b/debuggers/common/registers/registersview.h
@@ -38,7 +38,7 @@
     Q_OBJECT
 
 public:
-    RegistersView(QWidget* p = nullptr);
+    explicit RegistersView(QWidget* p = nullptr);
 
     void enable(bool enabled);
 
diff --git a/debuggers/common/stty.h b/debuggers/common/stty.h
--- a/debuggers/common/stty.h
+++ b/debuggers/common/stty.h
@@ -39,7 +39,7 @@
     Q_OBJECT
 
 public:
-    STTY(bool ext=false, const QString &termAppName=QString());
+    explicit STTY(bool ext=false, const QString &termAppName=QString());
     ~STTY() override;
 
     ///Call it if getSlave returns an empty string.
diff --git a/debuggers/common/widgets/debuggerconsoleview.h b/debuggers/common/widgets/debuggerconsoleview.h
--- a/debuggers/common/widgets/debuggerconsoleview.h
+++ b/debuggers/common/widgets/debuggerconsoleview.h
@@ -52,11 +52,11 @@
 {
     Q_OBJECT
 public:
-    DebuggerConsoleView(MIDebuggerPlugin *plugin, QWidget *parent = nullptr);
+    explicit DebuggerConsoleView(MIDebuggerPlugin *plugin, QWidget *parent = nullptr);
     ~DebuggerConsoleView();
 
     /**
-     * Whether show a button allowing user to interrput debugger execution.
+     * Whether show a button allowing user to interrupt debugger execution.
      */
     void setShowInterrupt(bool enable);
 
diff --git a/debuggers/common/widgets/disassemblewidget.h b/debuggers/common/widgets/disassemblewidget.h
--- a/debuggers/common/widgets/disassemblewidget.h
+++ b/debuggers/common/widgets/disassemblewidget.h
@@ -51,7 +51,7 @@
 {
     Q_OBJECT
 public:
-    SelectAddressDialog(QWidget *parent = nullptr);
+    explicit SelectAddressDialog(QWidget *parent = nullptr);
 
     QString address() const;
     void setAddress(const QString& address);
@@ -109,7 +109,7 @@
         ColumnCount
     };
 
-    DisassembleWidget( MIDebuggerPlugin* plugin, QWidget *parent=nullptr );
+    explicit DisassembleWidget( MIDebuggerPlugin* plugin, QWidget *parent=nullptr );
     ~DisassembleWidget() override;
 
 Q_SIGNALS:
diff --git a/debuggers/gdb/TODO.txt b/debuggers/gdb/TODO.txt
--- a/debuggers/gdb/TODO.txt
+++ b/debuggers/gdb/TODO.txt
@@ -43,7 +43,7 @@
 
       - Debugging optimized binaries
 
-      - Debugged application somtimes not killed.
+      - Debugged application sometimes not killed.
 
       - Fix moving breakpoints on editing files
 
diff --git a/debuggers/gdb/debuggerplugin.h b/debuggers/gdb/debuggerplugin.h
--- a/debuggers/gdb/debuggerplugin.h
+++ b/debuggers/gdb/debuggerplugin.h
@@ -67,7 +67,7 @@
 public:
     friend class DebugSession;
 
-    CppDebuggerPlugin(QObject *parent, const QVariantList & = QVariantList());
+    explicit CppDebuggerPlugin(QObject *parent, const QVariantList & = QVariantList());
     ~CppDebuggerPlugin() override;
 
     DebugSession *createSession() override;
diff --git a/debuggers/gdb/gdbbreakpointcontroller.h b/debuggers/gdb/gdbbreakpointcontroller.h
--- a/debuggers/gdb/gdbbreakpointcontroller.h
+++ b/debuggers/gdb/gdbbreakpointcontroller.h
@@ -33,7 +33,7 @@
     Q_OBJECT
 
 public:
-    BreakpointController(DebugSession *parent);
+    explicit BreakpointController(DebugSession *parent);
 private:
 };
 
diff --git a/debuggers/gdb/gdbconfigpage.h b/debuggers/gdb/gdbconfigpage.h
--- a/debuggers/gdb/gdbconfigpage.h
+++ b/debuggers/gdb/gdbconfigpage.h
@@ -58,7 +58,7 @@
 {
 Q_OBJECT
 public:
-    GdbConfigPage( QWidget* parent = nullptr );
+    explicit GdbConfigPage( QWidget* parent = nullptr );
     ~GdbConfigPage() override;
     QIcon icon() const override;
     void loadFromConfiguration(const KConfigGroup& cfg, KDevelop::IProject* = nullptr) override;
diff --git a/debuggers/gdb/gdbframestackmodel.h b/debuggers/gdb/gdbframestackmodel.h
--- a/debuggers/gdb/gdbframestackmodel.h
+++ b/debuggers/gdb/gdbframestackmodel.h
@@ -32,7 +32,7 @@
 {
     Q_OBJECT
 public:
-    GdbFrameStackModel(DebugSession* session);
+    explicit GdbFrameStackModel(DebugSession* session);
 
     DebugSession* session();
 };
diff --git a/debuggers/gdb/gdboutputwidget.h b/debuggers/gdb/gdboutputwidget.h
--- a/debuggers/gdb/gdboutputwidget.h
+++ b/debuggers/gdb/gdboutputwidget.h
@@ -51,7 +51,7 @@
     Q_OBJECT
 
 public:
-    GDBOutputWidget(CppDebuggerPlugin* plugin, QWidget *parent=nullptr );
+    explicit GDBOutputWidget(CppDebuggerPlugin* plugin, QWidget *parent=nullptr );
     ~GDBOutputWidget() override;
 
     void savePartialProjectSession();
@@ -144,7 +144,7 @@
     Q_OBJECT
 
 public:
-    OutputTextEdit(GDBOutputWidget* parent);
+    explicit OutputTextEdit(GDBOutputWidget* parent);
 
 protected:
     void contextMenuEvent(QContextMenuEvent* event) override;
diff --git a/debuggers/gdb/memviewdlg.h b/debuggers/gdb/memviewdlg.h
--- a/debuggers/gdb/memviewdlg.h
+++ b/debuggers/gdb/memviewdlg.h
@@ -42,7 +42,7 @@
     {
         Q_OBJECT
     public:
-        MemoryViewerWidget(CppDebuggerPlugin* plugin, QWidget* parent = nullptr);
+        explicit MemoryViewerWidget(CppDebuggerPlugin* plugin, QWidget* parent = nullptr);
 
     public Q_SLOTS:
         /** Adds a new memory view. */
@@ -65,7 +65,7 @@
     {
         Q_OBJECT
     public:
-        MemoryView(QWidget* parent);
+        explicit MemoryView(QWidget* parent);
 
         void debuggerStateChanged(DBGStateFlags state);
 
diff --git a/debuggers/gdb/printers/tests/qlistcontainer.cpp b/debuggers/gdb/printers/tests/qlistcontainer.cpp
--- a/debuggers/gdb/printers/tests/qlistcontainer.cpp
+++ b/debuggers/gdb/printers/tests/qlistcontainer.cpp
@@ -8,7 +8,7 @@
 #include 
 
 struct A {
-    A(const QString& _a = QString(), const QString& _b = QString(),
+    explicit A(const QString& _a = QString(), const QString& _b = QString(),
       int _c = -1, int _d = -1)
     : a(_a), b(_b), c(_c), d(_d)
     {}
diff --git a/debuggers/gdb/printers/tests/qtprinters.cpp b/debuggers/gdb/printers/tests/qtprinters.cpp
--- a/debuggers/gdb/printers/tests/qtprinters.cpp
+++ b/debuggers/gdb/printers/tests/qtprinters.cpp
@@ -31,7 +31,7 @@
 class GdbProcess : private QProcess
 {
 public:
-    GdbProcess(const QString &program) : QProcess()
+    explicit GdbProcess(const QString &program) : QProcess()
     {
         setProcessChannelMode(MergedChannels);
         // don't attempt to load .gdbinit in home (may cause unexpected results)
diff --git a/debuggers/gdb/unittests/test_gdb.cpp b/debuggers/gdb/unittests/test_gdb.cpp
--- a/debuggers/gdb/unittests/test_gdb.cpp
+++ b/debuggers/gdb/unittests/test_gdb.cpp
@@ -140,7 +140,7 @@
 class TestLaunchConfiguration : public KDevelop::ILaunchConfiguration
 {
 public:
-    TestLaunchConfiguration(const QUrl& executable = findExecutable("debugee"),
+    explicit TestLaunchConfiguration(const QUrl& executable = findExecutable("debugee"),
                             const QUrl& workingDirectory = QUrl()) {
         qDebug() << "FIND" << executable;
         c = new KConfig();
@@ -169,7 +169,7 @@
 {
 public:
 
-    TestFrameStackModel(DebugSession* session)
+    explicit TestFrameStackModel(DebugSession* session)
         : GdbFrameStackModel(session), fetchFramesCalled(0), fetchThreadsCalled(0) {}
 
     int fetchFramesCalled;
diff --git a/debuggers/gdb/variablecontroller.h b/debuggers/gdb/variablecontroller.h
--- a/debuggers/gdb/variablecontroller.h
+++ b/debuggers/gdb/variablecontroller.h
@@ -33,7 +33,7 @@
     Q_OBJECT
 
 public:
-    VariableController(DebugSession* parent);
+    explicit VariableController(DebugSession* parent);
 
 private:
     DebugSession* debugSession() const;
diff --git a/debuggers/lldb/TODO.txt b/debuggers/lldb/TODO.txt
--- a/debuggers/lldb/TODO.txt
+++ b/debuggers/lldb/TODO.txt
@@ -46,7 +46,11 @@
         + [DONE] KDevelop::Path
         + [DONE] KTextEditor::Cursor
         + [DONE] KTextEditor::Range
+    * lldb-mi doesn't properly quote string in most MI records, so can't use \\ or " in names
 - Finish unit tests for LLDB data formatters
+- Qt data formatter cause hangs data size is too large
+    * [DONE] use dynamic caching
+    * invalid object detect
 
 - [DONE] Show application exit reason in the Debug View
 
@@ -57,9 +61,6 @@
     * disassembly widget
     * memory view
 
-- Qt data formatter cause hangs data size is too large
-    * use dynamic caching
-
 - [DONE] Find a way to avoid duplicate tool views for GDB and LLDB plugin
 
 - Polish debugger console
diff --git a/debuggers/lldb/controllers/breakpointcontroller.h b/debuggers/lldb/controllers/breakpointcontroller.h
--- a/debuggers/lldb/controllers/breakpointcontroller.h
+++ b/debuggers/lldb/controllers/breakpointcontroller.h
@@ -33,7 +33,7 @@
     Q_OBJECT
 
 public:
-    BreakpointController(DebugSession *parent);
+    explicit BreakpointController(DebugSession *parent);
 private:
 };
 
diff --git a/debuggers/lldb/controllers/framestackmodel.h b/debuggers/lldb/controllers/framestackmodel.h
--- a/debuggers/lldb/controllers/framestackmodel.h
+++ b/debuggers/lldb/controllers/framestackmodel.h
@@ -38,7 +38,7 @@
 {
     Q_OBJECT
 public:
-    LldbFrameStackModel(DebugSession* session);
+    explicit LldbFrameStackModel(DebugSession* session);
 
     DebugSession* session();
 
diff --git a/debuggers/lldb/controllers/framestackmodel.cpp b/debuggers/lldb/controllers/framestackmodel.cpp
--- a/debuggers/lldb/controllers/framestackmodel.cpp
+++ b/debuggers/lldb/controllers/framestackmodel.cpp
@@ -69,7 +69,7 @@
     // TODO: preliminary test shows there might be a bug in lldb-mi
     // that's causing std::logic_error when executing -thread-info with
     // more than one threads. Find a workaround for this (and report bug
-    // if it truely is).
+    // if it truly is).
     session()->addCommand(ThreadInfo, "", this, &LldbFrameStackModel::handleThreadInfo);
 }
 
diff --git a/debuggers/lldb/controllers/variable.cpp b/debuggers/lldb/controllers/variable.cpp
--- a/debuggers/lldb/controllers/variable.cpp
+++ b/debuggers/lldb/controllers/variable.cpp
@@ -49,19 +49,18 @@
         return;
     }
 
-
     // update the value itself
     QPointer guarded_this(this);
     debugSession->addCommand(VarEvaluateExpression, varobj_, [guarded_this](const ResultRecord &r){
         if (guarded_this && r.reason == "done" && r.hasField("value")) {
-            guarded_this->setValue(r["value"].literal());
+            guarded_this->setValue(guarded_this->formatValue(r["value"].literal()));
         }
     });
 
     // update children
     // remove all children first, this will cause some gliches in the UI, but there's no good way
     // that we can know if there's anything changed
-    if (isExpanded()) {
+    if (isExpanded() || !childCount()) {
         deleteChildren();
         fetchMoreChildren();
     }
@@ -114,6 +113,9 @@
         return Utils::quote(Utils::unquote(value, true));
     } else if (value.startsWith('\'')) {
         return Utils::quote(Utils::unquote(value, true, '\''), '\'');
+    } else if (value.startsWith('b')) {
+        // this is a byte array, don't translate unicode, simply return without 'b' prefix
+        return value.mid(1);
     }
     return value;
 }
diff --git a/debuggers/lldb/controllers/variablecontroller.h b/debuggers/lldb/controllers/variablecontroller.h
--- a/debuggers/lldb/controllers/variablecontroller.h
+++ b/debuggers/lldb/controllers/variablecontroller.h
@@ -34,7 +34,7 @@
     Q_OBJECT
 
 public:
-    VariableController(DebugSession* parent);
+    explicit VariableController(DebugSession* parent);
 
     void update() override;
     LldbVariable* createVariable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
diff --git a/debuggers/lldb/controllers/variablecontroller.cpp b/debuggers/lldb/controllers/variablecontroller.cpp
--- a/debuggers/lldb/controllers/variablecontroller.cpp
+++ b/debuggers/lldb/controllers/variablecontroller.cpp
@@ -54,11 +54,11 @@
         variableCollection()->watches()->reinstall();
     }
 
-   if (autoUpdate() & UpdateLocals) {
+    if (autoUpdate() & UpdateLocals) {
         updateLocals();
-   }
+    }
 
-   if ((autoUpdate() & UpdateLocals) ||
+    if ((autoUpdate() & UpdateLocals) ||
        ((autoUpdate() & UpdateWatches) && variableCollection()->watches()->childCount() > 0))
     {
         debugSession()->updateAllVariables();
diff --git a/debuggers/lldb/debuggerplugin.h b/debuggers/lldb/debuggerplugin.h
--- a/debuggers/lldb/debuggerplugin.h
+++ b/debuggers/lldb/debuggerplugin.h
@@ -34,7 +34,7 @@
 class NonInterruptDebuggerConsoleView : public DebuggerConsoleView
 {
 public:
-    NonInterruptDebuggerConsoleView(MIDebuggerPlugin *plugin, QWidget *parent = nullptr)
+    explicit NonInterruptDebuggerConsoleView(MIDebuggerPlugin *plugin, QWidget *parent = nullptr)
         : DebuggerConsoleView(plugin, parent)
     {
         setShowInterrupt(false);
@@ -49,7 +49,7 @@
 public:
     friend class KDevMI::LLDB::DebugSession;
 
-    LldbDebuggerPlugin(QObject *parent, const QVariantList & = QVariantList());
+    explicit LldbDebuggerPlugin(QObject *parent, const QVariantList & = QVariantList());
     ~LldbDebuggerPlugin() override;
 
     DebugSession *createSession() override;
diff --git a/debuggers/lldb/debugsession.cpp b/debuggers/lldb/debugsession.cpp
--- a/debuggers/lldb/debugsession.cpp
+++ b/debuggers/lldb/debugsession.cpp
@@ -57,7 +57,7 @@
 
 struct ExecRunHandler : public MICommandHandler
 {
-    ExecRunHandler(DebugSession *session, int maxRetry = 5)
+    explicit ExecRunHandler(DebugSession *session, int maxRetry = 5)
         : m_session(session)
         , m_remainRetry(maxRetry)
         , m_activeCommands(1)
diff --git a/debuggers/lldb/formatters/helpers.py b/debuggers/lldb/formatters/helpers.py
--- a/debuggers/lldb/formatters/helpers.py
+++ b/debuggers/lldb/formatters/helpers.py
@@ -21,7 +21,7 @@
 
 # BEGIN: Utilities for wrapping differences of Python 2.x and Python 3
 # Inspired by http://pythonhosted.org/six/
-
+from __future__ import print_function
 import sys
 import lldb
 # Useful for very coarse version differentiation.
@@ -38,11 +38,21 @@
             return type(self).__next__(self)
 if PY3:
     unichr = chr
+    unicode = str
 else:
     unichr = unichr
 # END
 
 
+def canonicalized_type_name(name):
+    """Canonicalize the type name for FindFirstType usage.
+        + 1 space between template arguments (after comma)
+        + no space before pointer *
+    otherwise FindFirstType returns None
+    """
+    return name.replace(' ', '').replace(',', ', ')
+
+
 def quote(string, quote='"'):
     """Quote a string so it's suitable to be used in quote"""
     if isinstance(string, unicode):
@@ -65,22 +75,25 @@
                                   q=quote)
 
 
-def unquote(string, quote='"'):
+def unquote(data, quote='"'):
     """Unquote a string"""
-    if string.startswith(quote) and string.endswith(quote):
-        string = string.lstrip(quote).rstrip(quote)
+    if data.startswith(quote) and data.endswith(quote):
+        data = data[1:-1]
         ls = []
         esc = False
-        for idx in range(0, len(string)):
-            ch = string[idx]
-            if ch == '\\':
-                if esc:
-                    ls.append(ch)
-                esc = not esc
-            else:
+        for ch in data:
+            if esc:
                 ls.append(ch)
-        string = ''.join(ls)
-    return string
+                esc = False
+            else:
+                if ch == '\\':
+                    esc = True
+                else:
+                    ls.append(ch)
+        if esc:
+            print('WARNING: unpaired escape')
+        data = ''.join(ls)
+    return data
 
 
 def invoke(val, method, args=''):
@@ -105,8 +118,8 @@
     # third, build expression
     expr = 'reinterpret_cast({})->{}({})'.format(ptype.GetName(), addr, method, args)
     res = frame.EvaluateExpression(expr)
-    #if not res.IsValid():
-        #print 'Expr {} on value {} failed'.format(expr, val.GetName())
+    # if not res.IsValid():
+    #     print 'Expr {} on value {} failed'.format(expr, val.GetName())
     return res
 
 
@@ -209,7 +222,7 @@
             # it might be overwriten by others if we cache them.
             # child is a (name, expr) tuple in this case
             if len(child) != 2:
-                print 'error, const char[] value should be a tuple with two elements, it is', child
+                print('error, const char[] value should be a tuple with two elements, it is', child)
             return self.valobj.CreateValueFromExpression(*child)
 
     @staticmethod
diff --git a/debuggers/lldb/formatters/kde.py b/debuggers/lldb/formatters/kde.py
--- a/debuggers/lldb/formatters/kde.py
+++ b/debuggers/lldb/formatters/kde.py
@@ -19,13 +19,10 @@
 # along with this program.  If not, see .
 #
 
-import lldb
-
-from helpers import *
 
 def __lldb_init_module(debugger, unused):
     debugger.HandleCommand('type summary add KDevelop::Path -w kdevelop-kde -F kde.KDevPathSummaryProvider')
-    debugger.HandleCommand('type summary add KTextEditor::Cursor -w kdevelop-kde -F kde.KTextEditorCursorSummaryProvider')
+    debugger.HandleCommand('type summary add KTextEditor::Cursor -w kdevelop-kde -F kde.KTextEditorCursorSummaryProvider')  # noqa: E501
     debugger.HandleCommand('type summary add KTextEditor::Range -w kdevelop-kde -F kde.KTextEditorRangeSummaryProvider')
 
     debugger.HandleCommand('type category enable kdevelop-kde')
diff --git a/debuggers/lldb/formatters/qt.py b/debuggers/lldb/formatters/qt.py
--- a/debuggers/lldb/formatters/qt.py
+++ b/debuggers/lldb/formatters/qt.py
@@ -18,16 +18,19 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see .
 #
+from __future__ import print_function
 
-import calendar
 import time
 import datetime as dt
+import string
 from urlparse import urlsplit, urlunsplit
 
 import locale
 import lldb
 
-from helpers import *
+from helpers import (HiddenMemberProvider, quote, unquote, unichr, toSBPointer, Iterator, validAddr,
+                     validPointer, invoke, rename, canonicalized_type_name)
+
 
 def __lldb_init_module(debugger, unused):
     debugger.HandleCommand('type synthetic add QString -w kdevelop-qt -l qt.QStringFormatter')
@@ -87,7 +90,7 @@
     debugger.HandleCommand('type summary add -x QDateTime -w kdevelop-qt -e -F qt.QDateTimeSummaryProvider')
 
     debugger.HandleCommand('type synthetic add QUrl -w kdevelop-qt -l qt.QUrlFormatter')
-    debugger.HandleCommand('type summary add QUrl -w kdevelop-qt -e -s "${svar.(encoded)}"')
+    debugger.HandleCommand('type summary add QUrl -w kdevelop-qt -e -F qt.QUrlSummaryProvider')
 
     debugger.HandleCommand('type synthetic add QUuid -w kdevelop-qt -l qt.QUuidFormatter')
     debugger.HandleCommand('type summary add QUuid -w kdevelop-qt -F qt.QUuidSummaryProvider')
@@ -110,7 +113,6 @@
         if isQt4:
             alloc += 1
 
-
         # some sanity check to see if we are dealing with garbage
         if size_val < 0 or size_val >= alloc:
             return None, 0, 0
@@ -120,7 +122,6 @@
             tooLarge = u'...'
             size_val = HiddenMemberProvider._capping_size()
 
-
         if isQt4:
             pointer = data.GetValueAsUnsigned(0)
         elif offset.IsValid():
@@ -143,8 +144,8 @@
             # The QString object might be not yet initialized. In this case size is a bogus value,
             # and memory access may fail
             if error.Success():
-                string = string_data.decode('utf-16')
-                return string + tooLarge, pointer, length
+                content = string_data.decode('utf-16')
+                return content + tooLarge, pointer, length
         except:
             pass
     return None, 0, 0
@@ -154,12 +155,14 @@
     if valobj.IsValid():
         content = valobj.GetChildMemberWithName('(content)')
         if content.IsValid():
-            return content.GetSummary()
-        else:
-            # No synthetic provider installed, get the content by ourselves
-            printable, _, _ = printableQString(valobj)
-            if printable is not None:
-                return quote(printable)
+            summary = content.GetSummary()
+            if summary is not None:
+                return summary
+        # Something wrong with synthetic provider, or
+        # no synthetic provider installed, get the content by ourselves
+        printable, _, _ = printableQString(valobj)
+        if printable is not None:
+            return quote(printable)
     return ''
 
 
@@ -189,7 +192,11 @@
 def QCharSummaryProvider(valobj, internal_dict):
     if valobj.IsValid():
         ucs = valobj.GetChildMemberWithName('ucs').GetValueAsUnsigned(0)
-        return unichr(ucs).__repr__().lstrip('u')
+        if ucs == 39:
+            # for '\'', python returns "'" rather than '\''
+            return u"'\\''"
+        else:
+            return unichr(ucs).__repr__()[1:]
     return None
 
 
@@ -234,14 +241,15 @@
             if error.Success():
                 # replace non-ascii byte with a space and get a printable version
                 ls = list(string_data)
-                for idx in range(0, length):
-                    byte = ord(ls[idx])
-                    if byte >= 128 or byte < 0:
-                        ls[idx] = hex(byte).replace('0', '\\', 1)
-                    elif byte == 0: # specical handle for 0, as hex(0) returns '\\x0'
-                        ls[idx] = '\\x00'
-                string = u''.join(ls)
-                return string + tooLarge, pointer, length
+                for idx in range(length):
+                    if ls[idx] in string.printable:
+                        if ls[idx] != "'":
+                            # convert tab, nl, ..., and '\\' to r'\\'
+                            ls[idx] = ls[idx].__repr__()[1:-1]
+                    else:
+                        ls[idx] = r'\x{:02x}'.format(ord(ls[idx]))
+                content = u''.join(ls)
+                return content + tooLarge, pointer, length
         except:
             pass
     return None, 0, 0
@@ -251,12 +259,17 @@
     if valobj.IsValid():
         content = valobj.GetChildMemberWithName('(content)')
         if content.IsValid():
-            return content.GetSummary()
-        else:
-            # Our synthetic provider is not installed, get the content by ourselves
-            printable, _, _ = printableQByteArray(valobj)
-            if printable is not None:
-                return quote(printable)
+            summary = content.GetSummary()
+            if summary is not None:
+                # unlike QString, we quoted the (content) twice to preserve our own quotation,
+                # must undo the quotation done by GetSummary
+                return 'b' + unquote(summary)
+        # Something wrong with our synthetic provider, get the content by ourselves
+        printable, _, _ = printableQByteArray(valobj)
+        if printable is not None:
+            # first replace " to \", and suround by "", no need to escape other things which
+            # are handled in printableQByteArray.
+            return 'b"{}"'.format(printable.replace('"', '\\"'))
     return ''
 
 
@@ -278,6 +291,12 @@
                                                          dataPointer + idx * self._char_size,
                                                          self._char_type)
                 self._addChild(var)
+
+            # first replace " to \", and suround by "", no need to escape other things which
+            # are handled in printableQByteArray.
+            printable = '"{}"'.format(printable.replace('"', '\\"'))
+            # then we need to quote again, as the quoted_printable_expr is parsed by the lldb to
+            # produce the final content, which removes one level of quotation
             quoted_printable_expr = quote(printable)
             self._addChild(('(content)', quoted_printable_expr), hidden=True)
 
@@ -294,20 +313,20 @@
         pvoid_type = valobj.GetTarget().GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
         self._pvoid_size = pvoid_type.GetByteSize()
 
-        #from QTypeInfo::isLarge
+        # from QTypeInfo::isLarge
         isLarge = self._item_type.GetByteSize() > self._pvoid_size
 
-        #unfortunately we can't use QTypeInfo::isStatic as it's all inlined, so use
-        #this list of types that use Q_DECLARE_TYPEINFO(T, Q_MOVABLE_TYPE)
-        #(obviously it won't work for custom types)
+        # unfortunately we can't use QTypeInfo::isStatic as it's all inlined, so use
+        # this list of types that use Q_DECLARE_TYPEINFO(T, Q_MOVABLE_TYPE)
+        # (obviously it won't work for custom types)
         movableTypes = ['QRect', 'QRectF', 'QString', 'QMargins', 'QLocale', 'QChar', 'QDate',
                         'QTime', 'QDateTime', 'QVector', 'QRegExpr', 'QPoint', 'QPointF', 'QByteArray',
                         'QSize', 'QSizeF', 'QBitArray', 'QLine', 'QLineF', 'QModelIndex',
                         'QPersitentModelIndex', 'QVariant', 'QFileInfo', 'QUrl', 'QXmlStreamAttribute',
                         'QXmlStreamNamespaceDeclaration', 'QXmlStreamNotationDeclaration',
                         'QXmlStreamEntityDeclaration', 'QPair']
         movableTypes = [valobj.GetTarget().FindFirstType(t) for t in movableTypes]
-        #this list of types that use Q_DECLARE_TYPEINFO(T, Q_PRIMITIVE_TYPE) (from qglobal.h)
+        # this list of types that use Q_DECLARE_TYPEINFO(T, Q_PRIMITIVE_TYPE) (from qglobal.h)
         primitiveTypes = ['bool', 'char', 'signed char', 'unsigned char', 'short', 'unsigned short',
                           'int', 'unsigned int', 'long', 'unsigned long', 'long long',
                           'unsigned long long', 'float', 'double']
@@ -318,7 +337,7 @@
         else:
             isStatic = not self._item_type.IsPointerType()
 
-        #see QList::Node::t()
+        # see QList::Node::t()
         self._externalStorage = isLarge or isStatic
         # If is external storage, then the node (a void*) is a pointer to item
         # else the item is stored inside the node
@@ -400,7 +419,7 @@
         if not toSBPointer(self.valobj, pArray, self._item_type).IsValid():
             return
 
-        #self._num_children = d.GetChildMemberWithName('size').GetValueAsUnsigned(0)
+        # self._num_children = d.GetChildMemberWithName('size').GetValueAsUnsigned(0)
         self._num_children = d.GetChildMemberWithName('size').GetValueAsSigned(-1)
         if self._num_children < 0:
             return
@@ -506,7 +525,9 @@
 
     key = valobj.GetChildMemberWithName('key')
     value = valobj.GetChildMemberWithName('value')
-    return '({}, {})'.format(key.GetSummary(), value.GetValue())
+    key_summary = key.GetSummary() or key.GetValue()  # show value if summary is empty or None
+    val_summary = value.GetSummary() or value.GetValue()  # show value if summary is empty or None
+    return '({}, {})'.format(key_summary, val_summary)
 
 
 class BasicMapFormatter(HiddenMemberProvider):
@@ -520,6 +541,7 @@
         # the ' ' between two template arguments is significant,
         # otherwise FindFirstType returns None
         node_typename = 'QMapNode<{}, {}>'.format(key_type.GetName(), val_type.GetName())
+        node_typename = canonicalized_type_name(node_typename)
         self._node_type = valobj.GetTarget().FindFirstType(node_typename)
 
         e = self.valobj.GetChildMemberWithName('e')
@@ -697,10 +719,10 @@
         self_type = valobj.GetType()
         self._key_type = self_type.GetTemplateArgumentType(0)
         self._val_type = self_type.GetTemplateArgumentType(1)
-        # the ' ' between two template arguments is significant,
-        # otherwise FindFirstType returns None
         node_typename = 'QHashNode<{}, {}>'.format(self._key_type.GetName(),
                                                    self._val_type.GetName())
+        node_typename = canonicalized_type_name(node_typename)
+
         self._node_type = valobj.GetTarget().FindFirstType(node_typename)
 
     class _iterator(Iterator):
@@ -768,6 +790,10 @@
 
         idx = 0
         for pnode in self._iterator(self.valobj, self._node_type.GetPointerType()):
+            if idx >= self._num_children:
+                self._members = []
+                self._num_children = 0
+                break
             # dereference node and change to a user friendly name
             name = '[{}]'.format(idx)
             idx += 1
@@ -797,6 +823,7 @@
         self.valobj = self.actualobj.GetChildAtIndex(0)
         super(QMultiHashFormatter, self).update()
 
+
 class QSetFormatter(HiddenMemberProvider):
     """lldb synthetic provider for QSet"""
 
@@ -807,7 +834,6 @@
 
     def num_children(self):
         return self._num_children
-        pass
 
     def _update(self):
         self._hash_formatter.valobj = self.valobj.GetChildMemberWithName('q_hash')
@@ -840,76 +866,75 @@
         if julianDay >= 2299161:
             # Gregorian calendar starting from October 15, 1582
             # This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern
-            ell = julianDay + 68569;
-            n = (4 * ell) / 146097;
-            ell = ell - (146097 * n + 3) / 4;
-            i = (4000 * (ell + 1)) / 1461001;
-            ell = ell - (1461 * i) / 4 + 31;
-            j = (80 * ell) / 2447;
-            d = ell - (2447 * j) / 80;
-            ell = j / 11;
-            m = j + 2 - (12 * ell);
-            y = 100 * (n - 49) + i + ell;
+            ell = julianDay + 68569
+            n = (4 * ell) / 146097
+            ell = ell - (146097 * n + 3) / 4
+            i = (4000 * (ell + 1)) / 1461001
+            ell = ell - (1461 * i) / 4 + 31
+            j = (80 * ell) / 2447
+            d = ell - (2447 * j) / 80
+            ell = j / 11
+            m = j + 2 - (12 * ell)
+            y = 100 * (n - 49) + i + ell
         else:
             # Julian calendar until October 4, 1582
             # Algorithm from Frequently Asked Questions about Calendars by Claus Toendering
-            julianDay += 32082;
-            dd = (4 * julianDay + 3) / 1461;
-            ee = julianDay - (1461 * dd) / 4;
-            mm = ((5 * ee) + 2) / 153;
-            d = ee - (153 * mm + 2) / 5 + 1;
-            m = mm + 3 - 12 * (mm / 10);
-            y = dd - 4800 + (mm / 10);
+            julianDay += 32082
+            dd = (4 * julianDay + 3) / 1461
+            ee = julianDay - (1461 * dd) / 4
+            mm = ((5 * ee) + 2) / 153
+            d = ee - (153 * mm + 2) / 5 + 1
+            m = mm + 3 - 12 * (mm / 10)
+            y = dd - 4800 + (mm / 10)
             if y <= 0:
                 return None
         return dt.date(y, m, d)
 
     def _update(self):
         # FIXME: Calling functions returns incorrect SBValue for complex type in lldb
-        ## toString
-        #res = invoke(self.valobj, 'toString', '0')
-        #self._addChild(rename('toString', res))
+        # # toString
+        # res = invoke(self.valobj, 'toString', '0')
+        # self._addChild(rename('toString', res))
 
         # jd
         julianDay = self.valobj.GetChildMemberWithName('jd')
         self._addChild(julianDay)
 
-
         pydate = self.parse(julianDay.GetValueAsUnsigned(0))
         if pydate is None:
             return
         # (ISO)
-        iso_str = pydate.isoformat().decode().__repr__().lstrip("u'").rstrip("'")
+        iso_str = pydate.isoformat().decode().__repr__()[2:-1]
         self._addChild(('(ISO)', quote(iso_str)))
 
         # (Locale)
         locale_encoding = [locale.getlocale()[1]]
         if locale_encoding[0] is None:
             locale_encoding = []
-        locale_str = pydate.strftime('%x').decode(*locale_encoding).__repr__().lstrip("u'").rstrip("'")
+        locale_str = pydate.strftime('%x').decode(*locale_encoding).__repr__()[2:-1]
         self._addChild(('(Locale)', quote(locale_str)))
 
 
 def QDateSummaryProvider(valobj, internal_dict):
     if valobj.IsValid():
         content = valobj.GetChildMemberWithName('(Locale)')
         if content.IsValid():
-            return content.GetSummary()
-        else:
-            # No synthetic provider installed, get the content by ourselves
-            pydate = QDateFormatter.parse(valobj.GetChildMemberWithName('jd').GetValueAsUnsigned(0))
-            if pydate is not None:
-                content = pydate.isoformat().decode().__repr__().lstrip("u'").rstrip("'")
-                return quote(content)
+            summary = content.GetSummary()
+            if summary is not None:
+                return summary
+        # No synthetic provider installed, get the content by ourselves
+        pydate = QDateFormatter.parse(valobj.GetChildMemberWithName('jd').GetValueAsUnsigned(0))
+        if pydate is not None:
+            return pydate.isoformat().decode().__repr__()[2:-1]
     return ''
 
 
 class QTimeFormatter(HiddenMemberProvider):
     """lldb synthetic provider for QTime"""
     def __init__(self, valobj, internal_dict):
         super(QTimeFormatter, self).__init__(valobj, internal_dict)
         self._add_original = False
-        
+
     def has_children(self):
         return True
 
@@ -923,15 +948,15 @@
 
         hour = ds / MSECS_PER_HOUR
         minute = (ds % MSECS_PER_HOUR) / MSECS_PER_MIN
-        second = (ds / 1000)%SECS_PER_MIN
+        second = (ds / 1000) % SECS_PER_MIN
         msec = ds % 1000
         return dt.time(hour, minute, second, msec)
 
     def _update(self):
         # FIXME: Calling functions returns incorrect SBValue for complex type in lldb
-        ## toString
-        #res = invoke(self.valobj, 'toString', '0')
-        #self._addChild(rename('toString', res))
+        # # toString
+        # res = invoke(self.valobj, 'toString', '0')
+        # self._addChild(rename('toString', res))
 
         # mds
         mds = self.valobj.GetChildMemberWithName('mds')
@@ -941,36 +966,36 @@
         if pytime is None:
             return
         # (ISO)
-        iso_str = pytime.isoformat().decode().__repr__().lstrip("u'").rstrip("'")
+        iso_str = pytime.isoformat().decode().__repr__()[2:-1]
         self._addChild(('(ISO)', quote(iso_str)))
 
         # (Locale)
         locale_encoding = [locale.getlocale()[1]]
         if locale_encoding[0] is None:
             locale_encoding = []
-        locale_str = pytime.strftime('%X').decode(*locale_encoding).__repr__().lstrip("u'").rstrip("'")
+        locale_str = pytime.strftime('%X').decode(*locale_encoding).__repr__()[2:-1]
         self._addChild(('(Locale)', quote(locale_str)))
 
 
 def QTimeSummaryProvider(valobj, internal_dict):
     if valobj.IsValid():
         content = valobj.GetChildMemberWithName('(Locale)')
         if content.IsValid():
-            return content.GetSummary()
-        else:
-            # No synthetic provider installed, get the content by ourselves
-            pytime = QTimeFormatter.parse(valobj.GetChildMemberWithName('mds').GetValueAsUnsigned(0))
-            if pytime is not None:
-                content = pytime.isoformat().decode().__repr__().lstrip("u'").rstrip("'")
-                return quote(content)
+            summary = content.GetSummary()
+            if summary is not None:
+                return summary
+        # No synthetic provider installed, get the content by ourselves
+        pytime = QTimeFormatter.parse(valobj.GetChildMemberWithName('mds').GetValueAsUnsigned(0))
+        if pytime is not None:
+            return pytime.isoformat().decode().__repr__()[2:-1]
     return None
 
 
 class QDateTimeFormatter(HiddenMemberProvider):
     """lldb synthetic provider for QTime"""
     def __init__(self, valobj, internal_dict):
         super(QDateTimeFormatter, self).__init__(valobj, internal_dict)
-    
+
     def has_children(self):
         return True
 
@@ -1006,43 +1031,43 @@
         utc_tt = self.parse(time_t.GetValueAsUnsigned(0), utc=True)
 
         # (ISO)
-        formatted = time.strftime('%Y-%m-%d %H:%M:%S', utc_tt).decode(*locale_encoding).__repr__().lstrip("u'").rstrip("'")
+        formatted = time.strftime('%Y-%m-%d %H:%M:%S', utc_tt).decode(*locale_encoding).__repr__()
+        formatted = formatted[2:-1]
         self._addChild(('(ISO)', quote(formatted)))
 
         def locale_fmt(name, tt):
-            formatted = time.strftime('%c', tt).decode(*locale_encoding).__repr__().lstrip("u'").rstrip("'")
+            formatted = time.strftime('%c', tt).decode(*locale_encoding).__repr__()[2:-1]
             self._addChild((name, quote(formatted)))
 
         # (Locale)
         locale_fmt('(Locale)', local_tt)
 
         # (UTC)
         locale_fmt('(UTC)', utc_tt)
-        
+
         # FIXME: Calling functions returns incorrect SBValue for complex type in lldb
-        ## toString
-        #res = invoke(self.valobj, 'toString', '0')
-        #print 'tostring', res
-        #self._addChild(rename('toString', res))
+        # # toString
+        # res = invoke(self.valobj, 'toString', '0')
+        # print 'tostring', res
+        # self._addChild(rename('toString', res))
 
-        ## toLocalTime
-        #res = invoke(self.valobj, 'toTimeSpec', '0')  # Qt::LocalTime == 0
-        #print 'tolocaltime', res
-        #self._addChild(rename('toLocalTime', res))
+        # # toLocalTime
+        # res = invoke(self.valobj, 'toTimeSpec', '0')  # Qt::LocalTime == 0
+        # print 'tolocaltime', res
+        # self._addChild(rename('toLocalTime', res))
 
 
 def QDateTimeSummaryProvider(valobj, internal_dict):
     if valobj.IsValid():
         content = valobj.GetChildMemberWithName('(Locale)')
         if content.IsValid():
-            return content.GetSummary()
-        else:
-            # No synthetic provider installed, get the content by ourselves
-            pytime = QDateTimeFormatter.parse(QDateTimeFormatter.getdata(valobj).GetValueAsUnsigned(0))
-            if pytime is not None:
-                #content = pytime.isoformat().decode().__repr__().lstrip("u'").rstrip("'")
-                #return quote(content)
-                pass
+            summary = content.GetSummary()
+            if summary is not None:
+                return summary
+        # No synthetic provider installed, get the content by ourselves
+        pytime = QDateTimeFormatter.parse(QDateTimeFormatter.getdata(valobj).GetValueAsUnsigned(0))
+        if pytime is not None:
+            return pytime.isoformat().decode().__repr__()[2:-1]
     return None
 
 
@@ -1065,10 +1090,11 @@
                 username_str = printableQString(username)[0]
                 if username_str is not None:
                     netloc += username_str
-                password_str = printableQString(password)[0]
-                if password_str is not None:
-                    netloc += ':' + password_str
-                netloc += "@" + host_str
+                    password_str = printableQString(password)[0]
+                    if password_str is not None:
+                        netloc += ':' + password_str
+                    netloc += "@"
+                netloc += host_str
                 port_num = port.GetValueAsSigned(-1)
                 if port_num != -1:
                     netloc += ":" + str(port_num)
@@ -1169,51 +1195,63 @@
             return (None,) * 9
         return parseComponents(encoded)
 
-    def _update(self):
+    def try_parse(self):
         dataobj = self.valobj.GetChildMemberWithName('d')
         # first try to access Qt4 data
         (encoded, port, scheme,
          username, password, host, path, query, fragment) = self.parseQt4Data(dataobj)
         if encoded is not None:
-            self._addChild(port)
-            self._addChild(scheme)
-            self._addChild(username)
-            self._addChild(password)
-            self._addChild(host)
-            self._addChild(path)
-            self._addChild(query)
-            self._addChild(fragment)
-            self._addChild(encoded, hidden=True)
-            return
+            return (encoded, port, scheme, username, password, host, path, query, fragment)
 
         # if this fails, maybe we deal with Qt5
         (encoded, port, scheme,
          username, password, host,
          path, query, fragment) = self.parseQt5Data(dataobj)
         if encoded is not None:
-            self._addChild(port)
-            self._addChild(scheme)
-            self._addChild(username)
-            self._addChild(password)
-            self._addChild(host)
-            self._addChild(path)
-            self._addChild(query)
-            self._addChild(fragment)
-            self._addChild(encoded, hidden=True)
-            return
+            return (encoded, port, scheme, username, password, host, path, query, fragment)
 
         # if above fails, try to print directly.
         # But this might not work, and could lead to issues
         # (see http://sourceware-org.1504.n7.nabble.com/help-Calling-malloc-from-a-Python-pretty-printer-td284031.html)
-        res = invoke(self.valobj, 'toString', '(QUrl::FormattingOptions)0') # QUrl::PrettyDecoded == 0
+        res = invoke(self.valobj, 'toString', '(QUrl::FormattingOptions)0')  # QUrl::PrettyDecoded == 0
         if res.IsValid():
-            self._addChild(rename('(encoded)', res))
+            return rename('(encoded)', res), None, None, None, None, None, None, None, None
+        return None, None, None, None, None, None, None, None, None
 
+    def _update(self):
+        (encoded, port, scheme, username,
+         password, host, path, query, fragment) = self.try_parse()
+        if encoded is not None:
+            self._addChild(encoded, hidden=True)
+            if port is not None:
+                self._addChild(port)
+                self._addChild(scheme)
+                self._addChild(username)
+                self._addChild(password)
+                self._addChild(host)
+                self._addChild(path)
+                self._addChild(query)
+                self._addChild(fragment)
+            return
         # if everything fails, we have no choice but to show the original member
         self._add_original = False
         self._addChild(self.valobj.GetChildMemberWithName('d'))
 
 
+def QUrlSummaryProvider(valobj, internal_dict):
+    if valobj.IsValid():
+        content = valobj.GetChildMemberWithName('(encoded)')
+        if content.IsValid():
+            summary = content.GetSummary()
+            if summary is not None:
+                return summary
+        # No synthetic provider installed, get the content by ourselves
+        encoded = QUrlFormatter(valobj, internal_dict).try_parse()[0][1]
+        if encoded is not None:
+            return encoded
+    return None
+
+
 class QUuidFormatter(HiddenMemberProvider):
     """A lldb synthetic provider for QUuid"""
     def __init__(self, valobj, internal_dict):
diff --git a/debuggers/lldb/lldbcommand.h b/debuggers/lldb/lldbcommand.h
--- a/debuggers/lldb/lldbcommand.h
+++ b/debuggers/lldb/lldbcommand.h
@@ -35,7 +35,7 @@
 class LldbCommand : public MI::MICommand
 {
 protected:
-    LldbCommand(MI::CommandType type, const QString& arguments = QString(),
+    explicit LldbCommand(MI::CommandType type, const QString& arguments = QString(),
                 MI::CommandFlags flags = nullptr);
     friend class KDevMI::LLDB::DebugSession;
 public:
diff --git a/debuggers/lldb/lldbcommand.cpp b/debuggers/lldb/lldbcommand.cpp
--- a/debuggers/lldb/lldbcommand.cpp
+++ b/debuggers/lldb/lldbcommand.cpp
@@ -179,7 +179,7 @@
             }
             break;
         }
-        // find the postion to insert '-f'
+        // find the position to insert '-f'
         case BreakInsert: {
             if (!overrideCmd.isEmpty()) {
                 // already done
diff --git a/debuggers/lldb/unittests/debugees/debugeeqt.cpp b/debuggers/lldb/unittests/debugees/debugeeqt.cpp
--- a/debuggers/lldb/unittests/debugees/debugeeqt.cpp
+++ b/debuggers/lldb/unittests/debugees/debugeeqt.cpp
@@ -27,6 +27,5 @@
         x += QString::number(i);
         qDebug() << x;
     }
-    QString ustr = QString::fromUtf8("\u4f60\u597d\u4e16\u754c");
     return 0;
 }
diff --git a/debuggers/lldb/unittests/debugees/qbytearray.cpp b/debuggers/lldb/unittests/debugees/qbytearray.cpp
--- a/debuggers/lldb/unittests/debugees/qbytearray.cpp
+++ b/debuggers/lldb/unittests/debugees/qbytearray.cpp
@@ -1,7 +1,7 @@
 #include 
 int main()
 {
-    QByteArray ba("test byte array");
+    QByteArray ba("\xe6\x98\xaf'\"\\u6211");
     ba.append("x");
     return 0;
 }
diff --git a/debuggers/lldb/unittests/debugees/qlistcontainer.cpp b/debuggers/lldb/unittests/debugees/qlistcontainer.cpp
--- a/debuggers/lldb/unittests/debugees/qlistcontainer.cpp
+++ b/debuggers/lldb/unittests/debugees/qlistcontainer.cpp
@@ -8,7 +8,7 @@
 #include 
 
 struct A {
-    A(const QString& _a = QString(), const QString& _b = QString(),
+    explicit A(const QString& _a = QString(), const QString& _b = QString(),
       int _c = -1, int _d = -1)
     : a(_a), b(_b), c(_c), d(_d)
     {}
diff --git a/debuggers/lldb/unittests/debugees/qstring.cpp b/debuggers/lldb/unittests/debugees/qstring.cpp
--- a/debuggers/lldb/unittests/debugees/qstring.cpp
+++ b/debuggers/lldb/unittests/debugees/qstring.cpp
@@ -1,7 +1,7 @@
 #include 
 int main()
 {
-    QString s("test string");
+    QString s = QString::fromUtf8("test最后一个不是特殊字符'\"\\u6211");
     s.append("x");
     return 0;
 }
diff --git a/debuggers/lldb/unittests/test_lldb.h b/debuggers/lldb/unittests/test_lldb.h
--- a/debuggers/lldb/unittests/test_lldb.h
+++ b/debuggers/lldb/unittests/test_lldb.h
@@ -100,7 +100,6 @@
     void testVariablesStartSecondSession();
     void testVariablesSwitchFrame();
     void testVariablesQuicklySwitchFrame();
-    void testVariablesNonascii();
     void testSwitchFrameLldbConsole();
 
     void testSegfaultDebugee();
diff --git a/debuggers/lldb/unittests/test_lldb.cpp b/debuggers/lldb/unittests/test_lldb.cpp
--- a/debuggers/lldb/unittests/test_lldb.cpp
+++ b/debuggers/lldb/unittests/test_lldb.cpp
@@ -95,7 +95,7 @@
 class TestLaunchConfiguration : public ILaunchConfiguration
 {
 public:
-    TestLaunchConfiguration(const QUrl& executable = findExecutable("lldb_debugee"),
+    explicit TestLaunchConfiguration(const QUrl& executable = findExecutable("lldb_debugee"),
                             const QUrl& workingDirectory = QUrl()) {
         qDebug() << "FIND" << executable;
         c = new KConfig();
@@ -124,7 +124,7 @@
 {
 public:
 
-    TestFrameStackModel(DebugSession* session)
+    explicit TestFrameStackModel(DebugSession* session)
         : LldbFrameStackModel(session), fetchFramesCalled(0), fetchThreadsCalled(0) {}
 
     void fetchFrames(int threadNumber, int from, int to) override
@@ -1676,26 +1676,6 @@
     WAIT_FOR_STATE(session, DebugSession::EndedState);
 }
 
-void LldbTest::testVariablesNonascii()
-{
-    TestDebugSession *session = new TestDebugSession;
-    TestLaunchConfiguration cfg(findExecutable("lldb_debugeeqt"));
-
-    session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
-
-    QString fileName = findSourceFile("debugeeqt.cpp");
-    breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 30);
-
-    QVERIFY(session->startDebugging(&cfg, m_iface));
-    WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState);
-
-    QCOMPARE(session->currentLine(), 30);
-    COMPARE_DATA(localVariableIndexAt(0, 1), QString("\"\u4f60\u597d\u4e16\u754c\""));
-
-    session->run();
-    WAIT_FOR_STATE(session, DebugSession::EndedState);
-}
-
 void LldbTest::testSwitchFrameLldbConsole()
 {
     TestDebugSession *session = new TestDebugSession;
diff --git a/debuggers/lldb/unittests/test_lldbformatters.h b/debuggers/lldb/unittests/test_lldbformatters.h
--- a/debuggers/lldb/unittests/test_lldbformatters.h
+++ b/debuggers/lldb/unittests/test_lldbformatters.h
@@ -23,8 +23,11 @@
 #ifndef LLDBFORMATTERSTEST_H
 #define LLDBFORMATTERSTEST_H
 
+#include 
 #include 
+#include 
 #include 
+#include 
 
 class IExecutePlugin;
 
@@ -48,38 +51,43 @@
     void init();
     void cleanup();
 
+    void testQChar();
     void testQString();
-    /*
     void testQByteArray();
     void testQListContainer_data();
     void testQListContainer();
+    void testQListPOD();
     void testQMapInt();
     void testQMapString();
     void testQMapStringBool();
-    void testQDate();
-    void testQTime();
-    void testQDateTime();
-    void testQUrl();
     void testQHashInt();
     void testQHashString();
     void testQSetInt();
     void testQSetString();
-    void testQChar();
-    void testQListPOD();
+    void testQDate();
+    void testQTime();
+    void testQDateTime();
+    void testQUrl();
     void testQUuid();
     void testKTextEditorTypes();
     void testKDevelopTypes();
-    */
 
 private:
     // helpers
-    bool verifyQString(int index, const QString &name, const QString &expected,
-                       const char *file, int line);
+    bool verifyVariable(int index, const QString &name,
+                        const QString &expectedSummary, QList> expectedChildren,
+                        const char *file, int line,
+                        bool isLocal = true, bool useRE = false, bool unordered = false);
+
+    bool verifyVariable(int index, const QString &name,
+                        const QString &expectedSummary, QStringList expectedChildren,
+                        const char *file, int line,
+                        bool isLocal = true, bool useRE = false, bool unordered = false);
 
 private:
     KDevelop::Breakpoint* addCodeBreakpoint(const QUrl& location, int line);
     KDevelop::VariableCollection *variableCollection();
-    KDevMI::LLDB::LldbVariable *watchVariableAt(int i);
+    QModelIndex watchVariableIndexAt(int i, int col = 0);
     QModelIndex localVariableIndexAt(int i, int col = 0);
 
     KDevelop::TestCore *m_core;
diff --git a/debuggers/lldb/unittests/test_lldbformatters.cpp b/debuggers/lldb/unittests/test_lldbformatters.cpp
--- a/debuggers/lldb/unittests/test_lldbformatters.cpp
+++ b/debuggers/lldb/unittests/test_lldbformatters.cpp
@@ -40,18 +40,25 @@
 #include 
 
 #include 
+#include 
 #include 
 #include 
 #include 
 
+#include 
+#include 
+
 #define WAIT_FOR_STATE(session, state) \
     do { if (!KDevMI::LLDB::waitForState((session), (state), __FILE__, __LINE__)) return; } while (0)
 
 #define WAIT_FOR_STATE_AND_IDLE(session, state) \
     do { if (!KDevMI::LLDB::waitForState((session), (state), __FILE__, __LINE__, true)) return; } while (0)
 
-#define WAIT_FOR_A_WHILE(session, ms) \
-    do { if (!KDevMI::LLDB::waitForAWhile((session), (ms), __FILE__, __LINE__)) return; } while (0)
+#define WAIT_FOR_A_WHILE_AND_IDLE(session, ms) \
+    do { if (!KDevMI::LLDB::waitForAWhile((session), (ms), __FILE__, __LINE__)) return; \
+         if (!KDevMI::LLDB::waitForState((session), DebugSession::PausedState, __FILE__, __LINE__, true)) \
+             return; \
+    } while (0)
 
 #define WAIT_FOR(session, condition) \
     do { \
@@ -62,8 +69,17 @@
 #define COMPARE_DATA(index, expected) \
     do { if (!KDevMI::LLDB::compareData((index), (expected), __FILE__, __LINE__)) return; } while (0)
 
-#define VERIFY_QSTRING(row, name, expected) \
-    do { if (!verifyQString((row), (name), (expected), __FILE__, __LINE__)) return; } while (0)
+#define VERIFY_LOCAL(row, name, summary, children) \
+    do { \
+        if (!verifyVariable((row), (name), (summary), (children), __FILE__, __LINE__)) \
+            return; \
+    } while (0)
+
+#define VERIFY_WATCH(row, name, summary, children) \
+    do { \
+        if (!verifyVariable((row), (name), (summary), (children), __FILE__, __LINE__, false)) \
+            return; \
+    } while (0)
 
 #define findSourceFile(name) \
     findSourceFile(__FILE__, (name))
@@ -74,7 +90,7 @@
 class TestLaunchConfiguration : public ILaunchConfiguration
 {
 public:
-    TestLaunchConfiguration(const QString& executable,
+    explicit TestLaunchConfiguration(const QString& executable,
                             const QUrl& workingDirectory = QUrl()) {
         auto execPath = findExecutable(executable);
         qDebug() << "FIND" << execPath;
@@ -120,19 +136,19 @@
     return m_core->debugController()->variableCollection();
 }
 
-LldbVariable *LldbFormattersTest::watchVariableAt(int i)
+QModelIndex LldbFormattersTest::watchVariableIndexAt(int i, int col)
 {
     auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0);
-    auto idx = variableCollection()->index(i, 0, watchRoot);
-    return dynamic_cast(variableCollection()->itemForIndex(idx));
+    return variableCollection()->index(i, col, watchRoot);
 }
 
 QModelIndex LldbFormattersTest::localVariableIndexAt(int i, int col)
 {
     auto localRoot = variableCollection()->indexForItem(variableCollection()->locals(), 0);
     return variableCollection()->index(i, col, localRoot);
 }
 
+// Note: line is zero-based
 KDevelop::Breakpoint* LldbFormattersTest::addCodeBreakpoint(const QUrl& location, int line)
 {
     return m_core->debugController()->breakpointModel()->addCodeBreakpoint(location, line);
@@ -168,7 +184,8 @@
     m_core->debugController()->breakpointModel()->removeRows(0, count);
 
     while (variableCollection()->watches()->childCount() > 0) {
-        auto var = watchVariableAt(0);
+        auto idx = watchVariableIndexAt(0);
+        auto var = dynamic_cast(variableCollection()->itemForIndex(idx));
         if (!var) break;
         var->die();
     }
@@ -185,415 +202,806 @@
     m_session.clear();
 }
 
-bool LldbFormattersTest::verifyQString(int index, const QString &name,
-                                       const QString &expected,
-                                       const char *file, int line)
+bool LldbFormattersTest::verifyVariable(int index, const QString &name,
+                                        const QString &expectedSummary,
+                                        QStringList expectedChildren,
+                                        const char *file, int line,
+                                        bool isLocal, bool useRE, bool unordered)
+{
+    QList> childrenPairs;
+    childrenPairs.reserve(expectedChildren.size());
+    if (unordered) {
+        qDebug() << "useRE set to true when unordered = true";
+        useRE = true;
+        expectedChildren.sort();
+        for (auto c : expectedChildren) {
+            childrenPairs << qMakePair(QStringLiteral(R"(^\[\d+\]$)"), c);
+        }
+    } else {
+        for (int i = 0; i != expectedChildren.size(); ++i) {
+            childrenPairs << qMakePair(QStringLiteral("[%0]").arg(i), expectedChildren[i]);
+        }
+    }
+    return verifyVariable(index, name, expectedSummary, childrenPairs, file, line, isLocal, useRE, unordered);
+}
+
+bool LldbFormattersTest::verifyVariable(int index, const QString &name,
+                                        const QString &expectedSummary,
+                                        QList> expectedChildren,
+                                        const char *file, int line,
+                                        bool isLocal, bool useRE, bool unordered)
 {
-    auto varidx = localVariableIndexAt(index, 0);
-    auto var = variableCollection()->itemForIndex(varidx);
+    QModelIndex varIdx, summaryIdx;
+    if (isLocal) {
+        varIdx = localVariableIndexAt(index, 0);
+        summaryIdx = localVariableIndexAt(index, 1);
+    } else {
+        varIdx = watchVariableIndexAt(index, 0);
+        summaryIdx = watchVariableIndexAt(index, 1);
+    }
 
-    if (!compareData(varidx, name, file, line)) {
+    if (!compareData(varIdx, name, file, line)) {
         return false;
     }
-    if (!compareData(localVariableIndexAt(index, 1), Utils::quote(expected), file, line)) {
+    if (!compareData(summaryIdx, expectedSummary, file, line, useRE)) {
         return false;
     }
 
     // fetch all children
+    auto var = variableCollection()->itemForIndex(varIdx);
     auto childCount = 0;
-    while (childCount != variableCollection()->rowCount(varidx)) {
-        childCount = variableCollection()->rowCount(varidx);
+    while (childCount != variableCollection()->rowCount(varIdx)) {
+        childCount = variableCollection()->rowCount(varIdx);
         var->fetchMoreChildren();
         if (!waitForAWhile(m_session, 50, file, line))
             return false;
     }
-    if (childCount != expected.length()) {
+    if (childCount != expectedChildren.length()) {
         QTest::qFail(qPrintable(QString("'%0' didn't match expected '%1' in %2:%3")
-                                .arg(childCount).arg(expected.length()).arg(file).arg(line)),
+                                .arg(childCount).arg(expectedChildren.length()).arg(file).arg(line)),
                      file, line);
         return false;
     }
 
+    QVector theOrder;
+    theOrder.reserve(childCount);
+    for (int i = 0; i != childCount; ++i) {
+        theOrder.push_back(i);
+    }
+    if (unordered) {
+        qDebug() << "actual list sorted for unordered compare";
+        std::sort(theOrder.begin(), theOrder.end(), [&](int a, int b){
+            auto indexA = variableCollection()->index(a, 1, varIdx);
+            auto indexB = variableCollection()->index(b, 1, varIdx);
+            return indexA.model()->data(indexA, Qt::DisplayRole).toString()
+                < indexB.model()->data(indexB, Qt::DisplayRole).toString();
+        });
+        std::sort(expectedChildren.begin(), expectedChildren.end(),
+                  [](const QPair &a, const QPair &b){
+            return a.second < b.second;
+        });
+        qDebug() << "sorted actual order" << theOrder;
+        qDebug() << "sorted expectedChildren" << expectedChildren;
+    }
+
     for (int i = 0; i != childCount; ++i) {
-        if (!compareData(variableCollection()->index(i, 0, varidx),
-                         QString("[%0]").arg(i), file, line)) {
+        if (!compareData(variableCollection()->index(theOrder[i], 0, varIdx),
+                         expectedChildren[i].first, file, line, useRE)) {
             return false;
         }
-        if (!compareData(variableCollection()->index(i, 1, varidx),
-                         QString("'%0'").arg(expected[i]), file, line)) {
+
+        if (!compareData(variableCollection()->index(theOrder[i], 1, varIdx),
+                         expectedChildren[i].second, file, line, useRE)) {
             return false;
         }
     }
     return true;
 }
 
+void LldbFormattersTest::testQChar()
+{
+    TestLaunchConfiguration cfg("lldb_qchar");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qchar.cpp")), 4);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> children;
+    children << qMakePair(QStringLiteral("ucs"), QStringLiteral("107"));
+
+    VERIFY_LOCAL(0, "c", "'k'", children);
+}
+
 void LldbFormattersTest::testQString()
 {
     TestLaunchConfiguration cfg("lldb_qstring");
     addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qstring.cpp")), 4);
 
     QVERIFY(m_session->startDebugging(&cfg, m_iface));
     WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
 
+    // Should be two rows ('auto', 'local')
     QCOMPARE(variableCollection()->rowCount(), 2);
 
-    VERIFY_QSTRING(0, "s", "test string");
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QString expected = QString::fromUtf8("test最后一个不是特殊字符'\"\\u6211");
+    QStringList children;
+    for (auto ch : expected) {
+        children << Utils::quote(ch, '\'');
+    }
+
+    VERIFY_LOCAL(0, "s", Utils::quote(expected), children);
 
     m_session->stepOver();
     WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
     QCOMPARE(m_session->currentLine(), 5);
 
-    VERIFY_QSTRING(0, "s", "test stringx");
+    expected.append("x");
+    children << "'x'";
+
+    VERIFY_LOCAL(0, "s", Utils::quote(expected), children);
 
     m_session->run();
     WAIT_FOR_STATE(m_session, DebugSession::EndedState);
 }
-/*
+
 void LldbFormattersTest::testQByteArray()
 {
-    LldbProcess lldb("qbytearray");
-    lldb.execute("break qbytearray.cpp:5");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print ba");
-    QVERIFY(out.contains("\"test byte array\""));
-    QVERIFY(out.contains("[0] = 116 't'"));
-    QVERIFY(out.contains("[4] = 32 ' '"));
-    lldb.execute("next");
-    QVERIFY(lldb.execute("print ba").contains("\"test byte arrayx\""));
+    TestLaunchConfiguration cfg("lldb_qbytearray");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qbytearray.cpp")), 4);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QStringList charlist {
+        R"(-26 '\xe6')",
+        R"(-104 '\x98')",
+        R"(-81 '\xaf')",
+        R"(39 ''')",
+        R"(34 '"')",
+        R"(92 '\')",
+        R"(117 'u')",
+        R"(54 '6')",
+        R"(50 '2')",
+        R"(49 '1')",
+        R"(49 '1')",
+    };
+
+    VERIFY_LOCAL(0, "ba", R"("\xe6\x98\xaf'\"\\u6211")", charlist);
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 5);
+
+    charlist << "120 'x'";
+    VERIFY_LOCAL(0, "ba", R"("\xe6\x98\xaf'\"\\u6211x")", charlist);
+
+    m_session->run();
+    WAIT_FOR_STATE(m_session, DebugSession::EndedState);
 }
 
+
 void LldbFormattersTest::testQListContainer_data()
 {
     QTest::addColumn("container");
-
-    QTest::newRow("QList") << "QList";
-    QTest::newRow("QQueue") << "QQueue";
-    QTest::newRow("QVector") << "QVector";
-    QTest::newRow("QStack") << "QStack";
-    QTest::newRow("QLinkedList") << "QLinkedList";
-    QTest::newRow("QSet") << "QSet";
+    QTest::addColumn("unordered");
+
+    QTest::newRow("QList") << "QList" << false;
+    QTest::newRow("QQueue") << "QQueue" << false;
+    QTest::newRow("QVector") << "QVector" << false;
+    QTest::newRow("QStack") << "QStack" << false;
+    QTest::newRow("QLinkedList") << "QLinkedList" << false;
+    QTest::newRow("QSet") << "QSet" << true;
 }
 
 void LldbFormattersTest::testQListContainer()
 {
     QFETCH(QString, container);
-    LldbProcess lldb("qlistcontainer");
-    lldb.execute("break main");
-    lldb.execute("run");
-    lldb.execute(QString("break 'doStuff<%1>()'").arg(container).toLocal8Bit());
-    lldb.execute("cont");
-    { // 
-    lldb.execute("break qlistcontainer.cpp:34");
-    lldb.execute("cont");
-    QByteArray out = lldb.execute("print intList");
-    QVERIFY(out.contains(QString("empty %1").arg(container).toLocal8Bit()));
-    lldb.execute("next");
-    out = lldb.execute("print intList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    if (container != "QSet") {
-        QVERIFY(out.contains("[0] = 10"));
-        QVERIFY(out.contains("[1] = 20"));
-        QVERIFY(!out.contains("[2] = 30"));
-    } else { // QSet order is undefined
-        QVERIFY(out.contains("] = 10"));
-        QVERIFY(out.contains("] = 20"));
-        QVERIFY(!out.contains("] = 30"));
-    }
-    lldb.execute("next");
-    out = lldb.execute("print intList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    if (container != "QSet") {
-        QVERIFY(out.contains("[0] = 10"));
-        QVERIFY(out.contains("[1] = 20"));
-        QVERIFY(out.contains("[2] = 30"));
-    } else { // QSet order is undefined
-        QVERIFY(out.contains("] = 10"));
-        QVERIFY(out.contains("] = 20"));
-        QVERIFY(out.contains("] = 30"));
-    }
-    }
-    { // 
-    lldb.execute("next");
-    QByteArray out = lldb.execute("print stringList");
-    QVERIFY(out.contains(QString("empty %1").arg(container).toLocal8Bit()));
-    lldb.execute("next");
-    out = lldb.execute("print stringList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    if (container != "QSet") {
-        QVERIFY(out.contains("[0] = \"a\""));
-        QVERIFY(out.contains("[1] = \"bc\""));
-        QVERIFY(!out.contains("[2] = \"d\""));
-    } else { // QSet order is undefined
-        QVERIFY(out.contains("] = \"a\""));
-        QVERIFY(out.contains("] = \"bc\""));
-        QVERIFY(!out.contains("] = \"d\""));
-    }
-    lldb.execute("next");
-    out = lldb.execute("print stringList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    if (container != "QSet") {
-        QVERIFY(out.contains("[0] = \"a\""));
-        QVERIFY(out.contains("[1] = \"bc\""));
-        QVERIFY(out.contains("[2] = \"d\""));
-    } else { // QSet order is undefined
-        QVERIFY(out.contains("] = \"a\""));
-        QVERIFY(out.contains("] = \"bc\""));
-        QVERIFY(out.contains("] = \"d\""));
-    }
-    }
-    { // 
-    lldb.execute("next");
-    QByteArray out = lldb.execute("print structList");
-    QVERIFY(out.contains(QString("empty %1").arg(container).toLocal8Bit()));
-    lldb.execute("next");
-    out = lldb.execute("print structList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    QVERIFY(out.contains("[0] = {"));
-    QVERIFY(out.contains("a = \"a\""));
-    QVERIFY(out.contains("b = \"b\""));
-    QVERIFY(out.contains("c = 100"));
-    QVERIFY(out.contains("d = -200"));
-    lldb.execute("next");
-    out = lldb.execute("print structList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    QVERIFY(out.contains("[1] = {"));
-    }
-    { // 
-    lldb.execute("next");
-    QByteArray out = lldb.execute("print pointerList");
-    QVERIFY(out.contains(QString("empty %1").arg(container).toLocal8Bit()));
-    lldb.execute("next");
-    out = lldb.execute("print pointerList");
-    QVERIFY(out.contains(QString("%1").arg(container).toLocal8Bit()));
-    QVERIFY(out.contains("[0] = 0x"));
-    QVERIFY(out.contains("[1] = 0x"));
-    QVERIFY(!out.contains("[2] = 0x"));
-    lldb.execute("next");
-    out = lldb.execute("print pointerList");
-    QVERIFY(out.contains("[0] = 0x"));
-    QVERIFY(out.contains("[1] = 0x"));
-    QVERIFY(out.contains("[2] = 0x"));
-	lldb.execute("next");
-    }
-    { //  >
-    lldb.execute("next");
-    QByteArray out = lldb.execute("print pairList");
-    QVERIFY(out.contains(QString("empty %1>").arg(container).toLocal8Bit()));
-    lldb.execute("next");
-    out = lldb.execute("print pairList");
-    QVERIFY(out.contains(QString("%1>").arg(container).toLocal8Bit()));
-    if (container != "QSet") {
-        QVERIFY(out.contains("[0] = {\n    first = 1, \n    second = 2\n  }"));
-        QVERIFY(out.contains("[1] = {\n    first = 2, \n    second = 3\n  }"));
-    } else { // order is undefined in QSet
-        QVERIFY(out.contains("] = {\n    first = 1, \n    second = 2\n  }"));
-        QVERIFY(out.contains("] = {\n    first = 2, \n    second = 3\n  }"));
-    }
-    QVERIFY(!out.contains("[2] = "));
-    lldb.execute("next");
-    out = lldb.execute("print pairList");
-    if (container != "QSet") {
-        QVERIFY(out.contains("[0] = {\n    first = 1, \n    second = 2\n  }"));
-        QVERIFY(out.contains("[1] = {\n    first = 2, \n    second = 3\n  }"));
-        QVERIFY(out.contains("[2] = {\n    first = 4, \n    second = 5\n  }"));
-    } else { // order is undefined in QSet
-        QVERIFY(out.contains("] = {\n    first = 1, \n    second = 2\n  }"));
-        QVERIFY(out.contains("] = {\n    first = 2, \n    second = 3\n  }"));
-        QVERIFY(out.contains("] = {\n    first = 4, \n    second = 5\n  }"));
+    QFETCH(bool, unordered);
+
+    TestLaunchConfiguration cfg("lldb_qlistcontainer");
+    cfg.config().writeEntry(KDevMI::Config::BreakOnStartEntry, true);
+
+    auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0);
+    variableCollection()->expanded(watchRoot);
+    variableCollection()->variableWidgetShown();
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    m_session->addUserCommand(QString("break set --func doStuff<%1>()").arg(container));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    m_session->run();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // 
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    auto var = variableCollection()->watches()->add("intList");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "intList", "", QStringList{},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
     }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update.
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "intList", "", QStringList{"10", "20"},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
     }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    if (!verifyVariable(0, "intList", "", QStringList{"10", "20", "30"},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+    var->die();
+
+    // 
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    var = variableCollection()->watches()->add("stringList");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "stringList", "", QStringList{},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update.
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+
+    if (!verifyVariable(0, "stringList", "", QStringList{"\"a\"", "\"bc\""},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    if (!verifyVariable(0, "stringList", "", QStringList{"\"a\"", "\"bc\"", "\"d\""},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+    var->die();
+
+    // 
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    var = variableCollection()->watches()->add("structList");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "structList", "", QStringList{},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update.
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "structList", "", QStringList{"{...}"},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    if (!verifyVariable(0, "structList", "", QStringList{"{...}", "{...}"},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+    var->die();
+
+    // 
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    var = variableCollection()->watches()->add("pointerList");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "pointerList", "", QStringList{},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update.
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "pointerList", "", QStringList{"^0x[0-9A-Fa-f]+$", "^0x[0-9A-Fa-f]+$"},
+                        __FILE__, __LINE__, false, true, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    if (!verifyVariable(0, "pointerList", "", QStringList{"^0x[0-9A-Fa-f]+$", "^0x[0-9A-Fa-f]+$",
+                                                                  "^0x[0-9A-Fa-f]+$"},
+                        __FILE__, __LINE__, false, true, unordered)) {
+        return;
+    }
+    var->die();
+    m_session->stepOver(); // step over qDeleteAll
+
+    // >
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    var = variableCollection()->watches()->add("pairList");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    VERIFY_WATCH(0, "pairList", "", QStringList{});
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    variableCollection()->expanded(watchVariableIndexAt(0)); // expand this node for correct update.
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "pairList", "", QStringList{"{...}", "{...}"},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    if (!verifyVariable(0, "pairList", "", QStringList{"{...}", "{...}", "{...}"},
+                        __FILE__, __LINE__, false, false, unordered)) {
+        return;
+    }
+    var->die();
+}
+
+void LldbFormattersTest::testQListPOD()
+{
+    TestLaunchConfiguration cfg("lldb_qlistpod");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qlistpod.cpp")), 30);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0);
+    variableCollection()->expanded(watchRoot);
+    variableCollection()->variableWidgetShown();
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    variableCollection()->watches()->add("b");
+    variableCollection()->watches()->add("c");
+    variableCollection()->watches()->add("uc");
+    variableCollection()->watches()->add("s");
+    variableCollection()->watches()->add("us");
+    variableCollection()->watches()->add("i");
+    variableCollection()->watches()->add("ui");
+    variableCollection()->watches()->add("l");
+    variableCollection()->watches()->add("ul");
+    variableCollection()->watches()->add("i64");
+    variableCollection()->watches()->add("ui64");
+    variableCollection()->watches()->add("f");
+    variableCollection()->watches()->add("d");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    VERIFY_WATCH(0, "b", "", (QStringList{"false"}));
+    VERIFY_WATCH(1, "c", "", (QStringList{"50 '2'"}));
+    VERIFY_WATCH(2, "uc", "", (QStringList{"50 '2'"}));
+
+    VERIFY_WATCH(3, "s", "", (QStringList{"50"}));
+    VERIFY_WATCH(4, "us", "", (QStringList{"50"}));
+
+    VERIFY_WATCH(5, "i", "", (QStringList{"50"}));
+    VERIFY_WATCH(6, "ui", "", (QStringList{"50"}));
+
+    VERIFY_WATCH(7, "l", "", (QStringList{"50"}));
+    VERIFY_WATCH(8, "ul", "", (QStringList{"50"}));
+
+    VERIFY_WATCH(9, "i64", "", (QStringList{"50"}));
+    VERIFY_WATCH(10, "ui64", "", (QStringList{"50"}));
+
+    VERIFY_WATCH(11, "f", "", (QStringList{"50"}));
+    VERIFY_WATCH(12, "d", "", (QStringList{"50"}));
 }
 
 void LldbFormattersTest::testQMapInt()
 {
-    LldbProcess lldb("qmapint");
-    lldb.execute("break qmapint.cpp:7");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print m");
-    QVERIFY(out.contains("QMap"));
-    QVERIFY(out.contains("[10] = 100"));
-    QVERIFY(out.contains("[20] = 200"));
-    lldb.execute("next");
-    out = lldb.execute("print m");
-    QVERIFY(out.contains("[30] = 300"));
+    TestLaunchConfiguration cfg("lldb_qmapint");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qmapint.cpp")), 6);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    VERIFY_LOCAL(0, "m", "", (QStringList{"(10, 100)", "(20, 200)"}));
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 7);
+
+    VERIFY_LOCAL(0, "m", "", (QStringList{"(10, 100)", "(20, 200)", "(30, 300)"}));
 }
 
 void LldbFormattersTest::testQMapString()
 {
-    LldbProcess lldb("qmapstring");
-    lldb.execute("break qmapstring.cpp:8");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print m");
-    QVERIFY(out.contains("QMap"));
-    QVERIFY(out.contains("[\"10\"] = \"100\""));
-    QVERIFY(out.contains("[\"20\"] = \"200\""));
-    lldb.execute("next");
-    out = lldb.execute("print m");
-    QVERIFY(out.contains("[\"30\"] = \"300\""));
+    TestLaunchConfiguration cfg("lldb_qmapstring");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qmapstring.cpp")), 7);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    VERIFY_LOCAL(0, "m", "", (QStringList{"(\"10\", \"100\")", "(\"20\", \"200\")"}));
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 8);
+
+    VERIFY_LOCAL(0, "m", "",
+                 (QStringList{"(\"10\", \"100\")", "(\"20\", \"200\")", "(\"30\", \"300\")"}));
 }
 
 void LldbFormattersTest::testQMapStringBool()
 {
-    LldbProcess lldb("qmapstringbool");
-    lldb.execute("break qmapstringbool.cpp:8");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print m");
-    QVERIFY(out.contains("QMap"));
-    QVERIFY(out.contains("[\"10\"] = true"));
-    QVERIFY(out.contains("[\"20\"] = false"));
-    lldb.execute("next");
-    out = lldb.execute("print m");
-    QVERIFY(out.contains("[\"30\"] = true"));
-}
+    TestLaunchConfiguration cfg("lldb_qmapstringbool");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qmapstringbool.cpp")), 7);
 
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
 
-void LldbFormattersTest::testQDate()
-{
-    LldbProcess lldb("qdate");
-    lldb.execute("break qdate.cpp:6");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print d");
-    QVERIFY(out.contains("2010-01-20"));
-}
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
 
-void LldbFormattersTest::testQTime()
-{
-    LldbProcess lldb("qtime");
-    lldb.execute("break qtime.cpp:6");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print t");
-    QVERIFY(out.contains("15:30:10.123"));
-}
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
 
-void LldbFormattersTest::testQDateTime()
-{
-    LldbProcess lldb("qdatetime");
-    lldb.execute("break qdatetime.cpp:5");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print dt");
-    QVERIFY(out.contains("Wed Jan 20 15:31:13 2010"));
-}
+    VERIFY_LOCAL(0, "m", "", (QStringList{"(\"10\", true)", "(\"20\", false)"}));
 
-void LldbFormattersTest::testQUrl()
-{
-    LldbProcess lldb("qurl");
-    lldb.execute("break qurl.cpp:5");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print u");
-    QVERIFY(out.contains("http://www.kdevelop.org/foo"));
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 8);
+
+    VERIFY_LOCAL(0, "m", "", (QStringList{"(\"10\", true)", "(\"20\", false)", "(\"30\", true)"}));
 }
 
+
 void LldbFormattersTest::testQHashInt()
 {
-    LldbProcess lldb("qhashint");
-    lldb.execute("break qhashint.cpp:7");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print h");
-    QVERIFY(out.contains("[10] = 100"));
-    QVERIFY(out.contains("[20] = 200"));
-    lldb.execute("next");
-    out = lldb.execute("print h");
-    QVERIFY(out.contains("[30] = 300"));
+    TestLaunchConfiguration cfg("lldb_qhashint");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qhashint.cpp")), 6);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "h", "", {"(10, 100)", "(20, 200)"},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 7);
+
+    if (!verifyVariable(0, "h", "", {"(10, 100)", "(20, 200)", "(30, 300)"},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
 }
 
 void LldbFormattersTest::testQHashString()
 {
-    LldbProcess lldb("qhashstring");
-    lldb.execute("break qhashstring.cpp:8");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print h");
-    QVERIFY(out.contains("[\"10\"] = \"100\""));
-    QVERIFY(out.contains("[\"20\"] = \"200\""));
-    lldb.execute("next");
-    out = lldb.execute("print h");
-    QVERIFY(out.contains("[\"30\"] = \"300\""));
+    TestLaunchConfiguration cfg("lldb_qhashstring");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qhashstring.cpp")), 7);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "h", "", {"(\"10\", \"100\")", "(\"20\", \"200\")"},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 8);
+
+    if (!verifyVariable(0, "h", "",
+                        {"(\"10\", \"100\")", "(\"20\", \"200\")", "(\"30\", \"300\")"},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
 }
 
 void LldbFormattersTest::testQSetInt()
 {
-    LldbProcess lldb("qsetint");
-    lldb.execute("break qsetint.cpp:7");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print s");
-    QVERIFY(out.contains("] = 10"));
-    QVERIFY(out.contains("] = 20"));
-    lldb.execute("next");
-    out = lldb.execute("print s");
-    QVERIFY(out.contains("] = 30"));
+    TestLaunchConfiguration cfg("lldb_qsetint");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qsetint.cpp")), 6);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "s", "", {"10", "20"},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 7);
+
+    if (!verifyVariable(0, "s", "", {"10", "20", "30"},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
 }
 
 void LldbFormattersTest::testQSetString()
 {
-    LldbProcess lldb("qsetstring");
-    lldb.execute("break qsetstring.cpp:8");
-    lldb.execute("run");
-    QByteArray out = lldb.execute("print s");
-    QVERIFY(out.contains("] = \"10\""));
-    QVERIFY(out.contains("] = \"20\""));
-    lldb.execute("next");
-    out = lldb.execute("print s");
-    QVERIFY(out.contains("] = \"30\""));
+    TestLaunchConfiguration cfg("lldb_qsetstring");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qsetstring.cpp")), 7);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    if (!verifyVariable(0, "s", "", {"\"10\"", "\"20\""},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
+
+    m_session->stepOver();
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+    QCOMPARE(m_session->currentLine(), 8);
+
+    if (!verifyVariable(0, "s", "",
+                        {"\"10\"", "\"20\"", "\"30\""},
+                        __FILE__, __LINE__, true, false, true)) {
+        return;
+    }
 }
 
-void LldbFormattersTest::testQChar()
+void LldbFormattersTest::testQDate()
 {
-    LldbProcess lldb("qchar");
-    lldb.execute("break qchar.cpp:5");
-    lldb.execute("run");
-    QVERIFY(lldb.execute("print c").contains("\"k\""));
+    TestLaunchConfiguration cfg("lldb_qdate");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qdate.cpp")), 5);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> children;
+    children.append({"jd", "2455217"});
+    children.append({"(ISO)", "\"2010-01-20\""});
+    children.append({"(Locale)", "\".+\""}); // (Locale) and summary are locale dependent
+    if (!verifyVariable(0, "d", ".+", children,
+                        __FILE__, __LINE__, true, true, false)) {
+        return;
+    }
 }
 
-void LldbFormattersTest::testQListPOD()
+void LldbFormattersTest::testQTime()
 {
-    LldbProcess lldb("qlistpod");
-    lldb.execute("break qlistpod.cpp:31");
-    lldb.execute("run");
-    QVERIFY(lldb.execute("print b").contains("false"));
-    QVERIFY(lldb.execute("print c").contains("50"));
-    QVERIFY(lldb.execute("print uc").contains("50"));
-    QVERIFY(lldb.execute("print s").contains("50"));
-    QVERIFY(lldb.execute("print us").contains("50"));
-    QVERIFY(lldb.execute("print i").contains("50"));
-    QVERIFY(lldb.execute("print ui").contains("50"));
-    QVERIFY(lldb.execute("print l").contains("50"));
-    QVERIFY(lldb.execute("print ul").contains("50"));
-    QVERIFY(lldb.execute("print i64").contains("50"));
-    QVERIFY(lldb.execute("print ui64").contains("50"));
-    QVERIFY(lldb.execute("print f").contains("50"));
-    QVERIFY(lldb.execute("print d").contains("50"));
+    TestLaunchConfiguration cfg("lldb_qtime");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qtime.cpp")), 5);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> children;
+    children.append({"mds", "55810123"});
+    children.append({"(ISO)", "\"15:30:10.000123\""});
+    children.append({"(Locale)", "\".+\""}); // (Locale) and summary are locale dependent
+    if (!verifyVariable(0, "t", ".+", children,
+                        __FILE__, __LINE__, true, true, false)) {
+        return;
+    }
+}
+
+void LldbFormattersTest::testQDateTime()
+{
+    TestLaunchConfiguration cfg("lldb_qdatetime");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qdatetime.cpp")), 5);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> children;
+    children.append({"toTime_t", "1264019473"});
+    children.append({"(ISO)", "\"2010-01-20 20:31:13\""});
+    children.append({"(Locale)", "\".+\""}); // (Locale), (UTC) and summary are locale dependent
+    children.append({"(UTC)", "\".+\""});
+    if (!verifyVariable(0, "dt", ".+", children,
+                        __FILE__, __LINE__, true, true, false)) {
+        return;
+    }
+}
+
+void LldbFormattersTest::testQUrl()
+{
+    TestLaunchConfiguration cfg("lldb_qurl");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("qurl.cpp")), 4);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> children;
+    children.append({"(port)", "-1"});
+    children.append({"(scheme)", "\"http\""});
+    children.append({"(userName)", ""});
+    children.append({"(password)", ""});
+    children.append({"(host)", "\"www.kdevelop.org\""});
+    children.append({"(path)", "\"/foo\""});
+    children.append({"(query)", ""});
+    children.append({"(fragment)", ""});
+    VERIFY_LOCAL(0, "u", "\"http://www.kdevelop.org/foo\"", children);
 }
 
 void LldbFormattersTest::testQUuid()
 {
-    LldbProcess lldb("quuid");
-    lldb.execute("break quuid.cpp:4");
-    lldb.execute("run");
-    QByteArray data = lldb.execute("print id");
-    QVERIFY(data.contains("{9ec3b70b-d105-42bf-b3b4-656e44d2e223}"));
+    TestLaunchConfiguration cfg("lldb_quuid");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("quuid.cpp")), 4);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    variableCollection()->expanded(localVariableIndexAt(0));
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    VERIFY_LOCAL(0, "id", "QUuid({9ec3b70b-d105-42bf-b3b4-656e44d2e223})", (QStringList{}));
 }
 
 void LldbFormattersTest::testKTextEditorTypes()
 {
-    LldbProcess lldb("ktexteditortypes");
-    lldb.execute("break ktexteditortypes.cpp:9");
-    lldb.execute("run");
+    TestLaunchConfiguration cfg("lldb_ktexteditortypes");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("ktexteditortypes.cpp")), 8);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0);
+    variableCollection()->expanded(watchRoot);
+    variableCollection()->variableWidgetShown();
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    variableCollection()->watches()->add("cursor");
+    variableCollection()->watches()->add("range");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> cursorChildren;
+    cursorChildren.append({"m_line", "1"});
+    cursorChildren.append({"m_column", "1"});
 
-    QByteArray data = lldb.execute("print cursor");
-    QCOMPARE(data, QByteArray("$1 = [1, 1]"));
-    data = lldb.execute("print range");
-    QCOMPARE(data, QByteArray("$2 = [(1, 1) -> (2, 2)]"));
+    QList> rangeChildren;
+    rangeChildren.append({"m_start", "(1, 1)"});
+    rangeChildren.append({"m_end", "(2, 2)"});
+
+    VERIFY_WATCH(0, "cursor", "(1, 1)", cursorChildren);
+    VERIFY_WATCH(1, "range", "[(1, 1) -> (2, 2)]", rangeChildren);
 }
 
 void LldbFormattersTest::testKDevelopTypes()
 {
-    LldbProcess lldb("kdeveloptypes");
-    lldb.execute("break kdeveloptypes.cpp:12");
-    lldb.execute("run");
+    TestLaunchConfiguration cfg("lldb_kdeveloptypes");
+    addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile("kdeveloptypes.cpp")), 11);
+
+    QVERIFY(m_session->startDebugging(&cfg, m_iface));
+    WAIT_FOR_STATE_AND_IDLE(m_session, DebugSession::PausedState);
+
+    // Should be two rows ('auto', 'local')
+    QCOMPARE(variableCollection()->rowCount(), 2);
+
+    auto watchRoot = variableCollection()->indexForItem(variableCollection()->watches(), 0);
+    variableCollection()->expanded(watchRoot);
+    variableCollection()->variableWidgetShown();
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    variableCollection()->watches()->add("path1");
+    variableCollection()->watches()->add("path2");
+    WAIT_FOR_A_WHILE_AND_IDLE(m_session, 50);
+
+    QList> path1Children;
+    path1Children.append({"m_data", ""});
+
+    QList> path2Children;
+    path2Children.append({"m_data", ""});
 
-    QVERIFY(lldb.execute("print path1").contains("(\"tmp\", \"foo\")"));
-    QVERIFY(lldb.execute("print path2").contains("(\"http://www.test.com\", \"tmp\", \"asdf.txt\")"));
+    VERIFY_WATCH(0, "path1", "(\"tmp\", \"foo\")", path1Children);
+    VERIFY_WATCH(1, "path2", "(\"http://www.test.com\", \"tmp\", \"asdf.txt\")", path2Children);
 }
-*/
 
 QTEST_MAIN(LldbFormattersTest)
 
diff --git a/debuggers/lldb/unittests/testhelper.h b/debuggers/lldb/unittests/testhelper.h
--- a/debuggers/lldb/unittests/testhelper.h
+++ b/debuggers/lldb/unittests/testhelper.h
@@ -40,7 +40,7 @@
 QString findSourceFile(const char *file, const QString& name);
 bool isAttachForbidden(const char *file, int line);
 
-bool compareData(QModelIndex index, QString expected, const char *file, int line);
+bool compareData(QModelIndex index, QString expected, const char *file, int line, bool useRE = false);
 
 bool waitForState(MIDebugSession *session, KDevelop::IDebugSession::DebuggerState state,
                   const char *file, int line, bool waitForIdle = false);
diff --git a/debuggers/lldb/unittests/testhelper.cpp b/debuggers/lldb/unittests/testhelper.cpp
--- a/debuggers/lldb/unittests/testhelper.cpp
+++ b/debuggers/lldb/unittests/testhelper.cpp
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 namespace KDevMI { namespace LLDB {
@@ -74,10 +75,17 @@
     return false;
 }
 
-bool compareData(QModelIndex index, QString expected, const char *file, int line)
+bool compareData(QModelIndex index, QString expected, const char *file, int line, bool useRE)
 {
     QString s = index.model()->data(index, Qt::DisplayRole).toString();
-    if (s != expected) {
+    bool matched = true;
+    if (useRE) {
+        QRegularExpression re(expected);
+        matched = re.match(s).hasMatch();
+    } else {
+        matched = s == expected;
+    }
+    if (!matched) {
         QTest::qFail(qPrintable(QString("'%0' didn't match expected '%1' in %2:%3")
                                 .arg(s).arg(expected).arg(file).arg(line)),
                      file, line);
diff --git a/debuggers/lldb/widgets/lldbconfigpage.h b/debuggers/lldb/widgets/lldbconfigpage.h
--- a/debuggers/lldb/widgets/lldbconfigpage.h
+++ b/debuggers/lldb/widgets/lldbconfigpage.h
@@ -34,7 +34,7 @@
 {
     Q_OBJECT
 public:
-    LldbConfigPage( QWidget* parent = nullptr );
+    explicit LldbConfigPage( QWidget* parent = nullptr );
     ~LldbConfigPage() override;
 
     QIcon icon() const override;
diff --git a/doc/kdevelop/index.docbook b/doc/kdevelop/index.docbook
--- a/doc/kdevelop/index.docbook
+++ b/doc/kdevelop/index.docbook
@@ -120,7 +120,7 @@
 If you have multiple applications or libraries, simply repeat the steps to add more and more projects to your session.
 
 Creating projects from scratch
-There is of course also the possibility that you want to start a new project from scratch. This can be done using the ProjectsNew from Template menu item, which presents you with a template selection dialog. Some project templates are provided with &kdevelop;, but even more are available by installing the KAppTemplate application. Choose the project type and programming language from the dialog, enter a name and location for you project, and click Next.
+There is of course also the possibility that you want to start a new project from scratch. This can be done using the ProjectsNew from Template... menu item, which presents you with a template selection dialog. Some project templates are provided with &kdevelop;, but even more are available by installing the KAppTemplate application. Choose the project type and programming language from the dialog, enter a name and location for you project, and click Next.
 
 
 
@@ -1019,7 +1019,7 @@
 &kdevelop; uses templates for generating source code files and to avoid writing repeatable code.
 
 Creating a new class
-The most common use for code generation is probably writing new classes. To create a new class in an existing project, right click on a project folder and choose Create from Template. The same dialog can be started from the menu by clicking FileNew from Template, but using a project folder has the benefit of setting a base URL for the output files. Choose Class in the category selection view, and the desired language and template in the other two views. After you have selected a class template, you will have to specify the details of the new class.
+The most common use for code generation is probably writing new classes. To create a new class in an existing project, right click on a project folder and choose Create from Template.... The same dialog can be started from the menu by clicking FileNew from Template..., but using a project folder has the benefit of setting a base URL for the output files. Choose Class in the category selection view, and the desired language and template in the other two views. After you have selected a class template, you will have to specify the details of the new class.
 
 
 
@@ -1089,19 +1089,19 @@
 
 
 Creating a new unit test
-Even though most testing frameworks require each test to also be a class, &kdevelop; includes a method to simplify the creation of unit tests. To create a new test, right click on a project folder and choose Create from Template. In the template selection page, choose Test as the category, then choose your programming language and template and click Next.
+Even though most testing frameworks require each test to also be a class, &kdevelop; includes a method to simplify the creation of unit tests. To create a new test, right click on a project folder and choose Create from Template.... In the template selection page, choose Test as the category, then choose your programming language and template and click Next.
 
 You will be prompted for the test name and a list of test cases. For the test cases, you only have to specify a list of names. Some unit testing frameworks, such as PyUnit and PHPUnit, require that test cases start with a special prefix. In &kdevelop;, the template is responsible for adding the prefix, so you do not have to prefix the test cases here. After clicking Next, specify the license and output locations for the generated files, and the test will be created.
 
 Unit tests created this way will not be added to any target automatically. If you are using CTest or some other testing framework, make sure to add the new files to a target.
 
 
 Other files
-While classes and unit tests receive special attention when generating code from templates, the same method can be used for any kind of source code files. For example, one could use a template for a CMake Find module or a .desktop file. This can be done by choosing Create from Template, and selecting the wanted category and template. If the selected category is neither Class nor Test, you will only have the option of choosing the license, any custom options specified by the template, and the output file locations. As with classes and tests, finishing the assistant will generate the files and open them in the editor.
+While classes and unit tests receive special attention when generating code from templates, the same method can be used for any kind of source code files. For example, one could use a template for a CMake Find module or a .desktop file. This can be done by choosing Create from Template..., and selecting the wanted category and template. If the selected category is neither Class nor Test, you will only have the option of choosing the license, any custom options specified by the template, and the output file locations. As with classes and tests, finishing the assistant will generate the files and open them in the editor.
 
 
 Managing templates
-From the FileNew from Template assistant, you can also download additional file templates by clicking the Get more Templates... button. This opens a Get Hot New Stuff dialog, where you can install additional templates, as well as update or remove them. There is also a configuration module for templates, which can be reached by clicking SettingsConfigure &kdevelop;Templates. From there, you can manage both file templates (explained above) and project templates (used for creating new projects).
+From the FileNew from Template... assistant, you can also download additional file templates by clicking the Get more Templates... button. This opens a Get Hot New Stuff dialog, where you can install additional templates, as well as update or remove them. There is also a configuration module for templates, which can be reached by clicking SettingsConfigure &kdevelop;Templates. From there, you can manage both file templates (explained above) and project templates (used for creating new projects).
 
 
 
diff --git a/documentation/manpage/manpagemodel.h b/documentation/manpage/manpagemodel.h
--- a/documentation/manpage/manpagemodel.h
+++ b/documentation/manpage/manpagemodel.h
@@ -37,7 +37,7 @@
     Q_OBJECT
 
 public:
-    ManPageModel(QObject* parent = nullptr);
+    explicit ManPageModel(QObject* parent = nullptr);
     ~ManPageModel() override;
 
     /**
diff --git a/documentation/manpage/manpageplugin.h b/documentation/manpage/manpageplugin.h
--- a/documentation/manpage/manpageplugin.h
+++ b/documentation/manpage/manpageplugin.h
@@ -36,7 +36,7 @@
     Q_OBJECT
     Q_INTERFACES( KDevelop::IDocumentationProvider )
 public:
-    ManPagePlugin(QObject *parent, const QVariantList & args= QVariantList());
+    explicit ManPagePlugin(QObject *parent, const QVariantList & args= QVariantList());
     ~ManPagePlugin() override;
     KDevelop::IDocumentation::Ptr documentationForDeclaration (KDevelop::Declaration* dec) const override;
     QAbstractListModel* indexModel() const override;
diff --git a/documentation/qthelp/qthelpconfig.cpp b/documentation/qthelp/qthelpconfig.cpp
--- a/documentation/qthelp/qthelpconfig.cpp
+++ b/documentation/qthelp/qthelpconfig.cpp
@@ -97,11 +97,8 @@
 QtHelpConfig::QtHelpConfig(QtHelpPlugin* plugin, QWidget *parent)
     : KDevelop::ConfigPage(plugin, nullptr, parent)
 {
-    QVBoxLayout * l = new QVBoxLayout( this );
-
-    QWidget* w = new QWidget;
     m_configWidget = new Ui::QtHelpConfigUI;
-    m_configWidget->setupUi( w );
+    m_configWidget->setupUi(this);
     m_configWidget->addButton->setIcon(QIcon::fromTheme("list-add"));
     connect(m_configWidget->addButton, &QPushButton::clicked, this, &QtHelpConfig::add);
 
@@ -134,7 +131,6 @@
             i18n("The command \"qmake -query\" could not provide a path to a QtHelp file (QCH)."));
         m_configWidget->loadQtDocsCheckBox->setVisible(false);
     }
-    l->addWidget(w);
     reset();
 }
 
diff --git a/documentation/qthelp/qthelpconfig.ui b/documentation/qthelp/qthelpconfig.ui
--- a/documentation/qthelp/qthelpconfig.ui
+++ b/documentation/qthelp/qthelpconfig.ui
@@ -14,6 +14,9 @@
    
   
   
+   
+    0
+   
    
     
      
diff --git a/documentation/qthelp/qthelpnetwork.h b/documentation/qthelp/qthelpnetwork.h
--- a/documentation/qthelp/qthelpnetwork.h
+++ b/documentation/qthelp/qthelpnetwork.h
@@ -83,7 +83,7 @@
 class HelpNetworkAccessManager : public QNetworkAccessManager
 {
 	public:
-		HelpNetworkAccessManager(QHelpEngineCore *engine, QObject *parent = nullptr)
+		explicit HelpNetworkAccessManager(QHelpEngineCore *engine, QObject *parent = nullptr)
 			: QNetworkAccessManager(parent), m_helpEngine(engine) {}
 
 	protected:
diff --git a/documentation/qthelp/tests/test_qthelpplugin.cpp b/documentation/qthelp/tests/test_qthelpplugin.cpp
--- a/documentation/qthelp/tests/test_qthelpplugin.cpp
+++ b/documentation/qthelp/tests/test_qthelpplugin.cpp
@@ -42,6 +42,8 @@
 using namespace KDevelop;
 
 TestQtHelpPlugin::TestQtHelpPlugin()
+    : m_testCore(nullptr)
+    , m_plugin(nullptr)
 {
 }
 
diff --git a/file_templates/testing/python_pyunit/class.py b/file_templates/testing/python_pyunit/class.py
--- a/file_templates/testing/python_pyunit/class.py
+++ b/file_templates/testing/python_pyunit/class.py
@@ -14,12 +14,12 @@
 
 class {{ name }}(unittest.TestCase):
     def setUp(self):
-        # Called before the first testfunction is executed
+        # Called prior to each test method
         pass
 
 
     def tearDown(self):
-        # Called after the last testfunction was executed
+        # Called after each test method
         pass
 
 
diff --git a/format.config.uncrustify.4_spaces b/format.config.uncrustify.4_spaces
--- a/format.config.uncrustify.4_spaces
+++ b/format.config.uncrustify.4_spaces
@@ -1,139 +1,161 @@
+set for foreach
+
+align_func_params=false
+align_keep_tabs=false
+align_left_shift=true
+align_mix_var_proto=false
+align_nl_cont=false
+align_number_left=false
+align_on_operator=false
+align_on_tabstop=false
+align_right_cmt_mix=false
+align_same_func_call_params=false
+align_single_line_brace=false
+align_single_line_func=false
+align_var_def_attribute=false
+align_var_def_colon=false
+align_var_def_inline=false
+align_with_tabs=false
+cmt_c_group=false
+cmt_c_nl_end=false
+cmt_c_nl_start=false
+cmt_cpp_group=false
+cmt_cpp_nl_end=false
+cmt_cpp_nl_start=false
+cmt_cpp_to_c=false
+cmt_indent_multi=true
+cmt_insert_before_preproc=false
+cmt_multi_check_last=true
+cmt_star_cont=false
+eat_blanks_after_open_brace=true
+eat_blanks_before_close_brace=true
+indent_access_spec_body=false
+indent_align_assign=true
 indent_align_string=false
+indent_bool_paren=false
+indent_brace_parent=false
 indent_braces=false
 indent_braces_no_func=false
-indent_brace_parent=false
-indent_namespace=false
-indent_extern=false
-indent_class=true
 indent_class_colon=false
+indent_class=true
+indent_col1_comment=false
+indent_columns=4
+indent_comma_paren=false
 indent_else_if=false
-indent_func_call_param=true
-indent_func_def_param=true
-indent_func_proto_param=true
-indent_func_class_param=true
+indent_extern=false
+indent_func_call_param=false
+indent_func_class_param=false
 indent_func_ctor_var_param=true
-indent_template_param=true
+indent_func_def_param=false
 indent_func_param_double=false
-indent_relative_single_line_comments=false
-indent_col1_comment=false
-indent_access_spec_body=false
+indent_func_proto_param=false
+indent_namespace=false
 indent_paren_nl=false
-indent_comma_paren=false
-indent_bool_paren=false
-indent_square_nl=false
 indent_preserve_sql=false
-indent_align_assign=true
-sp_balance_nested_parens=true
-align_keep_tabs=false
-align_with_tabs=false
-align_on_tabstop=false
-align_number_left=false
-align_func_params=false
-align_same_func_call_params=false
-align_var_def_colon=false
-align_var_def_attribute=false
-align_var_def_inline=false
-align_right_cmt_mix=false
-align_on_operator=false
-align_mix_var_proto=false
-align_single_line_func=false
-align_single_line_brace=false
-align_nl_cont=false
-align_left_shift=true
-nl_collapse_empty_body=false
+indent_relative_single_line_comments=false
+indent_square_nl=false
+indent_switch_case=0
+indent_template_param=true
+indent_with_tabs=0
+ls_for_split_full=false
+ls_func_split_full=false
+mod_add_long_ifdef_else_comment=0
+mod_add_long_ifdef_endif_comment=0
+mod_full_brace_do=add
+mod_full_brace_for=add
+mod_full_brace_function=add
+mod_full_brace_if=add
+mod_full_paren_if_bool=false
+mod_move_case_break=false
+mod_pawn_semicolon=false
+mod_remove_empty_return=false
+mod_remove_extra_semicolon=false
+mod_sort_import=false
+mod_sort_include=false
+mod_sort_using=false
+nl_after_access_spec=0
+nl_after_brace_open=true
+nl_after_for=add
+nl_after_multiline_comment=false
+nl_after_vbrace_open=true
 nl_assign_leave_one_liners=true
+nl_before_access_spec=1
+nl_before_case=false
+nl_brace_else=remove
+nl_class_brace=add
+nl_class_brace=force
+nl_class_colon=add
+nl_class_init_args=add
 nl_class_leave_one_liners=true
+nl_collapse_empty_body=false
+nl_constr_init_args=add
+nl_create_for_one_liner=false
+nl_create_if_one_liner=false
+nl_create_while_one_liner=false
+nl_define_macro=false
+nl_ds_struct_enum_close_brace=false
+nl_ds_struct_enum_cmt=false
+nl_elseif_brace=remove
 nl_enum_leave_one_liners=true
-nl_getset_leave_one_liners=true
+nl_fdef_brace=add
+nl_for_brace=remove
 nl_func_leave_one_liners=true
-nl_if_leave_one_liners=true
+nl_getset_leave_one_liners=true
+nl_if_brace=remove
+nl_max=2
 nl_multi_line_cond=false
 nl_multi_line_define=false
-nl_before_case=false
-nl_after_case=false
-nl_after_return=false
-nl_after_semicolon=false
-nl_after_brace_open=false
-nl_after_brace_open_cmt=false
-nl_after_vbrace_open=false
-nl_after_brace_close=false
-nl_define_macro=false
+nl_namespace_brace=remove
 nl_squeeze_ifdef=false
-nl_ds_struct_enum_cmt=false
-nl_ds_struct_enum_close_brace=false
-nl_create_if_one_liner=false
-nl_create_for_one_liner=false
-nl_create_while_one_liner=false
-ls_for_split_full=false
-ls_func_split_full=false
-nl_after_multiline_comment=false
-eat_blanks_after_open_brace=true
-eat_blanks_before_close_brace=true
-mod_pawn_semicolon=false
-mod_full_paren_if_bool=false
-mod_remove_extra_semicolon=false
-mod_sort_import=false
-mod_sort_using=false
-mod_sort_include=false
-mod_move_case_break=false
-mod_remove_empty_return=false
-cmt_indent_multi=true
-cmt_c_group=false
-cmt_c_nl_start=false
-cmt_c_nl_end=false
-cmt_cpp_group=false
-cmt_cpp_nl_start=false
-cmt_cpp_nl_end=false
-cmt_cpp_to_c=false
-cmt_star_cont=false
-cmt_multi_check_last=true
-cmt_insert_before_preproc=false
+nl_struct_brace=force
+nl_while_brace=remove
+pos_class_colon=lead_force
+pos_class_comma=lead_force
+pos_comma=trail
+pos_constr_comma=lead_force
+pp_define_at_level=false
+pp_if_indent_code=false
 pp_indent_at_level=false
 pp_region_indent_code=false
-pp_if_indent_code=false
-pp_define_at_level=false
-indent_columns=4
-indent_switch_case=4
-nl_max=2
-mod_add_long_ifdef_endif_comment=0
-mod_add_long_ifdef_else_comment=0
-indent_with_tabs=0
-sp_before_assign=add
-sp_after_assign=add
-sp_enum_assign=add
-sp_enum_before_assign=add
-sp_enum_after_assign=add
-sp_pp_concat=add
-sp_pp_stringify=add
-sp_bool=add
-sp_compare=add
-sp_inside_paren=add
-sp_paren_paren=add
-sp_paren_brace=add
-sp_template_angle=add
-sp_inside_angle=remove
 sp_after_angle=add
-sp_inside_sparen=add
-sp_sparen_brace=add
-sp_inside_square=remove
-sp_after_comma=add
-sp_before_comma=remove
+sp_after_assign=add
+sp_after_byref=add
 sp_after_class_colon=add
-sp_before_class_colon=add
-sp_before_case_colon=remove
-sp_inside_paren_cast=add
-sp_func_def_paren=remove
-sp_inside_fparens=remove
-sp_inside_fparen=add
-sp_square_fparen=remove
-sp_fparen_brace=add
-sp_func_call_paren=remove
+sp_after_comma=add
+sp_after_ptr_star=add
+sp_after_sparen=remove
 sp_arith=add
 sp_assign=add
 sp_assign_default=add
-sp_enum_assign=add
+sp_balance_nested_parens=false
+sp_before_assign=add
+sp_before_byref=remove
+sp_before_case_colon=remove
+sp_before_class_colon=add
+sp_before_comma=remove
+sp_before_ptr_star=remove
+sp_before_sparen=add
 sp_bool=add
+sp_brace_else=add
 sp_compare=add
-nl_namespace_brace=add
-nl_class_brace=add
-nl_fdef_brace=ignore
+sp_else_brace=add
+sp_enum_after_assign=add
+sp_enum_assign=add
+sp_enum_before_assign=add
+sp_fparen_brace=add
+sp_func_call_paren=remove
+sp_func_def_paren=remove
+sp_inside_angle=remove
+sp_inside_fparen=remove
+sp_inside_fparens=remove
+sp_inside_paren_cast=add
+sp_inside_paren=remove
+sp_inside_sparen=remove
+sp_inside_square=remove
+sp_paren_brace=add
+sp_paren_paren=remove
+sp_pp_concat=add
+sp_pp_stringify=add
+sp_sparen_brace=add
+sp_square_fparen=remove
+sp_template_angle=add
diff --git a/formatters/astyle/astyle_preferences.h b/formatters/astyle/astyle_preferences.h
--- a/formatters/astyle/astyle_preferences.h
+++ b/formatters/astyle/astyle_preferences.h
@@ -33,7 +33,7 @@
 public:
     enum Language { CPP, Java, CSharp};
 
-    AStylePreferences(Language lang=CPP, QWidget *parent=nullptr);
+    explicit AStylePreferences(Language lang=CPP, QWidget *parent=nullptr);
     ~AStylePreferences() override;
 
     void load(const KDevelop::SourceFormatterStyle &style) override;
diff --git a/formatters/astyle/astyle_stringiterator.h b/formatters/astyle/astyle_stringiterator.h
--- a/formatters/astyle/astyle_stringiterator.h
+++ b/formatters/astyle/astyle_stringiterator.h
@@ -32,7 +32,7 @@
 class AStyleStringIterator : public astyle::ASSourceIterator
 {
 public:
-    AStyleStringIterator(const QString &string);
+    explicit AStyleStringIterator(const QString &string);
     virtual ~AStyleStringIterator();
 
     bool hasMoreLines() const override;
diff --git a/formatters/astyle/lib/ASBeautifier.cpp b/formatters/astyle/lib/ASBeautifier.cpp
--- a/formatters/astyle/lib/ASBeautifier.cpp
+++ b/formatters/astyle/lib/ASBeautifier.cpp
@@ -1268,7 +1268,7 @@
 	assert(isCharPotentialOperator(line[i]));
 	// find the operator in the vector
 	// the vector contains the LONGEST operators first
-	// must loop thru the entire vector
+	// must loop through the entire vector
 	size_t maxOperators = possibleOperators->size();
 	for (size_t p = 0; p < maxOperators; p++)
 	{
diff --git a/formatters/astyle/lib/ASFormatter.cpp b/formatters/astyle/lib/ASFormatter.cpp
--- a/formatters/astyle/lib/ASFormatter.cpp
+++ b/formatters/astyle/lib/ASFormatter.cpp
@@ -582,7 +582,7 @@
 				isInHorstmannRunIn = false;
 			}
 			processPreprocessor();
-			//  need to fall thru here to reset the variables
+			//  need to fall through here to reset the variables
 		}
 
 		/* not in preprocessor ... */
@@ -1102,7 +1102,7 @@
 			else if ((newHeader = findHeader(preCommandHeaders)) != NULL)
 			{
 				foundPreCommandHeader = true;
-				// fall thru here for a 'const' that is not a precommand header
+				// fall through here for a 'const' that is not a precommand header
 			}
 			else if ((newHeader = findHeader(castOperators)) != NULL)
 			{
diff --git a/formatters/astyle/lib/ASLocalizer.cpp b/formatters/astyle/lib/ASLocalizer.cpp
--- a/formatters/astyle/lib/ASLocalizer.cpp
+++ b/formatters/astyle/lib/ASLocalizer.cpp
@@ -78,15 +78,15 @@
 //----------------------------------------------------------------------------
 
 ASLocalizer::ASLocalizer()
-// Set the locale information.
+    // Set the locale information.
+    // set language default values to english (ascii)
+    // this will be used if a locale or a language cannot be found
+    : m_translation(nullptr)
+    , m_langID("en")
+    , m_localeName("UNKNOWN")
+    , m_lcid(0)
 {
-	// set language default values to english (ascii)
-	// this will be used if a locale or a language cannot be found
-	m_localeName = "UNKNOWN";
-	m_langID = "en";
-	m_lcid = 0;
 	m_subLangID.clear();
-	m_translation = NULL;
 
 	// Not all compilers support the C++ function locale::global(locale(""));
 	// For testing on Windows change the "Region and Language" settings or use AppLocale.
diff --git a/formatters/astyle/tests/test_astyle.cpp b/formatters/astyle/tests/test_astyle.cpp
--- a/formatters/astyle/tests/test_astyle.cpp
+++ b/formatters/astyle/tests/test_astyle.cpp
@@ -160,7 +160,7 @@
 {
     // think this:
     // asdf = 1;
-    // and you execute the assitant to get:
+    // and you execute the assistant to get:
     // int asdf = 1;
 
     // test1: already indented
diff --git a/formatters/customscript/customscript_plugin.h b/formatters/customscript/customscript_plugin.h
--- a/formatters/customscript/customscript_plugin.h
+++ b/formatters/customscript/customscript_plugin.h
@@ -30,82 +30,83 @@
 #include 
 #include 
 
-class CustomScriptPlugin : public KDevelop::IPlugin, public KDevelop::ISourceFormatter
+class CustomScriptPlugin
+    : public KDevelop::IPlugin
+    , public KDevelop::ISourceFormatter
 {
-		Q_OBJECT
-		Q_INTERFACES(KDevelop::ISourceFormatter)
-
-	public:
-		explicit CustomScriptPlugin(QObject *parent, const QVariantList & = QVariantList());
-		~CustomScriptPlugin() override;
-
-		QString name() override;
-		QString caption()  override;
-		QString description() override;
-
-		/** Formats using the current style.
-		*/
-		QString formatSource(const QString &text, const QUrl &url, const QMimeType& mime, const QString& leftContext, const QString& rightContext) override;
-
-		QString formatSourceWithStyle(KDevelop::SourceFormatterStyle, const QString& text,
-											  const QUrl &url,
-											  const QMimeType& mime,
-											  const QString& leftContext = QString(),
-											  const QString& rightContext = QString()) override;
-		
-		/** \return A map of predefined styles (a key and a caption for each type)
-		*/
-		QList predefinedStyles() override;
-
-		/** \return The widget to edit a style.
-		*/
-		KDevelop::SettingsWidget* editStyleWidget(const QMimeType& mime) override;
-
-		/** \return The text used in the config dialog to preview the current style.
-		*/
-		QString previewText(const KDevelop::SourceFormatterStyle& style, const QMimeType& mime) override;
-
-		/** \return The indentation of the currently selected style.
-		*/
-		Indentation indentation(const QUrl &url) override;
-
-	private:
-		QStringList computeIndentationFromSample(const QUrl &url);
-		
-		QStringList m_options;
-		KDevelop::SourceFormatterStyle m_currentStyle;
-		KDevelop::SourceFormatterStyle predefinedStyle(const QString& name);
+    Q_OBJECT
+    Q_INTERFACES(KDevelop::ISourceFormatter)
+public:
+    explicit CustomScriptPlugin(QObject* parent, const QVariantList& = QVariantList());
+    ~CustomScriptPlugin() override;
+
+    QString name() override;
+    QString caption()  override;
+    QString description() override;
+
+    /** Formats using the current style.
+     */
+    QString formatSource(const QString& text, const QUrl& url, const QMimeType& mime, const QString& leftContext, const QString& rightContext) override;
+
+    QString formatSourceWithStyle(KDevelop::SourceFormatterStyle, const QString& text,
+                                  const QUrl& url,
+                                  const QMimeType& mime,
+                                  const QString& leftContext = QString(),
+                                  const QString& rightContext = QString()) override;
+
+    /** \return A map of predefined styles (a key and a caption for each type)
+     */
+    QList predefinedStyles() override;
+
+    /** \return The widget to edit a style.
+     */
+    KDevelop::SettingsWidget* editStyleWidget(const QMimeType& mime) override;
+
+    /** \return The text used in the config dialog to preview the current style.
+     */
+    QString previewText(const KDevelop::SourceFormatterStyle& style, const QMimeType& mime) override;
+
+    /** \return The indentation of the currently selected style.
+     */
+    Indentation indentation(const QUrl& url) override;
+private:
+    QStringList computeIndentationFromSample(const QUrl& url);
+
+    QStringList m_options;
+    KDevelop::SourceFormatterStyle m_currentStyle;
+    KDevelop::SourceFormatterStyle predefinedStyle(const QString& name);
 };
 
-class CustomScriptPreferences : public KDevelop::SettingsWidget {
-Q_OBJECT
+class CustomScriptPreferences
+    : public KDevelop::SettingsWidget
+{
+    Q_OBJECT
 public:
-	CustomScriptPreferences() ;
-		
-    void load ( const KDevelop::SourceFormatterStyle& style ) override ;
-    
-    QString save() override ;
+    CustomScriptPreferences();
+
+    void load (const KDevelop::SourceFormatterStyle& style) override;
+
+    QString save() override;
 private:
-	QVBoxLayout* m_vLayout;
-	QLabel* m_captionLabel;
-	QHBoxLayout* m_hLayout;
-	QLabel* m_commandLabel;
-	QLineEdit* m_commandEdit;
-	QLabel* m_bottomLabel;
-	QTimer* m_updateTimer;
-	QPushButton* m_moreVariablesButton;
-	KDevelop::SourceFormatterStyle m_style;
-	
+    QVBoxLayout* m_vLayout;
+    QLabel* m_captionLabel;
+    QHBoxLayout* m_hLayout;
+    QLabel* m_commandLabel;
+    QLineEdit* m_commandEdit;
+    QLabel* m_bottomLabel;
+    QTimer* m_updateTimer;
+    QPushButton* m_moreVariablesButton;
+    KDevelop::SourceFormatterStyle m_style;
 private slots:
-	void textEdited ( QString ) {
-		m_updateTimer->start(1000);
-	}
-	
-	void updateTimeout();
-    void moreVariablesClicked ( bool );
-};
+    void textEdited(QString)
+    {
+        m_updateTimer->start(1000);
+    }
 
+    void updateTimeout();
+    void moreVariablesClicked (bool);
+};
 
 #endif // CUSTOMSCRIPTPLUGIN_H
 
-// kate: indent-mode cstyle; space-indent off; tab-width 4; 
+// kate: indent-mode cstyle; space-indent off; tab-width 4;
diff --git a/formatters/customscript/customscript_plugin.cpp b/formatters/customscript/customscript_plugin.cpp
--- a/formatters/customscript/customscript_plugin.cpp
+++ b/formatters/customscript/customscript_plugin.cpp
@@ -51,487 +51,476 @@
 
 static QPointer indentPluginSingleton;
 
-K_PLUGIN_FACTORY_WITH_JSON(CustomScriptFactory, "kdevcustomscript.json", registerPlugin();)
+K_PLUGIN_FACTORY_WITH_JSON(CustomScriptFactory, "kdevcustomscript.json", registerPlugin(); )
 
 // Replaces ${KEY} in command with variables[KEY]
-static QString replaceVariables( QString command, QMap variables )
+static QString replaceVariables(QString command, QMap variables)
 {
-	while( command.contains("${"))
-	{
-		int pos = command.indexOf("${");
-		int end = command.indexOf("}", pos+2);
-		if(end == -1)
-			break;
-		QString key = command.mid( pos+2, end-pos-2 );
-
-		if( variables.contains( key ) )
-		{
-			command.replace( pos, 1 + end - pos, variables[key] );
-		}else{
-			qCDebug(CUSTOMSCRIPT) << "found no variable while replacing in shell-command" << command << "key" << key << "available:" << variables;
-			command.replace( pos, 1 + end - pos, "" );
-		}
-	}
-	return command;
+    while (command.contains("${")) {
+        int pos = command.indexOf("${");
+        int end = command.indexOf("}", pos + 2);
+        if (end == -1) {
+            break;
+        }
+        QString key = command.mid(pos + 2, end - pos - 2);
+
+        if (variables.contains(key)) {
+            command.replace(pos, 1 + end - pos, variables[key]);
+        } else {
+            qCDebug(CUSTOMSCRIPT) << "found no variable while replacing in shell-command" << command << "key" << key << "available:" << variables;
+            command.replace(pos, 1 + end - pos, "");
+        }
+    }
+    return command;
 }
 
-CustomScriptPlugin::CustomScriptPlugin(QObject *parent, const QVariantList&)
-	: IPlugin("kdevcustomscript", parent)
+CustomScriptPlugin::CustomScriptPlugin(QObject* parent, const QVariantList&)
+    : IPlugin("kdevcustomscript", parent)
 {
-        m_currentStyle = predefinedStyles().at(0);
-	indentPluginSingleton = this;
+    m_currentStyle = predefinedStyles().at(0);
+    indentPluginSingleton = this;
 }
 
 CustomScriptPlugin::~CustomScriptPlugin()
 {
 }
 
 QString CustomScriptPlugin::name()
 {
-	// This needs to match the X-KDE-PluginInfo-Name entry from the .desktop file!
-	return "kdevcustomscript";
+    // This needs to match the X-KDE-PluginInfo-Name entry from the .desktop file!
+    return "kdevcustomscript";
 }
 
 QString CustomScriptPlugin::caption()
 {
-	return "Custom Script Formatter";
+    return "Custom Script Formatter";
 }
 
 QString CustomScriptPlugin::description()
 {
-	return i18n("Indent and Format Source Code.
" - "This plugin allows using powerful external formatting tools " - "that can be invoked through the command-line.
" - "For example, the uncrustify, astyle or indent " - "formatters can be used.
" - "The advantage of command-line formatters is that formatting configurations " - "can be easily shared by all team members, independent of their preferred IDE."); + return i18n("Indent and Format Source Code.
" + "This plugin allows using powerful external formatting tools " + "that can be invoked through the command-line.
" + "For example, the uncrustify, astyle or indent " + "formatters can be used.
" + "The advantage of command-line formatters is that formatting configurations " + "can be easily shared by all team members, independent of their preferred IDE."); } -QString CustomScriptPlugin::formatSourceWithStyle(SourceFormatterStyle style, const QString& text, const QUrl &url, const QMimeType& /*mime*/, const QString& leftContext, const QString& rightContext) +QString CustomScriptPlugin::formatSourceWithStyle(SourceFormatterStyle style, const QString& text, const QUrl& url, const QMimeType& /*mime*/, const QString& leftContext, const QString& rightContext) { - KProcess proc; - QTextStream ios(&proc); - - std::unique_ptr tmpFile; - - if (style.content().isEmpty()) - { - style = predefinedStyle(style.name()); - if (style.content().isEmpty()) - { - qWarning() << "Empty contents for style" << style.name() << "for indent plugin"; - return text; - } - } - - QString useText = text; - useText = leftContext + useText + rightContext; - - QMap projectVariables; - foreach(IProject* project, ICore::self()->projectController()->projects()) - projectVariables[project->name()] = project->path().toUrl().toLocalFile(); - - QString command = style.content(); - - // Replace ${Project} with the project path - command = replaceVariables( command, projectVariables ); - command.replace("$FILE", url.toLocalFile()); - - if(command.contains("$TMPFILE")) - { - tmpFile.reset(new QTemporaryFile(QDir::tempPath() + "/code")); - tmpFile->setAutoRemove(false); - if(tmpFile->open()) - { - qCDebug(CUSTOMSCRIPT) << "using temporary file" << tmpFile->fileName(); - command.replace("$TMPFILE", tmpFile->fileName()); - QByteArray useTextArray = useText.toLocal8Bit(); - if( tmpFile->write(useTextArray) != useTextArray.size() ) - { - qWarning() << "failed to write text to temporary file"; - return text; - } - - }else{ - qWarning() << "Failed to create a temporary file"; - return text; - } - tmpFile->close(); - } - - qCDebug(CUSTOMSCRIPT) << "using shell command for indentation: " << command; - proc.setShellCommand(command); - proc.setOutputChannelMode(KProcess::OnlyStdoutChannel); - - proc.start(); - if(!proc.waitForStarted()) { - qCDebug(CUSTOMSCRIPT) << "Unable to start indent" << endl; - return text; - } - - if(!tmpFile.get()) - proc.write(useText.toLocal8Bit()); - - proc.closeWriteChannel(); - if(!proc.waitForFinished()) { - qCDebug(CUSTOMSCRIPT) << "Process doesn't finish" << endl; - return text; - } - - QString output; - - if(tmpFile.get()) - { - QFile f(tmpFile->fileName()); - if( f.open(QIODevice::ReadOnly) ) - { - output = QString::fromLocal8Bit(f.readAll()); - }else{ - qWarning() << "Failed opening the temporary file for reading"; - return text; - } - }else{ - output = ios.readAll(); - } - if (output.isEmpty()) - { - qWarning() << "indent returned empty text for style" << style.name() << style.content(); - return text; - } - - int tabWidth = 4; - if((!leftContext.isEmpty() || !rightContext.isEmpty()) && (text.contains(' ') || output.contains(' '))) - { - // If we have to do contex-matching with tabs, determine the correct tab-width so that the context - // can be matched correctly - Indentation indent = indentation(url); - if(indent.indentationTabWidth > 0) - tabWidth = indent.indentationTabWidth; - } + KProcess proc; + QTextStream ios(&proc); + + std::unique_ptr tmpFile; + + if (style.content().isEmpty()) { + style = predefinedStyle(style.name()); + if (style.content().isEmpty()) { + qWarning() << "Empty contents for style" << style.name() << "for indent plugin"; + return text; + } + } + + QString useText = text; + useText = leftContext + useText + rightContext; + + QMap projectVariables; + foreach (IProject* project, ICore::self()->projectController()->projects()) { + projectVariables[project->name()] = project->path().toUrl().toLocalFile(); + } + + QString command = style.content(); + + // Replace ${Project} with the project path + command = replaceVariables(command, projectVariables); + command.replace("$FILE", url.toLocalFile()); + + if (command.contains("$TMPFILE")) { + tmpFile.reset(new QTemporaryFile(QDir::tempPath() + "/code")); + tmpFile->setAutoRemove(false); + if (tmpFile->open()) { + qCDebug(CUSTOMSCRIPT) << "using temporary file" << tmpFile->fileName(); + command.replace("$TMPFILE", tmpFile->fileName()); + QByteArray useTextArray = useText.toLocal8Bit(); + if (tmpFile->write(useTextArray) != useTextArray.size()) { + qWarning() << "failed to write text to temporary file"; + return text; + } + } else { + qWarning() << "Failed to create a temporary file"; + return text; + } + tmpFile->close(); + } + + qCDebug(CUSTOMSCRIPT) << "using shell command for indentation: " << command; + proc.setShellCommand(command); + proc.setOutputChannelMode(KProcess::OnlyStdoutChannel); + + proc.start(); + if (!proc.waitForStarted()) { + qCDebug(CUSTOMSCRIPT) << "Unable to start indent" << endl; + return text; + } + + if (!tmpFile.get()) { + proc.write(useText.toLocal8Bit()); + } + + proc.closeWriteChannel(); + if (!proc.waitForFinished()) { + qCDebug(CUSTOMSCRIPT) << "Process doesn't finish" << endl; + return text; + } + + QString output; + + if (tmpFile.get()) { + QFile f(tmpFile->fileName()); + if (f.open(QIODevice::ReadOnly)) { + output = QString::fromLocal8Bit(f.readAll()); + } else { + qWarning() << "Failed opening the temporary file for reading"; + return text; + } + } else { + output = ios.readAll(); + } + if (output.isEmpty()) { + qWarning() << "indent returned empty text for style" << style.name() << style.content(); + return text; + } + + int tabWidth = 4; + if ((!leftContext.isEmpty() || !rightContext.isEmpty()) && (text.contains(' ') || output.contains(' '))) { + // If we have to do contex-matching with tabs, determine the correct tab-width so that the context + // can be matched correctly + Indentation indent = indentation(url); + if (indent.indentationTabWidth > 0) { + tabWidth = indent.indentationTabWidth; + } + } return KDevelop::extractFormattedTextFromContext(output, text, leftContext, rightContext, tabWidth); } -QString CustomScriptPlugin::formatSource(const QString& text, const QUrl &url, const QMimeType& mime, const QString& leftContext, const QString& rightContext) +QString CustomScriptPlugin::formatSource(const QString& text, const QUrl& url, const QMimeType& mime, const QString& leftContext, const QString& rightContext) { - return formatSourceWithStyle( KDevelop::ICore::self()->sourceFormatterController()->styleForMimeType( mime ), text, url, mime, leftContext, rightContext ); + return formatSourceWithStyle(KDevelop::ICore::self()->sourceFormatterController()->styleForMimeType(mime), text, url, mime, leftContext, rightContext); } -static QList stylesFromLanguagePlugins() { - QList styles; - foreach (auto lang, ICore::self()->languageController()->loadedLanguages()) { - const SourceFormatterItemList& languageStyles = lang->sourceFormatterItems(); - for ( const SourceFormatterStyleItem& item: languageStyles ) { - if ( item.engine == "customscript" ) { - styles << item.style; - } - } - } - return styles; +static QList stylesFromLanguagePlugins() +{ + QList styles; + foreach (auto lang, ICore::self()->languageController()->loadedLanguages()) { + const SourceFormatterItemList& languageStyles = lang->sourceFormatterItems(); + for (const SourceFormatterStyleItem& item: languageStyles) { + if (item.engine == "customscript") { + styles << item.style; + } + } + } + + return styles; }; KDevelop::SourceFormatterStyle CustomScriptPlugin::predefinedStyle(const QString& name) { - for ( auto langStyle: stylesFromLanguagePlugins() ) { - qCDebug(CUSTOMSCRIPT) << "looking at style from language with custom sample" << langStyle.description() << langStyle.overrideSample(); - if ( langStyle.name() == name ) { - return langStyle; - } - } - SourceFormatterStyle result(name); - if (name == "GNU_indent_GNU") - { - result.setCaption(i18n("Gnu Indent: GNU")); - result.setContent("indent"); - } else if (name == "GNU_indent_KR") { - result.setCaption(i18n("Gnu Indent: Kernighan & Ritchie")); - result.setContent("indent -kr"); - } else if (name == "GNU_indent_orig") { - result.setCaption(i18n("Gnu Indent: Original Berkeley indent style")); - result.setContent("indent -orig"); - } else if(name == "kdev_format_source") { - result.setCaption("KDevelop: kdev_format_source"); - result.setContent("kdev_format_source $FILE $TMPFILE"); - result.setUsePreview(false); - result.setDescription(i18n( "Description:
" - "kdev_format_source is a script bundled with KDevelop " - "which allows using fine-grained formatting rules by placing " - "meta-files called format_sources into the file-system.

" - "Each line of the format_sources files defines a list of wildcards " - "followed by a colon and the used formatting-command.

" - "The formatting-command should use $TMPFILE to reference the " - "temporary file to reformat.

" - "Example:
" - "*.cpp *.h : myformatter $TMPFILE
" - "This will reformat all files ending with .cpp or .h using " - "the custom formatting script myformatter.

" - "Example:
" - "subdir/* : uncrustify -l CPP -f $TMPFILE -c uncrustify.config -o $TMPFILE
" - "This will reformat all files in subdirectory subdir using the uncrustify " - "tool with the config-file uncrustify.config." )); - } - result.setMimeTypes({ - {"text/x-c++src", "C++"}, {"text/x-chdr", "C"}, - {"text/x-c++hdr", "C++"}, {"text/x-csrc", "C"}, - {"text/x-java", "Java"}, {"text/x-csharp", "C#"} - }); - return result; + for (auto langStyle: stylesFromLanguagePlugins()) { + qCDebug(CUSTOMSCRIPT) << "looking at style from language with custom sample" << langStyle.description() << langStyle.overrideSample(); + if (langStyle.name() == name) { + return langStyle; + } + } + + SourceFormatterStyle result(name); + if (name == "GNU_indent_GNU") { + result.setCaption(i18n("Gnu Indent: GNU")); + result.setContent("indent"); + } else if (name == "GNU_indent_KR") { + result.setCaption(i18n("Gnu Indent: Kernighan & Ritchie")); + result.setContent("indent -kr"); + } else if (name == "GNU_indent_orig") { + result.setCaption(i18n("Gnu Indent: Original Berkeley indent style")); + result.setContent("indent -orig"); + } else if (name == "kdev_format_source") { + result.setCaption("KDevelop: kdev_format_source"); + result.setContent("kdev_format_source $FILE $TMPFILE"); + result.setUsePreview(false); + result.setDescription(i18n("Description:
" + "kdev_format_source is a script bundled with KDevelop " + "which allows using fine-grained formatting rules by placing " + "meta-files called format_sources into the file-system.

" + "Each line of the format_sources files defines a list of wildcards " + "followed by a colon and the used formatting-command.

" + "The formatting-command should use $TMPFILE to reference the " + "temporary file to reformat.

" + "Example:
" + "*.cpp *.h : myformatter $TMPFILE
" + "This will reformat all files ending with .cpp or .h using " + "the custom formatting script myformatter.

" + "Example:
" + "subdir/* : uncrustify -l CPP -f $TMPFILE -c uncrustify.config -o $TMPFILE
" + "This will reformat all files in subdirectory subdir using the uncrustify " + "tool with the config-file uncrustify.config.")); + } + result.setMimeTypes({ + {"text/x-c++src", "C++"}, {"text/x-chdr", "C"}, + {"text/x-c++hdr", "C++"}, {"text/x-csrc", "C"}, + {"text/x-java", "Java"}, {"text/x-csharp", "C#"} + }); + return result; } QList CustomScriptPlugin::predefinedStyles() { - QList styles = stylesFromLanguagePlugins(); - styles << predefinedStyle("kdev_format_source"); - styles << predefinedStyle("GNU_indent_GNU"); - styles << predefinedStyle("GNU_indent_KR"); - styles << predefinedStyle("GNU_indent_orig"); - return styles; + QList styles = stylesFromLanguagePlugins(); + styles << predefinedStyle("kdev_format_source"); + styles << predefinedStyle("GNU_indent_GNU"); + styles << predefinedStyle("GNU_indent_KR"); + styles << predefinedStyle("GNU_indent_orig"); + return styles; } KDevelop::SettingsWidget* CustomScriptPlugin::editStyleWidget(const QMimeType& mime) { - Q_UNUSED(mime); - return new CustomScriptPreferences(); + Q_UNUSED(mime); + return new CustomScriptPreferences(); } static QString formattingSample() { return - "// Formatting\n" - "void func(){\n" - "\tif(isFoo(a,b))\n" - "\tbar(a,b);\n" - "if(isFoo)\n" - "\ta=bar((b-c)*a,*d--);\n" - "if( isFoo( a,b ) )\n" - "\tbar(a, b);\n" - "if (isFoo) {isFoo=false;cat << isFoo <::const_iterator it = list.begin();\n" - "}\n" - "namespace A {\n" - "namespace B {\n" - "void foo() {\n" - " if (true) {\n" - " func();\n" - " } else {\n" - " // bla\n" - " }\n" - "}\n" - "}\n" - "}\n"; + "// Formatting\n" + "void func(){\n" + "\tif(isFoo(a,b))\n" + "\tbar(a,b);\n" + "if(isFoo)\n" + "\ta=bar((b-c)*a,*d--);\n" + "if( isFoo( a,b ) )\n" + "\tbar(a, b);\n" + "if (isFoo) {isFoo=false;cat << isFoo <::const_iterator it = list.begin();\n" + "}\n" + "namespace A {\n" + "namespace B {\n" + "void foo() {\n" + " if (true) {\n" + " func();\n" + " } else {\n" + " // bla\n" + " }\n" + "}\n" + "}\n" + "}\n"; } static QString indentingSample() { return - "// Indentation\n" - "#define foobar(A)\\\n" - "{Foo();Bar();}\n" - "#define anotherFoo(B)\\\n" - "return Bar()\n" - "\n" - "namespace Bar\n" - "{\n" - "class Foo\n" - "{public:\n" - "Foo();\n" - "virtual ~Foo();\n" - "};\n" - "switch (foo)\n" - "{\n" - "case 1:\n" - "a+=1;\n" - "break;\n" - "case 2:\n" - "{\n" - "a += 2;\n" - " break;\n" - "}\n" - "}\n" - "if (isFoo)\n" - "{\n" - "bar();\n" - "}\n" - "else\n" - "{\n" - "anotherBar();\n" - "}\n" - "int foo()\n" - "\twhile(isFoo)\n" - "\t\t{\n" - "\t\t\t...\n" - "\t\t\tgoto error;\n" - "\t\t....\n" - "\t\terror:\n" - "\t\t\t...\n" - "\t\t}\n" - "\t}\n" - "fooArray[]={ red,\n" - "\tgreen,\n" - "\tdarkblue};\n" - "fooFunction(barArg1,\n" - "\tbarArg2,\n" - "\tbarArg3);\n"; + "// Indentation\n" + "#define foobar(A)\\\n" + "{Foo();Bar();}\n" + "#define anotherFoo(B)\\\n" + "return Bar()\n" + "\n" + "namespace Bar\n" + "{\n" + "class Foo\n" + "{public:\n" + "Foo();\n" + "virtual ~Foo();\n" + "};\n" + "switch (foo)\n" + "{\n" + "case 1:\n" + "a+=1;\n" + "break;\n" + "case 2:\n" + "{\n" + "a += 2;\n" + " break;\n" + "}\n" + "}\n" + "if (isFoo)\n" + "{\n" + "bar();\n" + "}\n" + "else\n" + "{\n" + "anotherBar();\n" + "}\n" + "int foo()\n" + "\twhile(isFoo)\n" + "\t\t{\n" + "\t\t\t...\n" + "\t\t\tgoto error;\n" + "\t\t....\n" + "\t\terror:\n" + "\t\t\t...\n" + "\t\t}\n" + "\t}\n" + "fooArray[]={ red,\n" + "\tgreen,\n" + "\tdarkblue};\n" + "fooFunction(barArg1,\n" + "\tbarArg2,\n" + "\tbarArg3);\n"; } QString CustomScriptPlugin::previewText(const SourceFormatterStyle& style, const QMimeType& /*mime*/) { - if ( ! style.overrideSample().isEmpty() ) { - return style.overrideSample(); - } - return formattingSample() + "\n\n" + indentingSample(); + if (!style.overrideSample().isEmpty()) { + return style.overrideSample(); + } + return formattingSample() + "\n\n" + indentingSample(); } - -QStringList CustomScriptPlugin::computeIndentationFromSample( const QUrl &url ) +QStringList CustomScriptPlugin::computeIndentationFromSample(const QUrl& url) { - QStringList ret; + QStringList ret; - auto languages = ICore::self()->languageController()->languagesForUrl( url ); - if (languages.isEmpty()) + auto languages = ICore::self()->languageController()->languagesForUrl(url); + if (languages.isEmpty()) { return ret; + } QString sample = languages[0]->indentationSample(); QString formattedSample = formatSource(sample, url, QMimeDatabase().mimeTypeForUrl(url), QString(), QString()); - QStringList lines = formattedSample.split( "\n" ); - foreach( QString line, lines ) - { - if( !line.isEmpty() && line[0].isSpace() ) - { - QString indent; - foreach( QChar c, line ) - { - if( c.isSpace() ) - indent.push_back( c ); - else - break; - } - if(!indent.isEmpty() && !ret.contains(indent)) - ret.push_back(indent); - } - } - - return ret; + QStringList lines = formattedSample.split("\n"); + foreach (QString line, lines) { + if (!line.isEmpty() && line[0].isSpace()) { + QString indent; + foreach (QChar c, line) { + if (c.isSpace()) { + indent.push_back(c); + } else { + break; + } + } + + if (!indent.isEmpty() && !ret.contains(indent)) { + ret.push_back(indent); + } + } + } + + return ret; } -CustomScriptPlugin::Indentation CustomScriptPlugin::indentation( const QUrl &url ) +CustomScriptPlugin::Indentation CustomScriptPlugin::indentation(const QUrl& url) { Indentation ret; - QStringList indent = computeIndentationFromSample( url ); - if( indent.isEmpty() ) - { + QStringList indent = computeIndentationFromSample(url); + if (indent.isEmpty()) { qCDebug(CUSTOMSCRIPT) << "failed extracting a valid indentation from sample for url" << url; return ret; // No valid indentation could be extracted } - if( indent[0].contains( ' ' ) ) - ret.indentWidth = indent[0].count(' '); - - if( !indent.join("").contains(' ') ) - ret.indentationTabWidth = -1; // Tabs are not used for indentation - - if( indent[0] == " " ) - { - // The script indents with tabs-only - // The problem is that we don't know how - // wide a tab is supposed to be. - // - // We need indentation-width=tab-width - // to make the editor do tab-only formatting, - // so choose a random with of 4. - ret.indentWidth = 4; - ret.indentationTabWidth = 4; - }else if(ret.indentWidth) { - // Tabs are used for indentation, alongside with spaces - // Try finding out how many spaces one tab stands for. - // Do it by assuming a uniform indentation-step with each level. - - for(int pos = 0; pos < indent.size(); ++pos) - { - if(indent[pos] == " " && pos >= 1) - { - // This line consists of only a tab. - int prevWidth = indent[pos-1].length(); - int prevPrevWidth = (pos >= 2) ? indent[pos-2].length() : 0; - int step = prevWidth - prevPrevWidth; - qCDebug(CUSTOMSCRIPT) << "found in line " << pos << prevWidth << prevPrevWidth << step; - if(step > 0 && step <= prevWidth) - { - qCDebug(CUSTOMSCRIPT) << "Done"; - ret.indentationTabWidth = prevWidth + step; - break; - } - } - } - } + if (indent[0].contains(' ')) { + ret.indentWidth = indent[0].count(' '); + } + + if (!indent.join("").contains(' ')) { + ret.indentationTabWidth = -1; // Tabs are not used for indentation + } + if (indent[0] == " ") { + // The script indents with tabs-only + // The problem is that we don't know how + // wide a tab is supposed to be. + // + // We need indentation-width=tab-width + // to make the editor do tab-only formatting, + // so choose a random with of 4. + ret.indentWidth = 4; + ret.indentationTabWidth = 4; + } else if (ret.indentWidth) { + // Tabs are used for indentation, alongside with spaces + // Try finding out how many spaces one tab stands for. + // Do it by assuming a uniform indentation-step with each level. + + for (int pos = 0; pos < indent.size(); ++pos) { + if (indent[pos] == " "&& pos >= 1) { + // This line consists of only a tab. + int prevWidth = indent[pos - 1].length(); + int prevPrevWidth = (pos >= 2) ? indent[pos - 2].length() : 0; + int step = prevWidth - prevPrevWidth; + qCDebug(CUSTOMSCRIPT) << "found in line " << pos << prevWidth << prevPrevWidth << step; + if (step > 0 && step <= prevWidth) { + qCDebug(CUSTOMSCRIPT) << "Done"; + ret.indentationTabWidth = prevWidth + step; + break; + } + } + } + } qCDebug(CUSTOMSCRIPT) << "indent-sample" << "\"" + indent.join("\n") + "\"" << "extracted tab-width" << ret.indentationTabWidth << "extracted indentation width" << ret.indentWidth; return ret; } void CustomScriptPreferences::updateTimeout() { - const QString& text = indentPluginSingleton.data()->previewText(m_style, QMimeType()); + const QString& text = indentPluginSingleton.data()->previewText(m_style, QMimeType()); QString formatted = indentPluginSingleton.data()->formatSourceWithStyle(m_style, text, QUrl(), QMimeType()); - emit previewTextChanged ( formatted ); + emit previewTextChanged(formatted); } CustomScriptPreferences::CustomScriptPreferences() { - m_updateTimer = new QTimer ( this ); - m_updateTimer->setSingleShot ( true ); - connect ( m_updateTimer, &QTimer::timeout, this, &CustomScriptPreferences::updateTimeout ); - m_vLayout = new QVBoxLayout ( this ); + m_updateTimer = new QTimer(this); + m_updateTimer->setSingleShot(true); + connect(m_updateTimer, &QTimer::timeout, this, &CustomScriptPreferences::updateTimeout); + m_vLayout = new QVBoxLayout(this); m_captionLabel = new QLabel; - m_vLayout->addWidget ( m_captionLabel ); - m_vLayout->addSpacing ( 10 ); + m_vLayout->addWidget(m_captionLabel); + m_vLayout->addSpacing(10); m_hLayout = new QHBoxLayout; - m_vLayout->addLayout ( m_hLayout ); + m_vLayout->addLayout(m_hLayout); m_commandLabel = new QLabel; - m_hLayout->addWidget ( m_commandLabel ); + m_hLayout->addWidget(m_commandLabel); m_commandEdit = new QLineEdit; - m_hLayout->addWidget ( m_commandEdit ); - m_commandLabel->setText ( i18n("Command:") ); - m_vLayout->addSpacing ( 10 ); + m_hLayout->addWidget(m_commandEdit); + m_commandLabel->setText(i18n("Command:")); + m_vLayout->addSpacing(10); m_bottomLabel = new QLabel; - m_vLayout->addWidget ( m_bottomLabel ); - m_bottomLabel->setTextFormat ( Qt::RichText ); - m_bottomLabel->setText ( - i18n ( "You can enter an arbitrary shell command.
" - "The unformatted source-code is reached to the command
" - "through the standard input, and the
" - "formatted result is read from the standard output.
" - "
" - "If you add $TMPFILE into the command, then
" - "a temporary file is used for transferring the code." ) ); - connect ( m_commandEdit, &QLineEdit::textEdited, this, &CustomScriptPreferences::textEdited ); - - m_vLayout->addSpacing ( 10 ); - - m_moreVariablesButton = new QPushButton( i18n("More Variables") ); - connect( m_moreVariablesButton, &QPushButton::clicked, this, &CustomScriptPreferences::moreVariablesClicked ); - m_vLayout->addWidget( m_moreVariablesButton ); - + m_vLayout->addWidget(m_bottomLabel); + m_bottomLabel->setTextFormat(Qt::RichText); + m_bottomLabel->setText( + i18n("You can enter an arbitrary shell command.
" + "The unformatted source-code is reached to the command
" + "through the standard input, and the
" + "formatted result is read from the standard output.
" + "
" + "If you add $TMPFILE into the command, then
" + "a temporary file is used for transferring the code.")); + connect(m_commandEdit, &QLineEdit::textEdited, this, &CustomScriptPreferences::textEdited); + + m_vLayout->addSpacing(10); + + m_moreVariablesButton = new QPushButton(i18n("More Variables")); + connect(m_moreVariablesButton, &QPushButton::clicked, this, &CustomScriptPreferences::moreVariablesClicked); + m_vLayout->addWidget(m_moreVariablesButton); } -void CustomScriptPreferences::load ( const KDevelop::SourceFormatterStyle& style ) +void CustomScriptPreferences::load(const KDevelop::SourceFormatterStyle& style) { m_style = style; - m_commandEdit->setText ( style.content() ); - m_captionLabel->setText ( i18n ( "Style: %1", style.caption() ) ); + m_commandEdit->setText(style.content()); + m_captionLabel->setText(i18n("Style: %1", style.caption())); updateTimeout(); } @@ -541,22 +530,22 @@ return m_commandEdit->text(); } -void CustomScriptPreferences::moreVariablesClicked ( bool ) +void CustomScriptPreferences::moreVariablesClicked(bool) { - KMessageBox::information( ICore::self()->uiController()->activeMainWindow(), - i18n("$TMPFILE will be replaced with the path to a temporary file.
" - "The code will be written into the file, the temporary
" - "file will be substituted into that position, and the result
" - "will be read out of that file.
" - "
" - "$FILE will be replaced with the path of the original file.
" - "The contents of the file must not be modified, changes are allowed
" - "only in $TMPFILE.
" - "
" - "${PROJECT_NAME} will be replaced by the path of
" - "the currently open project with the matching name." - - ), i18n("Variable Replacements") ); + KMessageBox::information(ICore::self()->uiController()->activeMainWindow(), + i18n("$TMPFILE will be replaced with the path to a temporary file.
" + "The code will be written into the file, the temporary
" + "file will be substituted into that position, and the result
" + "will be read out of that file.
" + "
" + "$FILE will be replaced with the path of the original file.
" + "The contents of the file must not be modified, changes are allowed
" + "only in $TMPFILE.
" + "
" + "${PROJECT_NAME} will be replaced by the path of
" + "the currently open project with the matching name." + + ), i18n("Variable Replacements")); } #include "customscript_plugin.moc" diff --git a/kdeintegration/executeplasmoid/executeplasmoidplugin.h b/kdeintegration/executeplasmoid/executeplasmoidplugin.h --- a/kdeintegration/executeplasmoid/executeplasmoidplugin.h +++ b/kdeintegration/executeplasmoid/executeplasmoidplugin.h @@ -37,7 +37,7 @@ Q_OBJECT Q_INTERFACES( IExecutePlugin ) public: - ExecutePlasmoidPlugin(QObject *parent, const QVariantList & = QVariantList() ); + explicit ExecutePlasmoidPlugin(QObject *parent, const QVariantList & = QVariantList() ); ~ExecutePlasmoidPlugin() override; void unload() override; diff --git a/kdeintegration/executeplasmoid/plasmoidexecutionconfig.h b/kdeintegration/executeplasmoid/plasmoidexecutionconfig.h --- a/kdeintegration/executeplasmoid/plasmoidexecutionconfig.h +++ b/kdeintegration/executeplasmoid/plasmoidexecutionconfig.h @@ -34,7 +34,7 @@ { Q_OBJECT public: - PlasmoidExecutionConfig( QWidget* parent ); + explicit PlasmoidExecutionConfig( QWidget* parent ); void loadFromConfiguration( const KConfigGroup& cfg, KDevelop::IProject* project = nullptr ) override; void saveToConfiguration( KConfigGroup cfg, KDevelop::IProject* project = nullptr ) const override; QString title() const override; @@ -44,7 +44,7 @@ class PlasmoidLauncher : public KDevelop::ILauncher { public: - PlasmoidLauncher( ExecutePlasmoidPlugin* plugin ); + explicit PlasmoidLauncher( ExecutePlasmoidPlugin* plugin ); QList< KDevelop::LaunchConfigurationPageFactory* > configPages() const override; QString description() const override; QString id() override; diff --git a/languages/clang/clanghighlighting.cpp b/languages/clang/clanghighlighting.cpp --- a/languages/clang/clanghighlighting.cpp +++ b/languages/clang/clanghighlighting.cpp @@ -30,7 +30,7 @@ class ClangHighlighting::Instance : public KDevelop::CodeHighlightingInstance { public: - Instance(const KDevelop::CodeHighlighting* highlighting); + explicit Instance(const KDevelop::CodeHighlighting* highlighting); KDevelop::HighlightingEnumContainer::Types typeForDeclaration(KDevelop::Declaration* dec, KDevelop::DUContext* context) const override { diff --git a/languages/clang/clangsettings/sessionsettings/sessionconfigskeleton.h b/languages/clang/clangsettings/sessionsettings/sessionconfigskeleton.h --- a/languages/clang/clangsettings/sessionsettings/sessionconfigskeleton.h +++ b/languages/clang/clangsettings/sessionsettings/sessionconfigskeleton.h @@ -34,7 +34,7 @@ class SessionConfigSkeleton : public KConfigSkeleton { public: - SessionConfigSkeleton( const QString& ) + explicit SessionConfigSkeleton( const QString& ) : KConfigSkeleton( ICore::self()->activeSession()->config() ) { } diff --git a/languages/clang/clangsettings/sessionsettings/sessionsettings.cpp b/languages/clang/clangsettings/sessionsettings/sessionsettings.cpp --- a/languages/clang/clangsettings/sessionsettings/sessionsettings.cpp +++ b/languages/clang/clangsettings/sessionsettings/sessionsettings.cpp @@ -23,21 +23,14 @@ #include "sessionsettings.h" -#include - #include "sessionconfig.h" #include "ui_sessionsettings.h" SessionSettings::SessionSettings(QWidget* parent) : ConfigPage(nullptr, SessionConfig::self(), parent) , m_settings(new Ui::SessionSettings) { - auto l = new QVBoxLayout(this); - auto w = new QWidget(this); - - m_settings->setupUi(w); - - l->addWidget(w); + m_settings->setupUi(this); } void SessionSettings::reset() diff --git a/languages/clang/codecompletion/context.cpp b/languages/clang/codecompletion/context.cpp --- a/languages/clang/codecompletion/context.cpp +++ b/languages/clang/codecompletion/context.cpp @@ -285,7 +285,7 @@ return replacement; } - ImplementsItem(const FuncImplementInfo& item) + explicit ImplementsItem(const FuncImplementInfo& item) : DeclarationItem(item.declaration.data(), item.prototype, i18n("Implement %1", item.isConstructor ? QStringLiteral("") : item.isDestructor ? QStringLiteral("") : item.returnType), @@ -598,7 +598,7 @@ class LookAheadItemMatcher { public: - LookAheadItemMatcher(const TopDUContextPointer& ctx) + explicit LookAheadItemMatcher(const TopDUContextPointer& ctx) : m_topContext(ctx) , m_enabled(ClangSettingsManager::self()->codeCompletionSettings().lookAhead) {} diff --git a/languages/clang/codecompletion/includepathcompletioncontext.cpp b/languages/clang/codecompletion/includepathcompletioncontext.cpp --- a/languages/clang/codecompletion/includepathcompletioncontext.cpp +++ b/languages/clang/codecompletion/includepathcompletioncontext.cpp @@ -220,7 +220,7 @@ class IncludeFileCompletionItem : public AbstractIncludeFileCompletionItem { public: - IncludeFileCompletionItem(const IncludeItem& include) + explicit IncludeFileCompletionItem(const IncludeItem& include) : AbstractIncludeFileCompletionItem(include) {} diff --git a/languages/clang/codecompletion/model.h b/languages/clang/codecompletion/model.h --- a/languages/clang/codecompletion/model.h +++ b/languages/clang/codecompletion/model.h @@ -28,11 +28,6 @@ #include "clangprivateexport.h" -#include -#if KTEXTEDITOR_VERSION < QT_VERSION_CHECK(5, 10, 0) -Q_DECLARE_METATYPE(KTextEditor::Cursor) -#endif - class ClangIndex; class KDEVCLANGPRIVATE_EXPORT ClangCodeCompletionModel : public KDevelop::CodeCompletionModel diff --git a/languages/clang/codegen/adaptsignatureassistant.h b/languages/clang/codegen/adaptsignatureassistant.h --- a/languages/clang/codegen/adaptsignatureassistant.h +++ b/languages/clang/codegen/adaptsignatureassistant.h @@ -39,7 +39,7 @@ Q_OBJECT public: - AdaptSignatureAssistant(KDevelop::ILanguageSupport* supportedLanguage); + explicit AdaptSignatureAssistant(KDevelop::ILanguageSupport* supportedLanguage); QString title() const override; void textChanged(KTextEditor::Document* doc, const KTextEditor::Range& invocationRange, const QString& removedText = QString()) override; diff --git a/languages/clang/codegen/clangrefactoring.h b/languages/clang/codegen/clangrefactoring.h --- a/languages/clang/codegen/clangrefactoring.h +++ b/languages/clang/codegen/clangrefactoring.h @@ -28,6 +28,8 @@ #include +class TestRefactoring; + namespace KDevelop { class Context; @@ -49,7 +51,12 @@ public slots: void executeMoveIntoSourceAction(); +protected: + KDevelop::DocumentChangeSet::ChangeResult applyChangesToDeclarations(const QString& oldName, const QString& newName, KDevelop::DocumentChangeSet& changes, const QList& declarations) override; + private: + friend TestRefactoring; + bool validCandidateToMoveIntoSource(KDevelop::Declaration* decl); }; diff --git a/languages/clang/codegen/clangrefactoring.cpp b/languages/clang/codegen/clangrefactoring.cpp --- a/languages/clang/codegen/clangrefactoring.cpp +++ b/languages/clang/codegen/clangrefactoring.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,27 @@ using namespace KDevelop; +namespace { + +bool isDestructor(Declaration* decl) +{ + if (auto functionDef = dynamic_cast(decl)) { + // we found a definition, e.g. "Foo::~Foo()" + const auto functionDecl = functionDef->declaration(decl->topContext()); + if (auto classFunctionDecl = dynamic_cast(functionDecl)) { + return classFunctionDecl->isDestructor(); + } + } + else if (auto classFunctionDecl = dynamic_cast(decl)) { + // we found a declaration, e.g. "~Foo()" + return classFunctionDecl->isDestructor(); + } + + return false; +} + +} + ClangRefactoring::ClangRefactoring(QObject* parent) : BasicRefactoring(parent) { @@ -100,6 +122,10 @@ return false; } + if (dynamic_cast(decl)) { + return false; + } + auto childCtx = decl->internalContext()->childContexts(); if (childCtx.isEmpty()) { return false; @@ -229,3 +255,36 @@ KMessageBox::error(nullptr, error); } } + +DocumentChangeSet::ChangeResult ClangRefactoring::applyChangesToDeclarations(const QString& oldName, + const QString& newName, + DocumentChangeSet& changes, + const QList& declarations) +{ + foreach (const IndexedDeclaration decl, declarations) { + Declaration *declaration = decl.data(); + if (!declaration) + continue; + + if (declaration->range().isEmpty()) + clangDebug() << "found empty declaration:" << declaration->toString(); + + // special handling for dtors, their name is not "Foo", but "~Foo" + // see https://bugs.kde.org/show_bug.cgi?id=373452 + QString fixedOldName = oldName; + QString fixedNewName = newName; + + if (isDestructor(declaration)) { + clangDebug() << "found destructor:" << declaration->toString() << "-- making sure we replace the identifier correctly"; + fixedOldName = QLatin1Char('~') + oldName; + fixedNewName = QLatin1Char('~') + newName; + } + + TopDUContext *top = declaration->topContext(); + DocumentChangeSet::ChangeResult result = changes.addChange(DocumentChange(top->url(), declaration->rangeInCurrentRevision(), fixedOldName, fixedNewName)); + if (!result) + return result; + } + + return KDevelop::DocumentChangeSet::ChangeResult::successfulResult(); +} diff --git a/languages/clang/codegen/codegenhelper.cpp b/languages/clang/codegen/codegenhelper.cpp --- a/languages/clang/codegen/codegenhelper.cpp +++ b/languages/clang/codegen/codegenhelper.cpp @@ -220,7 +220,7 @@ : public TypeExchanger { DUContext* ctx; - ShortenTemplateDefaultParameter(DUContext* _ctx) + explicit ShortenTemplateDefaultParameter(DUContext* _ctx) : ctx(_ctx) { Q_ASSERT(ctx); } diff --git a/languages/clang/duchain/clangducontext.h b/languages/clang/duchain/clangducontext.h --- a/languages/clang/duchain/clangducontext.h +++ b/languages/clang/duchain/clangducontext.h @@ -30,12 +30,12 @@ { public: template - ClangDUContext(Data& data) : BaseContext(data) { + explicit ClangDUContext(Data& data) : BaseContext(data) { } ///Parameters will be reached to the base-class template - ClangDUContext(Params... params) : BaseContext(params...) { + explicit ClangDUContext(Params... params) : BaseContext(params...) { static_cast(this)->d_func_dynamic()->setClassId(this); } diff --git a/languages/clang/duchain/clangindex.h b/languages/clang/duchain/clangindex.h --- a/languages/clang/duchain/clangindex.h +++ b/languages/clang/duchain/clangindex.h @@ -46,11 +46,12 @@ CXIndex index() const; /** - * @returns the existing ClangPCH for the @param pchInclude - * The PCH is created using @param includePaths and @param defines if it doesn't exist + * @returns the existing ClangPCH for @p environment + * + * The PCH is created using @p environment if it doesn't exist * This function is thread safe. */ - QSharedPointer pch(const ClangParsingEnvironment& defines); + QSharedPointer pch(const ClangParsingEnvironment& environment); /** * Gets the currently pinned TU for @p url diff --git a/languages/clang/duchain/clangparsingenvironmentfile.h b/languages/clang/duchain/clangparsingenvironmentfile.h --- a/languages/clang/duchain/clangparsingenvironmentfile.h +++ b/languages/clang/duchain/clangparsingenvironmentfile.h @@ -36,7 +36,7 @@ using Ptr = QExplicitlySharedDataPointer; ClangParsingEnvironmentFile(const KDevelop::IndexedString& url, const ClangParsingEnvironment& environment); - ClangParsingEnvironmentFile(ClangParsingEnvironmentFileData& data); + explicit ClangParsingEnvironmentFile(ClangParsingEnvironmentFileData& data); ~ClangParsingEnvironmentFile(); bool needsUpdate(const KDevelop::ParsingEnvironment* environment = nullptr) const override; diff --git a/languages/clang/duchain/clangproblem.h b/languages/clang/duchain/clangproblem.h --- a/languages/clang/duchain/clangproblem.h +++ b/languages/clang/duchain/clangproblem.h @@ -85,7 +85,7 @@ Q_OBJECT public: - ClangFixitAssistant(const ClangFixits& fixits); + explicit ClangFixitAssistant(const ClangFixits& fixits); ClangFixitAssistant(const QString& title, const ClangFixits& fixits); QString title() const override; @@ -104,7 +104,7 @@ Q_OBJECT public: - ClangFixitAction(const ClangFixit& fixit); + explicit ClangFixitAction(const ClangFixit& fixit); QString description() const override; diff --git a/languages/clang/duchain/debugvisitor.h b/languages/clang/duchain/debugvisitor.h --- a/languages/clang/duchain/debugvisitor.h +++ b/languages/clang/duchain/debugvisitor.h @@ -28,7 +28,7 @@ class KDEVCLANGPRIVATE_EXPORT DebugVisitor { public: - DebugVisitor(ParseSession* session); + explicit DebugVisitor(ParseSession* session); void visit(CXTranslationUnit unit, CXFile file); diff --git a/languages/clang/duchain/macrodefinition.h b/languages/clang/duchain/macrodefinition.h --- a/languages/clang/duchain/macrodefinition.h +++ b/languages/clang/duchain/macrodefinition.h @@ -47,7 +47,7 @@ using Ptr = KDevelop::DUChainPointer; MacroDefinition(const KDevelop::RangeInRevision& range, KDevelop::DUContext* context); - MacroDefinition(MacroDefinitionData& data); + explicit MacroDefinition(MacroDefinitionData& data); MacroDefinition(const MacroDefinition& rhs); virtual ~MacroDefinition(); diff --git a/languages/clang/duchain/macronavigationcontext.h b/languages/clang/duchain/macronavigationcontext.h --- a/languages/clang/duchain/macronavigationcontext.h +++ b/languages/clang/duchain/macronavigationcontext.h @@ -32,7 +32,7 @@ class KDEVCLANGPRIVATE_EXPORT MacroNavigationContext : public KDevelop::AbstractNavigationContext { public: - MacroNavigationContext(const MacroDefinition::Ptr& macro, + explicit MacroNavigationContext(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation = KDevelop::DocumentCursor::invalid()); ~MacroNavigationContext(); diff --git a/languages/clang/duchain/missingincludepathproblem.cpp b/languages/clang/duchain/missingincludepathproblem.cpp --- a/languages/clang/duchain/missingincludepathproblem.cpp +++ b/languages/clang/duchain/missingincludepathproblem.cpp @@ -41,7 +41,7 @@ Q_OBJECT public: - AddCustomIncludePathAction(const KDevelop::IndexedString& path) + explicit AddCustomIncludePathAction(const KDevelop::IndexedString& path) : m_path(path) {} @@ -63,7 +63,7 @@ class OpenProjectForFileAssistant : public KDevelop::IAssistantAction { public: - OpenProjectForFileAssistant(const KDevelop::IndexedString& path) + explicit OpenProjectForFileAssistant(const KDevelop::IndexedString& path) : m_path(path) {} diff --git a/languages/clang/duchain/navigationwidget.h b/languages/clang/duchain/navigationwidget.h --- a/languages/clang/duchain/navigationwidget.h +++ b/languages/clang/duchain/navigationwidget.h @@ -38,7 +38,7 @@ class KDEVCLANGPRIVATE_EXPORT ClangNavigationWidget : public KDevelop::AbstractNavigationWidget { public: - ClangNavigationWidget(const KDevelop::DeclarationPointer& declaration, + explicit ClangNavigationWidget(const KDevelop::DeclarationPointer& declaration, KDevelop::AbstractNavigationWidget::DisplayHints hints = KDevelop::AbstractNavigationWidget::NoHints); ClangNavigationWidget(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation, KDevelop::AbstractNavigationWidget::DisplayHints hints = KDevelop::AbstractNavigationWidget::NoHints); diff --git a/languages/clang/duchain/navigationwidget.cpp b/languages/clang/duchain/navigationwidget.cpp --- a/languages/clang/duchain/navigationwidget.cpp +++ b/languages/clang/duchain/navigationwidget.cpp @@ -34,7 +34,7 @@ class DeclarationNavigationContext : public AbstractDeclarationNavigationContext { public: - DeclarationNavigationContext(const DeclarationPointer& decl, AbstractNavigationContext* previousContext = nullptr) + explicit DeclarationNavigationContext(const DeclarationPointer& decl, AbstractNavigationContext* previousContext = nullptr) : AbstractDeclarationNavigationContext(decl, {}, previousContext) { } diff --git a/languages/clang/duchain/parsesession.h b/languages/clang/duchain/parsesession.h --- a/languages/clang/duchain/parsesession.h +++ b/languages/clang/duchain/parsesession.h @@ -99,7 +99,7 @@ /** * Initialize a parse session with the given data and, if that data is valid, lock its mutex. */ - ParseSession(const ParseSessionData::Ptr& data); + explicit ParseSession(const ParseSessionData::Ptr& data); /** * Unlocks the mutex of the currently set ParseSessionData. */ diff --git a/languages/clang/duchain/types/classspecializationtype.h b/languages/clang/duchain/types/classspecializationtype.h --- a/languages/clang/duchain/types/classspecializationtype.h +++ b/languages/clang/duchain/types/classspecializationtype.h @@ -53,7 +53,7 @@ public: ClassSpecializationType(const ClassSpecializationType& rhs); - ClassSpecializationType(ClassSpecializationTypeData& data); + explicit ClassSpecializationType(ClassSpecializationTypeData& data); typedef KDevelop::TypePtr Ptr; diff --git a/languages/clang/duchain/unsavedfile.h b/languages/clang/duchain/unsavedfile.h --- a/languages/clang/duchain/unsavedfile.h +++ b/languages/clang/duchain/unsavedfile.h @@ -34,7 +34,7 @@ class KDEVCLANGPRIVATE_EXPORT UnsavedFile { public: - UnsavedFile(const QString& fileName = {}, const QStringList& contents = {}); + explicit UnsavedFile(const QString& fileName = {}, const QStringList& contents = {}); CXUnsavedFile toClangApi() const; diff --git a/languages/clang/tests/CMakeLists.txt b/languages/clang/tests/CMakeLists.txt --- a/languages/clang/tests/CMakeLists.txt +++ b/languages/clang/tests/CMakeLists.txt @@ -60,6 +60,14 @@ KDevClangPrivate ) +ecm_add_test(test_refactoring.cpp + TEST_NAME test_refactoring-clang + LINK_LIBRARIES + KDev::Tests + Qt5::Test + KDevClangPrivate +) + ecm_add_test(test_duchainutils.cpp TEST_NAME test_duchainutils LINK_LIBRARIES diff --git a/languages/clang/tests/codecompletiontestbase.cpp b/languages/clang/tests/codecompletiontestbase.cpp --- a/languages/clang/tests/codecompletiontestbase.cpp +++ b/languages/clang/tests/codecompletiontestbase.cpp @@ -37,11 +37,6 @@ #include #include -#include -#if KTEXTEDITOR_VERSION < QT_VERSION_CHECK(5, 10, 0) -Q_DECLARE_METATYPE(KTextEditor::Cursor); -#endif - void DeleteDocument::operator()(KTextEditor::View* view) const { delete view->document(); diff --git a/languages/clang/tests/test_buddies.cpp b/languages/clang/tests/test_buddies.cpp --- a/languages/clang/tests/test_buddies.cpp +++ b/languages/clang/tests/test_buddies.cpp @@ -405,7 +405,7 @@ // check that it only contains pNewView QVERIFY(pContainer->count() == 1 && pContainer->hasWidget(pNewView->widget())); - // now open the correponding definition file, classA.cpp + // now open the corresponding definition file, classA.cpp IDocument *pClassAImplem = m_documentController->openDocument(QUrl::fromLocalFile(dirA.filePath("classA.cpp"))); QVERIFY(pClassAImplem); pMainWindow->activeView()->setObjectName("classA.cpp"); diff --git a/languages/clang/tests/test_clangutils.cpp b/languages/clang/tests/test_clangutils.cpp --- a/languages/clang/tests/test_clangutils.cpp +++ b/languages/clang/tests/test_clangutils.cpp @@ -38,11 +38,6 @@ #include -#include -#if KTEXTEDITOR_VERSION < QT_VERSION_CHECK(5, 10, 0) -Q_DECLARE_METATYPE(KTextEditor::Range); -#endif - QTEST_MAIN(TestClangUtils) using namespace KDevelop; diff --git a/languages/clang/tests/test_duchain.cpp b/languages/clang/tests/test_duchain.cpp --- a/languages/clang/tests/test_duchain.cpp +++ b/languages/clang/tests/test_duchain.cpp @@ -227,7 +227,7 @@ void TestDUChain::testInclude() { TestFile header("int foo() { return 42; }\n", "h"); - // NOTE: header is _not_ explictly being parsed, instead the impl job does that + // NOTE: header is _not_ explicitly being parsed, instead the impl job does that TestFile impl("#include \"" + header.url().byteArray() + "\"\n" "int main() { return foo(); }", "cpp", &header); diff --git a/languages/clang/tests/test_duchainutils.cpp b/languages/clang/tests/test_duchainutils.cpp --- a/languages/clang/tests/test_duchainutils.cpp +++ b/languages/clang/tests/test_duchainutils.cpp @@ -32,11 +32,6 @@ using namespace KDevelop; -#include -#if KTEXTEDITOR_VERSION < QT_VERSION_CHECK(5, 10, 0) -Q_DECLARE_METATYPE(KTextEditor::Range); -#endif - QTEST_GUILESS_MAIN(TestDUChainUtils); void TestDUChainUtils::initTestCase() diff --git a/languages/clang/tests/test_problems.cpp b/languages/clang/tests/test_problems.cpp --- a/languages/clang/tests/test_problems.cpp +++ b/languages/clang/tests/test_problems.cpp @@ -40,12 +40,6 @@ #include #include -#include -#if KTEXTEDITOR_VERSION < QT_VERSION_CHECK(5, 10, 0) -Q_DECLARE_METATYPE(KTextEditor::Cursor); -Q_DECLARE_METATYPE(KTextEditor::Range); -#endif - Q_DECLARE_METATYPE(KDevelop::IProblem::Severity); using namespace KDevelop; @@ -254,10 +248,9 @@ QVERIFY(clangFixitAssistant); auto fixits = clangFixitAssistant->fixits(); - QCOMPARE(fixits.size(), 3); + QCOMPARE(fixits.size(), 2); QCOMPARE(fixits[0].replacementText, QString("class A;\n")); - QCOMPARE(fixits[1].replacementText, QString("struct A;\n")); // TODO: We shouldn't show this - QCOMPARE(fixits[2].replacementText, QString("#include \"%1\"\n").arg(include.url().toUrl().fileName())); + QCOMPARE(fixits[1].replacementText, QString("#include \"%1\"\n").arg(include.url().toUrl().fileName())); } struct ExpectedTodo diff --git a/debuggers/lldb/controllers/breakpointcontroller.h b/languages/clang/tests/test_refactoring.h copy from debuggers/lldb/controllers/breakpointcontroller.h copy to languages/clang/tests/test_refactoring.h --- a/debuggers/lldb/controllers/breakpointcontroller.h +++ b/languages/clang/tests/test_refactoring.h @@ -1,6 +1,5 @@ /* - * LLDB Breakpoint Controller - * Copyright 2016 Aetf + * Copyright 2017 Kevin Funk * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,27 +16,34 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * */ -#ifndef LLDB_BREAKPOINTCONTROLLER_H -#define LLDB_BREAKPOINTCONTROLLER_H +#ifndef TEST_REFACTORING_H +#define TEST_REFACTORING_H -#include "mibreakpointcontroller.h" +#include -namespace KDevMI { namespace LLDB { +namespace KDevelop { +class TestProjectController; +} -class DebugSession; -class BreakpointController : public MIBreakpointController +class TestRefactoring : public QObject { Q_OBJECT - public: - BreakpointController(DebugSession *parent); + ~TestRefactoring() override; + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void init(); + void cleanup(); + + void testClassRename(); + private: + KDevelop::TestProjectController* m_projectController; }; -} // end of namespace LLDB -} // end of namespace KDevMI - -#endif // LLDB_BREAKPOINTCONTROLLER_H +#endif // TEST_REFACTORING_H diff --git a/languages/clang/tests/test_refactoring.cpp b/languages/clang/tests/test_refactoring.cpp new file mode 100644 --- /dev/null +++ b/languages/clang/tests/test_refactoring.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2017 Kevin Funk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test_refactoring.h" + +#include +#include +#include +#include +#include + +#include "codegen/clangrefactoring.h" + +#include +#include +#include + +#include +#include + +QTEST_MAIN(TestRefactoring); + +using namespace KDevelop; + +TestRefactoring::~TestRefactoring() = default; + +void TestRefactoring::initTestCase() +{ + QLoggingCategory::setFilterRules(QStringLiteral("*.debug=false\ndefault.debug=true\nkdevelop.plugins.clang.debug=true\n")); + + QVERIFY(qputenv("KDEV_CLANG_DISPLAY_DIAGS", "1")); + + AutoTestShell::init({QStringLiteral("kdevclangsupport")}); + + auto core = TestCore::initialize(); + delete core->projectController(); + m_projectController = new TestProjectController(core); + core->setProjectController(m_projectController); +} + +void TestRefactoring::cleanupTestCase() +{ + TestCore::shutdown(); +} + +void TestRefactoring::cleanup() +{ +} + +void TestRefactoring::init() +{ +} + +void TestRefactoring::testClassRename() +{ + const QString codeBefore(R"( +class Foo { +public: + Foo(); + ~Foo(); +}; +Foo::Foo() { +} +Foo::~Foo() { +} + )"); + + const QString codeAfter(R"( +class FooNew { +public: + FooNew(); + ~FooNew(); +}; +FooNew::FooNew() { +} +FooNew::~FooNew() { +} + )"); + + QTemporaryDir dir; + auto project = new TestProject(Path(dir.path()), this); + m_projectController->addProject(project); + + TestFile file(codeBefore, "cpp", project, dir.path()); + QVERIFY(file.parseAndWait(TopDUContext::AllDeclarationsContextsAndUses)); + + DUChainReadLocker lock; + + auto top = file.topContext(); + QVERIFY(top); + + auto declaration = top->localDeclarations().first(); + QVERIFY(declaration); + + const QString originalName = declaration->identifier().identifier().str(); + const QString newName = QStringLiteral("FooNew"); + + QSharedPointer collector(new BasicRefactoringCollector(declaration)); + + // TODO: Do this without GUI? + UsesWidget uses(declaration, collector); + lock.unlock(); + + for (int i = 0; i < 30000; i += 1000) { + if (collector->isReady()) { + break; + } + QTest::qWait(1000); + } + QVERIFY(collector->isReady()); + + BasicRefactoring::NameAndCollector nameAndCollector{newName, collector}; + + auto languages = ICore::self()->languageController()->languagesForUrl(file.url().toUrl()); + QVERIFY(!languages.isEmpty()); + auto clangLanguageSupport = languages.first(); + QVERIFY(clangLanguageSupport); + auto clangRefactoring = qobject_cast(clangLanguageSupport->refactoring()); + QVERIFY(clangRefactoring); + + clangRefactoring->renameCollectedDeclarations(nameAndCollector.collector.data(), newName, originalName); + QCOMPARE(file.fileContents(), codeAfter); + + m_projectController->closeAllProjects(); +} + diff --git a/languages/clang/util/clangtypes.h b/languages/clang/util/clangtypes.h --- a/languages/clang/util/clangtypes.h +++ b/languages/clang/util/clangtypes.h @@ -59,7 +59,7 @@ class ClangString { public: - ClangString(CXString string); + explicit ClangString(CXString string); ~ClangString(); ClangString(const ClangString&) = delete; @@ -86,7 +86,7 @@ class ClangLocation { public: - ClangLocation(CXSourceLocation cursor); + explicit ClangLocation(CXSourceLocation cursor); ~ClangLocation(); operator KDevelop::DocumentCursor() const; @@ -106,7 +106,7 @@ class KDEVCLANGPRIVATE_EXPORT ClangRange { public: - ClangRange(CXSourceRange range); + explicit ClangRange(CXSourceRange range); ~ClangRange(); diff --git a/languages/clang/util/clangtypes.cpp b/languages/clang/util/clangtypes.cpp --- a/languages/clang/util/clangtypes.cpp +++ b/languages/clang/util/clangtypes.cpp @@ -138,12 +138,12 @@ ClangLocation ClangRange::start() const { - return {clang_getRangeStart(m_range)}; + return ClangLocation(clang_getRangeStart(m_range)); } ClangLocation ClangRange::end() const { - return {clang_getRangeEnd(m_range)}; + return ClangLocation(clang_getRangeEnd(m_range)); } CXSourceRange ClangRange::range() const @@ -222,7 +222,7 @@ { stream << "ClangTokens {"; for (uint i = 0; i < tokens.size(); ++i) { - stream << i << tokens.at(i) << clang_getTokenSpelling(tokens.unit(), tokens.at(i)) << ","; + stream << i << tokens.at(i) << ClangString(clang_getTokenSpelling(tokens.unit(), tokens.at(i))) << ","; } return stream << "}"; } diff --git a/languages/clang/util/clangutils.h b/languages/clang/util/clangutils.h --- a/languages/clang/util/clangutils.h +++ b/languages/clang/util/clangutils.h @@ -59,7 +59,7 @@ /** * Given a cursor representing a function, returns a vector containing the string * representations of the default arguments of the function which are defined at - * the occurence of the cursor. Note that this is not necessarily all of the default + * the occurrence of the cursor. Note that this is not necessarily all of the default * arguments of the function. * * @param cursor The cursor to examine diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp b/languages/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp --- a/languages/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp +++ b/languages/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp @@ -69,7 +69,7 @@ ConfigEntry configForItem(KDevelop::ProjectBaseItem* item) { if(!item){ - return {}; + return ConfigEntry(); } const Path itemPath = item->path(); diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h b/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h --- a/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h +++ b/languages/plugins/custom-definesandincludes/compilerprovider/settingsmanager.h @@ -59,7 +59,7 @@ CompilerPointer compiler; ParserArguments parserArguments; - ConfigEntry( const QString& path = QString() ); + explicit ConfigEntry( const QString& path = QString() ); // FIXME: get rid of this but stay backwards compatible void setDefines(const QHash& defines); diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.h b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.h --- a/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.h +++ b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.h @@ -41,7 +41,7 @@ CompilerDataRole = Qt::UserRole + 1 }; - CompilersModel( QObject* parent = nullptr ); + explicit CompilersModel( QObject* parent = nullptr ); void setCompilers( const QVector& compilers ); QVector compilers() const; diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.cpp b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.cpp --- a/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.cpp +++ b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.cpp @@ -30,7 +30,7 @@ class TreeItem { public: - TreeItem(const QList &data, TreeItem *parent = nullptr) + explicit TreeItem(const QList &data, TreeItem *parent = nullptr) :m_itemData(data) ,m_parentItem(parent) {} diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.ui b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.ui --- a/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.ui +++ b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.ui @@ -11,6 +11,9 @@
+ + 0 + diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/definesmodel.h b/languages/plugins/custom-definesandincludes/kcm_widget/definesmodel.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/definesmodel.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/definesmodel.h @@ -28,7 +28,7 @@ { Q_OBJECT public: - DefinesModel( QObject* parent = nullptr ); + explicit DefinesModel( QObject* parent = nullptr ); void setDefines( const KDevelop::Defines& defines ); KDevelop::Defines defines() const; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.h b/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.h @@ -41,7 +41,7 @@ { Q_OBJECT public: - DefinesWidget( QWidget* parent = nullptr ); + explicit DefinesWidget( QWidget* parent = nullptr ); void setDefines( const KDevelop::Defines& defines ); void clear(); signals: diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.ui b/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.ui --- a/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.ui +++ b/languages/plugins/custom-definesandincludes/kcm_widget/defineswidget.ui @@ -22,9 +22,6 @@ 8 - - QFrame::NoFrame - QAbstractItemView::SelectRows diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/includesmodel.h b/languages/plugins/custom-definesandincludes/kcm_widget/includesmodel.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/includesmodel.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/includesmodel.h @@ -26,7 +26,7 @@ { Q_OBJECT public: - IncludesModel( QObject* parent = nullptr ); + explicit IncludesModel( QObject* parent = nullptr ); void setIncludes( const QStringList& ); QStringList includes() const; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/includeswidget.h b/languages/plugins/custom-definesandincludes/kcm_widget/includeswidget.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/includeswidget.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/includeswidget.h @@ -42,7 +42,7 @@ { Q_OBJECT public: - IncludesWidget( QWidget* parent = nullptr ); + explicit IncludesWidget( QWidget* parent = nullptr ); void setProject(KDevelop::IProject* w_project); void setIncludes( const QStringList& ); void clear(); diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.h @@ -43,7 +43,7 @@ { Q_OBJECT public: - ParserWidget(QWidget* parent); + explicit ParserWidget(QWidget* parent); ~ParserWidget() override; void setParserArguments(const ParserArguments& arguments); diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui --- a/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui +++ b/languages/plugins/custom-definesandincludes/kcm_widget/parserwidget.ui @@ -11,6 +11,9 @@ + + 0 + diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.h b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.h @@ -42,7 +42,7 @@ CompilerDataRole = Qt::UserRole + 4, ParserArgumentsRole = Qt::UserRole + 5 }; - ProjectPathsModel( QObject* parent = nullptr ); + explicit ProjectPathsModel( QObject* parent = nullptr ); void setProject( KDevelop::IProject* w_project ); void setPaths( const QList< ConfigEntry >& paths ); void addPath( const QUrl &url ); diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.cpp b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.cpp --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.cpp +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathsmodel.cpp @@ -96,7 +96,7 @@ return false; } } - projectPaths.insert( 1, sanitizePath( value.toString(), false ) ); + projectPaths.insert( 1, ConfigEntry(sanitizePath( value.toString(), false ) )); emit dataChanged( this->index( 1, 0 ), this->index( projectPaths.count() - 1, 0 ) ); return true; } @@ -161,7 +161,7 @@ config.path = sanitizePath(rootPath ? QString() : config.path ); addPathInternal(config, rootPath); } - addPathInternal( sanitizePath( QString() ), true ); // add an empty "root" config entry if one does not exist + addPathInternal( ConfigEntry(sanitizePath( QString() )), true ); // add an empty "root" config entry if one does not exist endResetModel(); } @@ -190,7 +190,7 @@ } beginInsertRows( QModelIndex(), rowCount(), rowCount() ); - addPathInternal( sanitizeUrl(url), false ); + addPathInternal( ConfigEntry(sanitizeUrl(url)), false ); endInsertRows(); } diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h @@ -44,7 +44,7 @@ { Q_OBJECT public: - ProjectPathsWidget( QWidget* parent = nullptr ); + explicit ProjectPathsWidget( QWidget* parent = nullptr ); void setProject(KDevelop::IProject* w_project); void setPaths( const QList& ); QList paths() const; diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui @@ -11,17 +11,8 @@ - - 9 - - - 9 - - - 9 - - - 9 + + 0 @@ -59,10 +50,7 @@ - - - - + 0 @@ -176,18 +164,6 @@ Includes/Imports - - 0 - - - 0 - - - 0 - - - 0 - @@ -205,21 +181,6 @@ Defines - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - diff --git a/languages/plugins/custom-definesandincludes/noprojectincludesanddefines/noprojectcustomincludepaths.h b/languages/plugins/custom-definesandincludes/noprojectincludesanddefines/noprojectcustomincludepaths.h --- a/languages/plugins/custom-definesandincludes/noprojectincludesanddefines/noprojectcustomincludepaths.h +++ b/languages/plugins/custom-definesandincludes/noprojectincludesanddefines/noprojectcustomincludepaths.h @@ -35,7 +35,7 @@ Q_OBJECT public: - NoProjectCustomIncludePaths( QWidget* parent = nullptr ); + explicit NoProjectCustomIncludePaths( QWidget* parent = nullptr ); void setStorageDirectory( const QString& path ); QString storageDirectory() const; diff --git a/languages/qmljs/codecompletion/model.h b/languages/qmljs/codecompletion/model.h --- a/languages/qmljs/codecompletion/model.h +++ b/languages/qmljs/codecompletion/model.h @@ -32,7 +32,7 @@ class KDEVQMLJSCOMPLETION_EXPORT CodeCompletionModel : public KDevelop::CodeCompletionModel { public: - CodeCompletionModel(QObject* parent); + explicit CodeCompletionModel(QObject* parent); protected: KDevelop::CodeCompletionWorker* createCompletionWorker() override; }; diff --git a/languages/qmljs/codecompletion/worker.h b/languages/qmljs/codecompletion/worker.h --- a/languages/qmljs/codecompletion/worker.h +++ b/languages/qmljs/codecompletion/worker.h @@ -31,7 +31,7 @@ class CodeCompletionWorker : public KDevelop::CodeCompletionWorker { public: - CodeCompletionWorker(KDevelop::CodeCompletionModel* model); + explicit CodeCompletionWorker(KDevelop::CodeCompletionModel* model); protected: virtual KDevelop::CodeCompletionContext* createCompletionContext( diff --git a/languages/qmljs/duchain/contextbuilder.h b/languages/qmljs/duchain/contextbuilder.h --- a/languages/qmljs/duchain/contextbuilder.h +++ b/languages/qmljs/duchain/contextbuilder.h @@ -37,7 +37,7 @@ class Editor { public: - Editor(ParseSession** session) + explicit Editor(ParseSession** session) : m_session(session) {} diff --git a/languages/qmljs/duchain/debugvisitor.h b/languages/qmljs/duchain/debugvisitor.h --- a/languages/qmljs/duchain/debugvisitor.h +++ b/languages/qmljs/duchain/debugvisitor.h @@ -30,7 +30,7 @@ class KDEVQMLJSDUCHAIN_EXPORT DebugVisitor : public QmlJS::AST::Visitor { public: - DebugVisitor(const ParseSession* session); + explicit DebugVisitor(const ParseSession* session); void startVisiting(QmlJS::AST::Node* node); diff --git a/languages/qmljs/duchain/declarationbuilder.h b/languages/qmljs/duchain/declarationbuilder.h --- a/languages/qmljs/duchain/declarationbuilder.h +++ b/languages/qmljs/duchain/declarationbuilder.h @@ -45,7 +45,7 @@ friend class QmlJS::NodeJS; public: - DeclarationBuilder(ParseSession* session); + explicit DeclarationBuilder(ParseSession* session); virtual KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url, QmlJS::AST::Node* node, diff --git a/languages/qmljs/duchain/declarationbuilder.cpp b/languages/qmljs/duchain/declarationbuilder.cpp --- a/languages/qmljs/duchain/declarationbuilder.cpp +++ b/languages/qmljs/duchain/declarationbuilder.cpp @@ -139,7 +139,7 @@ } openType(func); - // Parameters, if any (a function must always have an interal function context, + // Parameters, if any (a function must always have an internal function context, // so always open a context here even if there are no parameters) DUContext* parametersContext = openContext( node + 1, // Don't call setContextOnNode on node, only the body context can be associated with node diff --git a/languages/qmljs/duchain/functiondeclaration.h b/languages/qmljs/duchain/functiondeclaration.h --- a/languages/qmljs/duchain/functiondeclaration.h +++ b/languages/qmljs/duchain/functiondeclaration.h @@ -58,7 +58,7 @@ public: FunctionDeclaration(const FunctionDeclaration &rhs); FunctionDeclaration(const KDevelop::RangeInRevision &range, KDevelop::DUContext *context); - FunctionDeclaration(FunctionDeclarationData &data); + explicit FunctionDeclaration(FunctionDeclarationData &data); ~FunctionDeclaration(); /** diff --git a/languages/qmljs/duchain/functiontype.h b/languages/qmljs/duchain/functiontype.h --- a/languages/qmljs/duchain/functiontype.h +++ b/languages/qmljs/duchain/functiontype.h @@ -44,7 +44,7 @@ FunctionType(); FunctionType(const FunctionType& rhs); - FunctionType(Data& data); + explicit FunctionType(Data& data); virtual ~FunctionType(); KDevelop::AbstractType* clone() const override; diff --git a/languages/qmljs/duchain/qmljsducontext.h b/languages/qmljs/duchain/qmljsducontext.h --- a/languages/qmljs/duchain/qmljsducontext.h +++ b/languages/qmljs/duchain/qmljsducontext.h @@ -42,7 +42,7 @@ { public: template - QmlJSDUContext(Data& data) : BaseContext(data) { + explicit QmlJSDUContext(Data& data) : BaseContext(data) { } ///Parameters will be reached to the base-class diff --git a/languages/qmljs/duchain/usebuilder.h b/languages/qmljs/duchain/usebuilder.h --- a/languages/qmljs/duchain/usebuilder.h +++ b/languages/qmljs/duchain/usebuilder.h @@ -29,7 +29,7 @@ class KDEVQMLJSDUCHAIN_EXPORT UseBuilder : public UseBuilderBase { public: - UseBuilder(ParseSession* session); + explicit UseBuilder(ParseSession* session); protected: using Visitor::visit; diff --git a/languages/qmljs/libs/CMakeLists.txt b/languages/qmljs/libs/CMakeLists.txt --- a/languages/qmljs/libs/CMakeLists.txt +++ b/languages/qmljs/libs/CMakeLists.txt @@ -1,3 +1,5 @@ +string(REPLACE "-Wdocumentation" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + qt5_wrap_ui(uifiles_SRCS utils/projectintropage.ui utils/filewizardpage.ui diff --git a/languages/qmljs/libs/qmljs/qmljsimportdependencies.h b/languages/qmljs/libs/qmljs/qmljsimportdependencies.h --- a/languages/qmljs/libs/qmljs/qmljsimportdependencies.h +++ b/languages/qmljs/libs/qmljs/qmljsimportdependencies.h @@ -56,7 +56,7 @@ namespace Internal { class ImportDependenciesPrivate; } class ImportDependencies; -// match strenght wrt to the selectors of a ViewerContext +// match strength wrt to the selectors of a ViewerContext // this is valid only within a ViewerContext class QMLJS_EXPORT ImportMatchStrength { diff --git a/languages/qmljs/libs/qmljs/qmljstypedescriptionreader.cpp b/languages/qmljs/libs/qmljs/qmljstypedescriptionreader.cpp --- a/languages/qmljs/libs/qmljs/qmljstypedescriptionreader.cpp +++ b/languages/qmljs/libs/qmljs/qmljstypedescriptionreader.cpp @@ -47,7 +47,10 @@ using namespace LanguageUtils; TypeDescriptionReader::TypeDescriptionReader(const QString &fileName, const QString &data) - : _fileName (fileName), _source(data), _objects(0) + : _fileName (fileName) + , _source(data) + , _objects(0) + , _moduleApis(nullptr) { } diff --git a/languages/qmljs/libs/utils/fileutils.cpp b/languages/qmljs/libs/utils/fileutils.cpp --- a/languages/qmljs/libs/utils/fileutils.cpp +++ b/languages/qmljs/libs/utils/fileutils.cpp @@ -382,13 +382,13 @@ FileSaverBase::FileSaverBase() - : m_hasError(false) + : m_file(nullptr) + , m_hasError(false) { } FileSaverBase::~FileSaverBase() { - delete m_file; } bool FileSaverBase::finalize() diff --git a/languages/qmljs/navigation/propertypreviewwidget.h b/languages/qmljs/navigation/propertypreviewwidget.h --- a/languages/qmljs/navigation/propertypreviewwidget.h +++ b/languages/qmljs/navigation/propertypreviewwidget.h @@ -30,7 +30,7 @@ // Describes one supported property, such as "width" struct SupportedProperty { - SupportedProperty(const QUrl& qmlfile, + explicit SupportedProperty(const QUrl& qmlfile, const QString &typeContains = QString(), const QString &classContains = QString()) : qmlfile(qmlfile), diff --git a/languages/qmljs/qmljshighlighting.h b/languages/qmljs/qmljshighlighting.h --- a/languages/qmljs/qmljshighlighting.h +++ b/languages/qmljs/qmljshighlighting.h @@ -26,7 +26,7 @@ Q_OBJECT public: - QmlJsHighlighting(QObject* parent); + explicit QmlJsHighlighting(QObject* parent); KDevelop::CodeHighlightingInstance* createInstance() const override; }; diff --git a/languages/qmljs/qmljshighlighting.cpp b/languages/qmljs/qmljshighlighting.cpp --- a/languages/qmljs/qmljshighlighting.cpp +++ b/languages/qmljs/qmljshighlighting.cpp @@ -25,7 +25,7 @@ class HighlightingInstance : public KDevelop::CodeHighlightingInstance { public: - HighlightingInstance(const CodeHighlighting* highlighting) + explicit HighlightingInstance(const CodeHighlighting* highlighting) : CodeHighlightingInstance(highlighting) {} diff --git a/projectbuilders/cmakebuilder/cmakebuilder.cpp b/projectbuilders/cmakebuilder/cmakebuilder.cpp --- a/projectbuilders/cmakebuilder/cmakebuilder.cpp +++ b/projectbuilders/cmakebuilder/cmakebuilder.cpp @@ -272,7 +272,7 @@ generatorNames << "Ninja"; #ifdef Q_OS_WIN - // Visual Studio solution is the standard generator under windows, but we dont want to use + // Visual Studio solution is the standard generator under windows, but we don't want to use // the VS IDE, so we need nmake makefiles generatorNames << "NMake Makefiles"; #endif diff --git a/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp b/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp --- a/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp +++ b/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp @@ -20,8 +20,6 @@ #include "cmakebuilderpreferences.h" -#include - #include #include @@ -33,11 +31,8 @@ CMakeBuilderPreferences::CMakeBuilderPreferences(KDevelop::IPlugin* plugin, QWidget* parent) : KDevelop::ConfigPage(plugin, CMakeBuilderSettings::self(), parent) { - QVBoxLayout* l = new QVBoxLayout( this ); - QWidget* w = new QWidget; m_prefsUi = new Ui::CMakeBuilderPreferences; - m_prefsUi->setupUi( w ); - l->addWidget( w ); + m_prefsUi->setupUi(this); #ifdef Q_OS_WIN m_prefsUi->kcfg_cmakeExe->setFilter("*.exe"); diff --git a/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui b/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui --- a/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui +++ b/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui @@ -11,6 +11,9 @@ + + 0 + diff --git a/projectbuilders/cmakebuilder/cmakejob.h b/projectbuilders/cmakebuilder/cmakejob.h --- a/projectbuilders/cmakebuilder/cmakejob.h +++ b/projectbuilders/cmakebuilder/cmakejob.h @@ -45,7 +45,7 @@ FailedError }; - CMakeJob(QObject* parent = nullptr); + explicit CMakeJob(QObject* parent = nullptr); void setProject(KDevelop::IProject* project); diff --git a/projectbuilders/cmakebuilder/prunejob.h b/projectbuilders/cmakebuilder/prunejob.h --- a/projectbuilders/cmakebuilder/prunejob.h +++ b/projectbuilders/cmakebuilder/prunejob.h @@ -28,7 +28,7 @@ { Q_OBJECT public: - PruneJob(KDevelop::IProject* project); + explicit PruneJob(KDevelop::IProject* project); void start() override; bool doKill() override; diff --git a/projectbuilders/makebuilder/makebuilderpreferences.cpp b/projectbuilders/makebuilder/makebuilderpreferences.cpp --- a/projectbuilders/makebuilder/makebuilderpreferences.cpp +++ b/projectbuilders/makebuilder/makebuilderpreferences.cpp @@ -20,8 +20,6 @@ #include "makebuilderpreferences.h" -#include - #include #include "ui_makeconfig.h" @@ -32,19 +30,14 @@ MakeBuilderPreferences::MakeBuilderPreferences(IPlugin* plugin, const ProjectConfigOptions& options, QWidget* parent) : ProjectConfigPage(plugin, options, parent) { - QVBoxLayout* l = new QVBoxLayout( this ); - QWidget* w = new QWidget; m_prefsUi = new Ui::MakeConfig; - m_prefsUi->setupUi( w ); + m_prefsUi->setupUi(this); connect(m_prefsUi->makeBinary, &KUrlRequester::textChanged, this, &MakeBuilderPreferences::changed); connect(m_prefsUi->makeBinary, &KUrlRequester::urlSelected, this, &MakeBuilderPreferences::changed); connect(m_prefsUi->configureEnvironment, &EnvironmentConfigureButton::environmentConfigured, this, &MakeBuilderPreferences::changed); - connect(m_prefsUi->kcfg_environmentProfile, &EnvironmentSelectionWidget::currentProfileChanged, - this, &MakeBuilderPreferences::changed); - l->addWidget( w ); m_prefsUi->configureEnvironment->setSelectionWidget( m_prefsUi->kcfg_environmentProfile ); } diff --git a/projectbuilders/makebuilder/makeconfig.ui b/projectbuilders/makebuilder/makeconfig.ui --- a/projectbuilders/makebuilder/makeconfig.ui +++ b/projectbuilders/makebuilder/makeconfig.ui @@ -11,6 +11,9 @@ + + 0 + QFormLayout::AllNonFixedFieldsGrow diff --git a/projectbuilders/ninjabuilder/kdevninjabuilderplugin.h b/projectbuilders/ninjabuilder/kdevninjabuilderplugin.h --- a/projectbuilders/ninjabuilder/kdevninjabuilderplugin.h +++ b/projectbuilders/ninjabuilder/kdevninjabuilderplugin.h @@ -32,7 +32,7 @@ Q_OBJECT Q_INTERFACES( KDevelop::IProjectBuilder ) public: - KDevNinjaBuilderPlugin(QObject* parent = nullptr, const QVariantList& args = QVariantList()); + explicit KDevNinjaBuilderPlugin(QObject* parent = nullptr, const QVariantList& args = QVariantList()); KJob* build(KDevelop::ProjectBaseItem* item) override; KJob* clean(KDevelop::ProjectBaseItem* item) override; diff --git a/projectbuilders/ninjabuilder/ninjabuilderpreferences.cpp b/projectbuilders/ninjabuilder/ninjabuilderpreferences.cpp --- a/projectbuilders/ninjabuilder/ninjabuilderpreferences.cpp +++ b/projectbuilders/ninjabuilder/ninjabuilderpreferences.cpp @@ -20,8 +20,6 @@ #include "ninjabuilderpreferences.h" -#include - #include #include #include @@ -37,16 +35,11 @@ QWidget* parent) : ProjectConfigPage(plugin, options, parent) { - QVBoxLayout* l = new QVBoxLayout( this ); - QWidget* w = new QWidget; m_prefsUi = new Ui::NinjaConfig; - m_prefsUi->setupUi( w ); - l->addWidget( w ); + m_prefsUi->setupUi(this); connect(m_prefsUi->configureEnvironment, &EnvironmentConfigureButton::environmentConfigured, this, &NinjaBuilderPreferences::changed); - connect(m_prefsUi->kcfg_environmentProfile, &EnvironmentSelectionWidget::currentProfileChanged, - this, &NinjaBuilderPreferences::changed); m_prefsUi->configureEnvironment->setSelectionWidget( m_prefsUi->kcfg_environmentProfile ); } diff --git a/projectbuilders/qmakebuilder/qmakebuilderpreferences.cpp b/projectbuilders/qmakebuilder/qmakebuilderpreferences.cpp --- a/projectbuilders/qmakebuilder/qmakebuilderpreferences.cpp +++ b/projectbuilders/qmakebuilder/qmakebuilderpreferences.cpp @@ -22,7 +22,6 @@ #include "qmakebuilderpreferences.h" #include -#include #include #include @@ -46,11 +45,8 @@ : KDevelop::ConfigPage(plugin, nullptr, parent) , m_project(options.project) { - auto l = new QVBoxLayout(this); - auto w = new QWidget; - m_prefsUi = new Ui::QMakeConfig; - m_prefsUi->setupUi(w); + m_prefsUi->setupUi(this); // display icons instead of text m_prefsUi->addButton->setIcon(QIcon::fromTheme("list-add")); @@ -63,7 +59,6 @@ groupBoxLayout->addWidget(m_chooserUi); m_chooserUi->kcfg_buildDir->setEnabled(false); // build directory MUST NOT be changed here - l->addWidget(w); connect(m_chooserUi, &QMakeBuildDirChooser::changed, this, &QMakeBuilderPreferences::changed); connect(m_chooserUi, &QMakeBuildDirChooser::changed, this, &QMakeBuilderPreferences::validate); @@ -123,7 +118,7 @@ } else { // invalid data: message box KMessageBox::error(nullptr, errormsg, "Data is invalid!"); - // FIXME dialog behaves like if save really happend (dialog closes if user click ok) even if changed signal is + // FIXME dialog behaves like if save really happened (dialog closes if user click ok) even if changed signal is // emitted } } diff --git a/projectbuilders/qmakebuilder/qmakejob.h b/projectbuilders/qmakebuilder/qmakejob.h --- a/projectbuilders/qmakebuilder/qmakejob.h +++ b/projectbuilders/qmakebuilder/qmakejob.h @@ -41,7 +41,7 @@ Q_OBJECT public: - QMakeJob(QObject *parent = nullptr); + explicit QMakeJob(QObject *parent = nullptr); enum ErrorTypes { NoProjectError = UserDefinedError, @@ -63,9 +63,9 @@ void slotCompleted(int); private: - KDevelop::IProject* m_project; - KDevelop::CommandExecutor* m_cmd; - bool m_killed; + KDevelop::IProject* m_project = nullptr; + KDevelop::CommandExecutor* m_cmd = nullptr; + bool m_killed = false; }; #endif // QMAKEJOB_H diff --git a/projectbuilders/qmakebuilder/qmakejob.cpp b/projectbuilders/qmakebuilder/qmakejob.cpp --- a/projectbuilders/qmakebuilder/qmakejob.cpp +++ b/projectbuilders/qmakebuilder/qmakejob.cpp @@ -39,7 +39,6 @@ QMakeJob::QMakeJob(QObject* parent) : OutputExecuteJob(parent) - , m_killed(false) { setCapabilities(Killable); setFilteringStrategy(OutputModel::CompilerFilter); diff --git a/projectmanagers/cmake/CMakeLists.txt b/projectmanagers/cmake/CMakeLists.txt --- a/projectmanagers/cmake/CMakeLists.txt +++ b/projectmanagers/cmake/CMakeLists.txt @@ -29,6 +29,7 @@ cmakeutils.cpp cmakeextraargumentshistory.cpp cmakebuilddirchooser.cpp + cmakeserver.cpp debug.cpp ) @@ -44,8 +45,10 @@ testing/ctestsuite.cpp testing/qttestdelegate.cpp cmakeimportjsonjob.cpp + cmakeserverimportjob.cpp cmakenavigationwidget.cpp cmakemanager.cpp + cmakeprojectdata.cpp cmakemodelitems.cpp duchain/cmakeparsejob.cpp duchain/usebuilder.cpp diff --git a/projectmanagers/cmake/cmakecodecompletionmodel.h b/projectmanagers/cmake/cmakecodecompletionmodel.h --- a/projectmanagers/cmake/cmakecodecompletionmodel.h +++ b/projectmanagers/cmake/cmakecodecompletionmodel.h @@ -32,7 +32,7 @@ class CMakeCodeCompletionModel : public KTextEditor::CodeCompletionModel { public: - CMakeCodeCompletionModel(QObject *parent); + explicit CMakeCodeCompletionModel(QObject *parent); void completionInvoked(KTextEditor::View* view, const KTextEditor::Range& range, InvocationType invocationType) override; QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const override; diff --git a/projectmanagers/cmake/cmakeextraargumentshistory.h b/projectmanagers/cmake/cmakeextraargumentshistory.h --- a/projectmanagers/cmake/cmakeextraargumentshistory.h +++ b/projectmanagers/cmake/cmakeextraargumentshistory.h @@ -39,7 +39,7 @@ class KDEVCMAKECOMMON_EXPORT CMakeExtraArgumentsHistory { public: - CMakeExtraArgumentsHistory(KComboBox* widget); + explicit CMakeExtraArgumentsHistory(KComboBox* widget); ~CMakeExtraArgumentsHistory(); QStringList list() const; diff --git a/projectmanagers/cmake/cmakehelpdocumentation.h b/projectmanagers/cmake/cmakehelpdocumentation.h --- a/projectmanagers/cmake/cmakehelpdocumentation.h +++ b/projectmanagers/cmake/cmakehelpdocumentation.h @@ -28,7 +28,7 @@ { Q_OBJECT public: - CMakeContentsModel(QObject* parent) ; + explicit CMakeContentsModel(QObject* parent) ; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex&) const override { return 1; } diff --git a/projectmanagers/cmake/cmakeimportjob.h b/projectmanagers/cmake/cmakeimportjob.h --- a/projectmanagers/cmake/cmakeimportjob.h +++ b/projectmanagers/cmake/cmakeimportjob.h @@ -36,19 +36,19 @@ class ReferencedTopDUContext; } -class CMakeImportJob : public KJob +class CMakeImportJsonJob : public KJob { Q_OBJECT public: - CMakeImportJob(KDevelop::ProjectFolderItem* dom, CMakeManager* parent); + CMakeImportJsonJob(KDevelop::ProjectFolderItem* dom, CMakeManager* parent); virtual void start(); KDevelop::IProject* project() const; CMakeProjectData projectData() const; private slots: void waitFinished(KJob* job); - void importFinished(); + void importCompileCommandsJsonFinished(); private: void initialize(); diff --git a/projectmanagers/cmake/cmakeimportjob.cpp b/projectmanagers/cmake/cmakeimportjob.cpp --- a/projectmanagers/cmake/cmakeimportjob.cpp +++ b/projectmanagers/cmake/cmakeimportjob.cpp @@ -78,7 +78,7 @@ bool m_started; }; -CMakeImportJob::CMakeImportJob(ProjectFolderItem* dom, CMakeManager* parent) +CMakeImportJsonJob::CMakeImportJsonJob(ProjectFolderItem* dom, CMakeManager* parent) : KJob(parent) , m_project(dom->project()) , m_dom(dom) @@ -89,13 +89,13 @@ connect(m_futureWatcher, SIGNAL(finished()), SLOT(importFinished())); } -void CMakeImportJob::start() +void CMakeImportJsonJob::start() { QFuture future = QtConcurrent::run(this, &CMakeImportJob::initialize); m_futureWatcher->setFuture(future); } -void CMakeImportJob::importFinished() +void CMakeImportJsonJob::importCompileCommandsJsonFinished() { Q_ASSERT(m_project->thread() == QThread::currentThread()); @@ -107,7 +107,7 @@ wjob->start(); } -void CMakeImportJob::initialize() +void CMakeImportJsonJob::initialize() { ReferencedTopDUContext ctx; ProjectBaseItem* parent = m_dom->parent(); @@ -122,7 +122,7 @@ importDirectory(m_project, m_dom->path(), ctx); } -KDevelop::ReferencedTopDUContext CMakeImportJob::initializeProject(CMakeFolderItem* rootFolder) +KDevelop::ReferencedTopDUContext CMakeImportJsonJob::initializeProject(CMakeFolderItem* rootFolder) { Path base(CMake::projectRoot(m_project)); @@ -193,20 +193,20 @@ return ref; } -void CMakeImportJob::waitFinished(KJob*) +void CMakeImportJsonJob::waitFinished(KJob*) { emitResult(); } -KDevelop::ReferencedTopDUContext CMakeImportJob::includeScript(const QString& file, const QString& dir, ReferencedTopDUContext parent) +KDevelop::ReferencedTopDUContext CMakeImportJsonJob::includeScript(const QString& file, const QString& dir, ReferencedTopDUContext parent) { m_manager->addWatcher(m_project, file); QString profile = CMake::currentEnvironment(m_project); const KDevelop::EnvironmentGroupList env( KSharedConfig::openConfig() ); return CMakeParserUtils::includeScript( file, parent, &m_data, dir, env.variables(profile)); } -CMakeCommitChangesJob* CMakeImportJob::importDirectory(IProject* project, const Path& path, const KDevelop::ReferencedTopDUContext& parentTop) +CMakeCommitChangesJob* CMakeImportJsonJob::importDirectory(IProject* project, const Path& path, const KDevelop::ReferencedTopDUContext& parentTop) { Q_ASSERT(thread() == m_project->thread()); Path cmakeListsPath(path, "CMakeLists.txt"); @@ -241,13 +241,13 @@ return commitJob; } -IProject* CMakeImportJob::project() const +IProject* CMakeImportJsonJob::project() const { Q_ASSERT(!m_futureWatcher->isRunning()); return m_project; } -CMakeProjectData CMakeImportJob::projectData() const +CMakeProjectData CMakeImportJsonJob::projectData() const { Q_ASSERT(!m_futureWatcher->isRunning()); return m_data; diff --git a/projectmanagers/cmake/cmakeimportjsonjob.h b/projectmanagers/cmake/cmakeimportjsonjob.h --- a/projectmanagers/cmake/cmakeimportjsonjob.h +++ b/projectmanagers/cmake/cmakeimportjsonjob.h @@ -31,7 +31,7 @@ class CMakeFolderItem; struct ImportData { - CMakeJsonData json; + CMakeFilesCompilationData compilationData; QHash targets; QVector testSuites; }; @@ -42,7 +42,7 @@ class ReferencedTopDUContext; } -class CMakeImportJob : public KJob +class CMakeImportJsonJob : public KJob { Q_OBJECT @@ -52,32 +52,23 @@ ReadError ///< Failed to read the JSON file }; - CMakeImportJob(KDevelop::IProject* project, QObject* parent); - ~CMakeImportJob() override; + CMakeImportJsonJob(KDevelop::IProject* project, QObject* parent); + ~CMakeImportJsonJob() override; void start() override; KDevelop::IProject* project() const; - /** - * Return the parsed JSON data - * - * @note Only call after the job has finished! - */ - CMakeJsonData jsonData() const; - QHash targets() const { return m_targets; } - QVector testSuites() const { return m_testSuites; } + CMakeProjectData projectData() const; private Q_SLOTS: - void importFinished(); + void importCompileCommandsJsonFinished(); private: KDevelop::IProject* m_project; QFutureWatcher m_futureWatcher; - CMakeJsonData m_data; - QHash m_targets; - QVector m_testSuites; + CMakeProjectData m_data; }; #endif // CMAKEIMPORTJSONJOB_H diff --git a/projectmanagers/cmake/cmakeimportjsonjob.cpp b/projectmanagers/cmake/cmakeimportjsonjob.cpp --- a/projectmanagers/cmake/cmakeimportjsonjob.cpp +++ b/projectmanagers/cmake/cmakeimportjsonjob.cpp @@ -42,7 +42,7 @@ namespace { -CMakeJsonData importCommands(const Path& commandsFile) +CMakeFilesCompilationData importCommands(const Path& commandsFile) { // NOTE: to get compile_commands.json, you need -DCMAKE_EXPORT_COMPILE_COMMANDS=ON QFile f(commandsFile.toLocalFile()); @@ -54,7 +54,7 @@ qCDebug(CMAKE) << "Found commands file" << commandsFile; - CMakeJsonData data; + CMakeFilesCompilationData data; QJsonParseError error; const QJsonDocument document = QJsonDocument::fromJson(f.readAll(), &error); if (error.error) { @@ -141,18 +141,18 @@ } -CMakeImportJob::CMakeImportJob(IProject* project, QObject* parent) +CMakeImportJsonJob::CMakeImportJsonJob(IProject* project, QObject* parent) : KJob(parent) , m_project(project) + , m_data({}) { - connect(&m_futureWatcher, &QFutureWatcher::finished, this, &CMakeImportJob::importFinished); + connect(&m_futureWatcher, &QFutureWatcher::finished, this, &CMakeImportJsonJob::importCompileCommandsJsonFinished); } -CMakeImportJob::~CMakeImportJob() -{ -} +CMakeImportJsonJob::~CMakeImportJsonJob() +{} -void CMakeImportJob::start() +void CMakeImportJsonJob::start() { auto commandsFile = CMake::commandsFile(project()); if (!QFileInfo::exists(commandsFile.toLocalFile())) { @@ -171,33 +171,31 @@ m_futureWatcher.setFuture(future); } -void CMakeImportJob::importFinished() +void CMakeImportJsonJob::importCompileCommandsJsonFinished() { Q_ASSERT(m_project->thread() == QThread::currentThread()); Q_ASSERT(m_futureWatcher.isFinished()); auto future = m_futureWatcher.future(); auto data = future.result(); - if (!data.json.isValid) { + if (!data.compilationData.isValid) { qCWarning(CMAKE) << "Could not import CMake project ('compile_commands.json' invalid)"; emitResult(); return; } - m_data = data.json; - m_targets = data.targets; - m_testSuites = data.testSuites; - qCDebug(CMAKE) << "Done importing, found" << m_data.files.count() << "entries for" << project()->path(); + m_data = CMakeProjectData {data.targets, data.compilationData, data.testSuites}; + qCDebug(CMAKE) << "Done importing, found" << data.compilationData.files.count() << "entries for" << project()->path(); emitResult(); } -IProject* CMakeImportJob::project() const +IProject* CMakeImportJsonJob::project() const { return m_project; } -CMakeJsonData CMakeImportJob::jsonData() const +CMakeProjectData CMakeImportJsonJob::projectData() const { Q_ASSERT(!m_futureWatcher.isRunning()); return m_data; diff --git a/projectmanagers/cmake/cmakemanager.h b/projectmanagers/cmake/cmakemanager.h --- a/projectmanagers/cmake/cmakemanager.h +++ b/projectmanagers/cmake/cmakemanager.h @@ -151,7 +151,8 @@ // // void directoryChanged(const QString& dir); // void filesystemBuffererTimeout(); - void importFinished(KJob* job); + + void integrateData(const CMakeProjectData &data, KDevelop::IProject* project); private: CMakeFile fileInformation(KDevelop::ProjectBaseItem* item) const; diff --git a/projectmanagers/cmake/cmakemanager.cpp b/projectmanagers/cmake/cmakemanager.cpp --- a/projectmanagers/cmake/cmakemanager.cpp +++ b/projectmanagers/cmake/cmakemanager.cpp @@ -33,6 +33,8 @@ #include "icmakedocumentation.h" #include "cmakemodelitems.h" #include "testing/ctestutils.h" +#include "cmakeserverimportjob.h" +#include "cmakeserver.h" #include #include @@ -112,7 +114,7 @@ bool CMakeManager::hasBuildInfo(ProjectBaseItem* item) const { - return m_projects[item->project()].jsonData.files.contains(item->path()); + return m_projects[item->project()].compilationData.files.contains(item->path()); } Path CMakeManager::buildDirectory(KDevelop::ProjectBaseItem *item) const @@ -138,23 +140,66 @@ return AbstractFileManagerPlugin::import(project); } +static bool serverSupported() +{ + static int supported = 2; + if (supported == 2) { + QProcess p; + p.start(CMake::findExecutable(), {"--version"}); + p.waitForReadyRead(); + const QByteArray line = p.readLine(); + + QRegularExpression rx("cmake version (\\d+)\\.(\\d+)\\.(\\d+)"); + auto match = rx.match(line); + if (match.isValid()) { + match.capturedTexts(); + } + } + return supported == 1; +} + KJob* CMakeManager::createImportJob(ProjectFolderItem* item) { auto project = item->project(); QList jobs; - // create the JSON file if it doesn't exist - auto commandsFile = CMake::commandsFile(project); - if (!QFileInfo::exists(commandsFile.toLocalFile())) { - qCDebug(CMAKE) << "couldn't find commands file:" << commandsFile << "- now trying to reconfigure"; - jobs << builder()->configure(project); - } + CMakeServer* server = new CMakeServer(this); + server->waitForConnected(); + + if (server->isServerAvailable()) { + auto job = new CMakeServerImportJob(project, server, this); + connect(job, &CMakeServerImportJob::result, this, [this, job](){ + if (job->error() != 0) { + qCWarning(CMAKE) << "couldn't load server successfully" << job->project()->name(); + m_projects.remove(job->project()); + } else { + integrateData(job->projectData(), job->project()); + } + }); + jobs << job; + } else { + delete server; + // parse the JSON file + CMakeImportJsonJob* job = new CMakeImportJsonJob(project, this); + + // create the JSON file if it doesn't exist + auto commandsFile = CMake::commandsFile(project); + if (!QFileInfo::exists(commandsFile.toLocalFile())) { + qCDebug(CMAKE) << "couldn't find commands file:" << commandsFile << "- now trying to reconfigure"; + jobs << builder()->configure(project); + } - // parse the JSON file - CMakeImportJob* job = new CMakeImportJob(project, this); - connect(job, &CMakeImportJob::result, this, &CMakeManager::importFinished); - jobs << job; + connect(job, &CMakeImportJsonJob::result, this, [this, job](){ + if (job->error() != 0) { + qCWarning(CMAKE) << "couldn't load json successfully" << job->project()->name(); + m_projects.remove(job->project()); + } else { + integrateData(job->projectData(), job->project()); + } + }); + jobs << job; + } // generate the file system listing jobs << KDevelop::AbstractFileManagerPlugin::createImportJob(item); @@ -183,7 +228,7 @@ CMakeFile CMakeManager::fileInformation(KDevelop::ProjectBaseItem* item) const { - const CMakeJsonData & data = m_projects[item->project()].jsonData; + const auto & data = m_projects[item->project()].compilationData; QHash::const_iterator it = data.files.constFind(item->path()); if (it == data.files.constEnd()) { @@ -286,31 +331,14 @@ } } -void CMakeManager::importFinished(KJob* j) +void CMakeManager::integrateData(const CMakeProjectData &data, KDevelop::IProject* project) { - CMakeImportJob* job = qobject_cast(j); - Q_ASSERT(job); - - auto project = job->project(); - if (job->error() != 0) { - qCDebug(CMAKE) << "Import failed for project" << project->name() << job->errorText(); - m_projects.remove(project); - } - - qCDebug(CMAKE) << "Successfully imported project" << project->name(); - - CMakeProjectData data; - data.watcher->addPath(CMake::commandsFile(project).toLocalFile()); - data.watcher->addPath(CMake::targetDirectoriesFile(project).toLocalFile()); - data.jsonData = job->jsonData(); - data.targets = job->targets(); connect(data.watcher.data(), &QFileSystemWatcher::fileChanged, this, &CMakeManager::dirtyFile); connect(data.watcher.data(), &QFileSystemWatcher::directoryChanged, this, &CMakeManager::dirtyFile); - m_projects[job->project()] = data; - - populateTargets(job->project()->projectItem(), job->targets()); + m_projects[project] = data; - CTestUtils::createTestSuites(job->testSuites(), project); + populateTargets(project->projectItem(), data.targets); + CTestUtils::createTestSuites(data.m_testSuites, project); } // void CMakeManager::deletedWatchedDirectory(IProject* p, const QUrl &dir) diff --git a/projectmanagers/cmake/cmakeprojectdata.h b/projectmanagers/cmake/cmakeprojectdata.h --- a/projectmanagers/cmake/cmakeprojectdata.h +++ b/projectmanagers/cmake/cmakeprojectdata.h @@ -1,6 +1,6 @@ /* KDevelop CMake Support * - * Copyright 2013 Aleix Pol + * Copyright 2013-2017 Aleix Pol * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,12 +21,17 @@ #ifndef CMAKEPROJECTDATA_H #define CMAKEPROJECTDATA_H +#include #include #include +#include +#include #include #include "cmaketypes.h" #include +class CMakeServer; + /** * Represents any file in a cmake project that has been added * to the project. @@ -45,22 +50,25 @@ return debug.maybeSpace(); } -struct CMakeJsonData +struct CMakeFilesCompilationData { QHash files; bool isValid = false; }; struct CMakeProjectData { + CMakeProjectData(const QHash &targets, const CMakeFilesCompilationData &data, const QVector &tests); + CMakeProjectData() : watcher(new QFileSystemWatcher) {} ~CMakeProjectData() {} - CMakeProperties properties; - CacheValues cache; - CMakeJsonData jsonData; + CMakeFilesCompilationData compilationData; QHash targets; QSharedPointer watcher; + QSharedPointer m_server; + + QVector m_testSuites; }; #endif diff --git a/projectmanagers/cmake/duchain/usebuilder.h b/projectmanagers/cmake/cmakeprojectdata.cpp copy from projectmanagers/cmake/duchain/usebuilder.h copy to projectmanagers/cmake/cmakeprojectdata.cpp --- a/projectmanagers/cmake/duchain/usebuilder.h +++ b/projectmanagers/cmake/cmakeprojectdata.cpp @@ -1,6 +1,6 @@ /* KDevelop CMake Support * - * Copyright 2014 Aleix Pol + * Copyright 2017 Aleix Pol * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,24 +18,17 @@ * 02110-1301, USA. */ -#ifndef USEBUILDER_H -#define USEBUILDER_H - -#include - -#include "contextbuilder.h" - -class UseBuilder +#include "cmakeprojectdata.h" +#include "cmakeutils.h" +#include +#include +#include +#include + +CMakeProjectData::CMakeProjectData(const QHash& targets, const CMakeFilesCompilationData& data, const QVector& tests) + : compilationData(data) + , targets(targets) + , watcher(new QFileSystemWatcher) + , m_testSuites(tests) { -public: - UseBuilder(const KDevelop::ReferencedTopDUContext& ctx); - - void startVisiting(CMakeContentIterator* node); - -private: - void newUse(const KDevelop::RangeInRevision& sr, KDevelop::DeclarationPointer d); - - KDevelop::ReferencedTopDUContext m_ctx; -}; - -#endif // USEBUILDER_H +} diff --git a/projectmanagers/cmake/cmakeserver.h b/projectmanagers/cmake/cmakeserver.h new file mode 100644 --- /dev/null +++ b/projectmanagers/cmake/cmakeserver.h @@ -0,0 +1,59 @@ +/* KDevelop CMake Support + * + * Copyright 2017 Aleix Pol + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef CMAKESERVER_H +#define CMAKESERVER_H + +#include +#include +#include +#include "cmakecommonexport.h" + +class KDEVCMAKECOMMON_EXPORT CMakeServer : public QObject +{ +Q_OBJECT +public: + CMakeServer(QObject* parent); + ~CMakeServer() override; + + void waitForConnected(); + bool isServerAvailable(); + void sendCommand(const QJsonObject& object); + + void handshake(const KDevelop::Path& source, const KDevelop::Path& build); + void configure(const QStringList &args); + void compute(); + void codemodel(); + +Q_SIGNALS: + void connected(); + void disconnected(); + void response(const QJsonObject &value); + +private: + void processOutput(); + void emitResponse(const QByteArray &data); + + QLocalSocket* m_localSocket; + QByteArray m_buffer; + QProcess m_process; +}; + +#endif // CMAKESERVER_H diff --git a/projectmanagers/cmake/cmakeserver.cpp b/projectmanagers/cmake/cmakeserver.cpp new file mode 100644 --- /dev/null +++ b/projectmanagers/cmake/cmakeserver.cpp @@ -0,0 +1,165 @@ +/* KDevelop CMake Support + * + * Copyright 2017 Aleix Pol + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cmakeserver.h" +#include "cmakeprojectdata.h" +#include "cmakeutils.h" +#include +#include +#include +#include +#include +#include +#include "debug.h" + +CMakeServer::CMakeServer(QObject* parent) + : QObject(parent) + , m_localSocket(new QLocalSocket(this)) +{ + QString path; + { + QTemporaryFile file(QDir::tempPath() + "/kdevelopcmake-"); + file.open(); + file.close(); + path = file.fileName(); + } + + m_process.setProcessChannelMode(QProcess::ForwardedChannels); + m_process.start(CMake::findExecutable(), {"-E", "server", "--experimental", "--pipe=" + path}); + + connect(&m_process, &QProcess::errorOccurred, this, [this, path](QProcess::ProcessError error) { + qWarning() << "cmake server error:" << error << path << m_process.readAllStandardError() << m_process.readAllStandardOutput(); + }); + connect(&m_process, static_cast(&QProcess::finished), this, [](int code){ + qCDebug(CMAKE) << "cmake server finished with code" << code; + }); + + connect(m_localSocket, &QIODevice::readyRead, this, &CMakeServer::processOutput); + connect(m_localSocket, static_cast(&QLocalSocket::error), this, [this, path](QLocalSocket::LocalSocketError socketError) { + qCDebug(CMAKE) << "cmake server socket error:" << socketError << path; + Q_EMIT disconnected(); + }); + connect(m_localSocket, &QLocalSocket::connected, this, &CMakeServer::connected); + + connect(&m_process, &QProcess::started, this, [this, path](){ + //Once the process has started, wait for the file to be created, then connect to it + QTimer* connectTimer = new QTimer(this); + connectTimer->setInterval(100); + connectTimer->setSingleShot(true); + connect(connectTimer, &QTimer::timeout, connectTimer, &QObject::deleteLater); + connect(connectTimer, &QTimer::timeout, this, [this, path]() { + m_localSocket->connectToServer(path, QIODevice::ReadWrite); + }); + }); +} + +CMakeServer::~CMakeServer() +{ + m_process.kill(); + m_process.waitForFinished(); +} + +void CMakeServer::waitForConnected() +{ + m_localSocket->waitForConnected(); +} + +bool CMakeServer::isServerAvailable() +{ + return m_localSocket->isOpen(); +} + +static QByteArray openTag() { return QByteArrayLiteral("\n[== \"CMake Server\" ==[\n"); } +static QByteArray closeTag() { return QByteArrayLiteral("\n]== \"CMake Server\" ==]\n"); } + +void CMakeServer::sendCommand(const QJsonObject& object) +{ + Q_ASSERT(isServerAvailable()); + + const QByteArray data = openTag() + QJsonDocument(object).toJson(QJsonDocument::Compact) + closeTag(); + auto len = m_localSocket->write(data); +// qCDebug(CMAKE) << "writing...\n" << QJsonDocument(object).toJson(); + Q_ASSERT(len > 0); +} + +void CMakeServer::processOutput() +{ + Q_ASSERT(m_localSocket); + + const auto openTag = ::openTag(); + const auto closeTag = ::closeTag(); + + m_buffer += m_localSocket->readAll(); + for(; m_buffer.size() > openTag.size(); ) { + + Q_ASSERT(m_buffer.startsWith(openTag)); + const int idx = m_buffer.indexOf(closeTag, openTag.size()); + if (idx >= 0) { + emitResponse(m_buffer.mid(openTag.size(), idx - openTag.size())); + m_buffer = m_buffer.mid(idx + closeTag.size()); + } else + break; + } +} + +void CMakeServer::emitResponse(const QByteArray& data) +{ + QJsonParseError error; + auto doc = QJsonDocument::fromJson(data, &error); + if (error.error) { + qCWarning(CMAKE) << "error processing" << error.errorString() << data; + } + Q_ASSERT(doc.isObject()); + Q_EMIT response(doc.object()); +} + +void CMakeServer::handshake(const KDevelop::Path& source, const KDevelop::Path& build) +{ + Q_ASSERT(!source.isEmpty()); + Q_ASSERT(!build.isEmpty()); + + sendCommand({ + {"cookie", ""}, + {"type", "handshake"}, + {"major", 1}, + {"protocolVersion", QJsonObject{{"major", 1}} }, + {"sourceDirectory", source.toLocalFile()}, + {"buildDirectory", build.toLocalFile()}, + {"generator", "Ninja"} //TODO: make it possible to keep whatever they have ATM + }); +} + +void CMakeServer::configure(const QStringList& args) +{ + sendCommand({ + {"type", "configure"}, + {"cacheArguments", QJsonArray::fromStringList(args)} + }); +} + +void CMakeServer::compute() +{ + sendCommand({ {"type", "compute"} }); +} + +void CMakeServer::codemodel() +{ + sendCommand({ {"type", "codemodel"} }); +} diff --git a/projectmanagers/cmake/duchain/usebuilder.h b/projectmanagers/cmake/cmakeserverimportjob.h copy from projectmanagers/cmake/duchain/usebuilder.h copy to projectmanagers/cmake/cmakeserverimportjob.h --- a/projectmanagers/cmake/duchain/usebuilder.h +++ b/projectmanagers/cmake/cmakeserverimportjob.h @@ -1,6 +1,6 @@ /* KDevelop CMake Support * - * Copyright 2014 Aleix Pol + * Copyright 2017 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,24 +18,39 @@ * 02110-1301, USA. */ -#ifndef USEBUILDER_H -#define USEBUILDER_H +#ifndef CMAKESERVERIMPORTJOB_H +#define CMAKESERVERIMPORTJOB_H -#include +#include +#include "cmakeprojectdata.h" -#include "contextbuilder.h" +namespace KDevelop +{ +class IProject; +} -class UseBuilder +class CMakeServerImportJob : public KJob { + Q_OBJECT public: - UseBuilder(const KDevelop::ReferencedTopDUContext& ctx); + CMakeServerImportJob(KDevelop::IProject* project, CMakeServer* server, QObject* parent); + + enum Error { NoError, UnexpectedDisconnect, ErrorResponse }; + + void start() override; - void startVisiting(CMakeContentIterator* node); + KDevelop::IProject* project() const { return m_project; } + + CMakeProjectData projectData() const { return m_data; } private: - void newUse(const KDevelop::RangeInRevision& sr, KDevelop::DeclarationPointer d); + void doStart(); + void processResponse(const QJsonObject &response); + + QPointer m_server; + KDevelop::IProject* m_project; - KDevelop::ReferencedTopDUContext m_ctx; + CMakeProjectData m_data; }; -#endif // USEBUILDER_H +#endif // CMAKESERVERIMPORTJOB_H diff --git a/projectmanagers/cmake/cmakeserverimportjob.cpp b/projectmanagers/cmake/cmakeserverimportjob.cpp new file mode 100644 --- /dev/null +++ b/projectmanagers/cmake/cmakeserverimportjob.cpp @@ -0,0 +1,166 @@ +/* KDevelop CMake Support + * + * Copyright 2017 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cmakeserverimportjob.h" +#include "cmakeutils.h" +#include "cmakeserver.h" +#include +#include +#include +#include "debug.h" +#include + +template +static T kTransform(const Q& list, W func) +{ + T ret; + ret.reserve(list.size()); + for (auto it = list.constBegin(), itEnd = list.constEnd(); it!=itEnd; ++it) + ret += func(*it); + return ret; +} + +static QString unescape(const QStringRef& input) +{ + QString output; + output.reserve(input.length()); + bool isEscaped = false; + for (auto it = input.data(), end = it + input.length(); it != end; ++it) { + QChar c = *it; + if (!isEscaped && c == '\\') { + isEscaped = true; + } else { + output.append(c); + isEscaped = false; + } + } + return output; +} + +static QHash processDefines(const QString &compileFlags, const QJsonArray &defines) +{ + QHash ret; + const auto& defineRx = MakeFileResolver::defineRegularExpression(); + auto it = defineRx.globalMatch(compileFlags); + while (it.hasNext()) { + const auto match = it.next(); + QString value; + if (match.lastCapturedIndex() > 1) { + value = unescape(match.capturedRef(match.lastCapturedIndex())); + } + ret[match.captured(1)] = value; + } + + for(const QJsonValue& defineValue: defines) { + const QString define = defineValue.toString(); + const int eqIdx = define.indexOf(QLatin1Char('=')); + if (eqIdx<0) + ret[define] = QString(); + else + ret[define.left(eqIdx)] = define.mid(eqIdx+1); + } + return ret; +} + +static void processFileData(const QJsonObject &response, CMakeProjectData &data) +{ + const auto configs = response.value(QLatin1String("configurations")).toArray(); + qCDebug(CMAKE) << "process response" << response; + for (const auto &config: configs) { + const auto projects = config.toObject().value(QLatin1String("projects")).toArray(); + for (const auto &project: projects) { + const auto targets = project.toObject().value(QLatin1String("targets")).toArray(); + for (const auto &targetObject: targets) { + const auto target = targetObject.toObject(); + const KDevelop::Path targetDir(target.value(QLatin1String("sourceDirectory")).toString()); + + data.targets[targetDir] += target.value(QLatin1String("name")).toString(); + + const auto fileGroups = target.value(QLatin1String("fileGroups")).toArray(); + for (const auto &fileGroupValue: fileGroups) { + const auto fileGroup = fileGroupValue.toObject(); + CMakeFile file; + file.includes = kTransform(fileGroup.value(QLatin1String("includePath")).toArray(), [](const QJsonValue& val) { return KDevelop::Path(val.toObject().value(QLatin1String("path")).toString()); }); + file.defines = processDefines(fileGroup.value(QLatin1String("compileFlags")).toString(), fileGroup.value(QLatin1String("defines")).toArray()); + + const auto sourcesArray = fileGroup.value(QLatin1String("sources")).toArray(); + const KDevelop::Path::List sources = kTransform(sourcesArray, [targetDir](const QJsonValue& val) { return KDevelop::Path(targetDir, val.toString()); }); + for (const auto& source: sources) { + data.compilationData.files[source] = file; + } + qCDebug(CMAKE) << "registering..." << sources << file; + } + } + } + } +} + +CMakeServerImportJob::CMakeServerImportJob(KDevelop::IProject* project, CMakeServer* server, QObject* parent) + : KJob(parent) + , m_server(server) + , m_project(project) +{ + connect(m_server, &CMakeServer::disconnected, this, [this]() { + setError(UnexpectedDisconnect); + emitResult(); + }); +} + +void CMakeServerImportJob::start() +{ + if (m_server->isServerAvailable()) + doStart(); + else + connect(m_server, &CMakeServer::connected, this, &CMakeServerImportJob::doStart); +} + +void CMakeServerImportJob::doStart() +{ + connect(m_server, &CMakeServer::response, this, &CMakeServerImportJob::processResponse); + + m_server->handshake(m_project->path(), CMake::currentBuildDir(m_project)); +} + +void CMakeServerImportJob::processResponse(const QJsonObject& response) +{ + const auto responseType = response.value(QLatin1String("type")); + if (responseType == QLatin1String("reply")) { + const auto inReplyTo = response.value(QLatin1String("inReplyTo")); + qCDebug(CMAKE) << "replying..." << inReplyTo; + if (inReplyTo == QLatin1String("handshake")) + m_server->configure({}); + else if (inReplyTo == QLatin1String("configure")) + m_server->compute(); + else if (inReplyTo == QLatin1String("compute")) + m_server->codemodel(); + else if(inReplyTo == QLatin1String("codemodel")) { + processFileData(response, m_data); + emitResult(); + } else + qWarning() << "unhandled reply" << response; + } else if(responseType == QLatin1String("error")) { + setError(ErrorResponse); + setErrorText(response.value(QLatin1String("errorMessage")).toString()); + qWarning() << "error!!" << response; + emitResult(); + } else { + qWarning() << "unhandled message" << response; + } +} diff --git a/projectmanagers/cmake/cmakeutils.h b/projectmanagers/cmake/cmakeutils.h --- a/projectmanagers/cmake/cmakeutils.h +++ b/projectmanagers/cmake/cmakeutils.h @@ -162,9 +162,9 @@ KDEVCMAKECOMMON_EXPORT void attemptMigrate( KDevelop::IProject* project ); /** - * Attempts to update CMake configuration keys from the cache data. + * Attempts to update CMake configuration keys from the cache data (CMakeCache.txt) * - * @param model The CMake cache model to load data from. If NULL, the model is created based on build directory path for the given index. + * The model is created based on build directory path for the given index @p buildDirectory */ KDEVCMAKECOMMON_EXPORT void updateConfig( KDevelop::IProject* project, int buildDirectory); diff --git a/projectmanagers/cmake/cmakeutils.cpp b/projectmanagers/cmake/cmakeutils.cpp --- a/projectmanagers/cmake/cmakeutils.cpp +++ b/projectmanagers/cmake/cmakeutils.cpp @@ -567,7 +567,7 @@ QString executeProcess(const QString& execName, const QStringList& args) { Q_ASSERT(!execName.isEmpty()); - qCDebug(CMAKE) << "Executing:" << execName << "::" << args /*<< "into" << *m_vars*/; + qCDebug(CMAKE) << "Executing:" << execName << "::" << args; QProcess p; QTemporaryDir tmp("kdevcmakemanager"); diff --git a/projectmanagers/cmake/duchain/usebuilder.h b/projectmanagers/cmake/duchain/usebuilder.h --- a/projectmanagers/cmake/duchain/usebuilder.h +++ b/projectmanagers/cmake/duchain/usebuilder.h @@ -28,7 +28,7 @@ class UseBuilder { public: - UseBuilder(const KDevelop::ReferencedTopDUContext& ctx); + explicit UseBuilder(const KDevelop::ReferencedTopDUContext& ctx); void startVisiting(CMakeContentIterator* node); diff --git a/projectmanagers/cmake/parser/cmakeduchaintypes.h b/projectmanagers/cmake/parser/cmakeduchaintypes.h --- a/projectmanagers/cmake/parser/cmakeduchaintypes.h +++ b/projectmanagers/cmake/parser/cmakeduchaintypes.h @@ -37,7 +37,7 @@ public: TargetType(); TargetType(TargetType& rhs); - TargetType(KDevelop::AbstractTypeData& dd); + explicit TargetType(KDevelop::AbstractTypeData& dd); void accept0(KDevelop::TypeVisitor* v) const override; AbstractType* clone() const override; diff --git a/projectmanagers/cmake/parser/cmakelistsparser.h b/projectmanagers/cmake/parser/cmakelistsparser.h --- a/projectmanagers/cmake/parser/cmakelistsparser.h +++ b/projectmanagers/cmake/parser/cmakelistsparser.h @@ -36,7 +36,7 @@ struct CMakeFunctionArgument { CMakeFunctionArgument(): value(), quoted(false), line(0), column(0) {} - CMakeFunctionArgument(const QString& v); + explicit CMakeFunctionArgument(const QString& v); CMakeFunctionArgument(const QString& v, bool q, quint32 l = 0, quint32 c=0); inline bool operator == (const CMakeFunctionArgument& r) const { diff --git a/projectmanagers/cmake/parser/cmaketypes.h b/projectmanagers/cmake/parser/cmaketypes.h --- a/projectmanagers/cmake/parser/cmaketypes.h +++ b/projectmanagers/cmake/parser/cmaketypes.h @@ -35,7 +35,7 @@ struct CacheEntry { - CacheEntry(const QString& value=QString(), const QString &doc=QString()) : value(value), doc(doc) {} + explicit CacheEntry(const QString& value=QString(), const QString &doc=QString()) : value(value), doc(doc) {} QString value; QString doc; }; diff --git a/projectmanagers/cmake/settings/cmakebuildsettings.ui b/projectmanagers/cmake/settings/cmakebuildsettings.ui --- a/projectmanagers/cmake/settings/cmakebuildsettings.ui +++ b/projectmanagers/cmake/settings/cmakebuildsettings.ui @@ -17,6 +17,9 @@ + + 0 + diff --git a/projectmanagers/cmake/settings/cmakecachedelegate.h b/projectmanagers/cmake/settings/cmakecachedelegate.h --- a/projectmanagers/cmake/settings/cmakecachedelegate.h +++ b/projectmanagers/cmake/settings/cmakecachedelegate.h @@ -29,7 +29,7 @@ { Q_OBJECT public: - CMakeCacheDelegate(QObject* parent); + explicit CMakeCacheDelegate(QObject* parent); ~CMakeCacheDelegate() override; QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const override; diff --git a/projectmanagers/cmake/settings/cmakepreferences.cpp b/projectmanagers/cmake/settings/cmakepreferences.cpp --- a/projectmanagers/cmake/settings/cmakepreferences.cpp +++ b/projectmanagers/cmake/settings/cmakepreferences.cpp @@ -51,11 +51,8 @@ CMakePreferences::CMakePreferences(IPlugin* plugin, const ProjectConfigOptions& options, QWidget* parent) : ConfigPage(plugin, nullptr, parent), m_project(options.project), m_currentModel(nullptr) { - QVBoxLayout* l = new QVBoxLayout( this ); - QWidget* w = new QWidget; m_prefsUi = new Ui::CMakeBuildSettings; - m_prefsUi->setupUi( w ); - l->addWidget( w ); + m_prefsUi->setupUi(this); m_prefsUi->addBuildDir->setIcon(QIcon::fromTheme( "list-add" )); m_prefsUi->removeBuildDir->setIcon(QIcon::fromTheme( "list-remove" )); @@ -295,20 +292,14 @@ // NOTE: (on removing the trailing slashes) // Generally, we have no clue about how shall a trailing slash look in the current system. // Moreover, the slash may be a part of the filename. - // It may be '/' or '\', so maybe should we rely on CMake::allBuildDirs() for returning well-formed pathes? + // It may be '/' or '\', so maybe should we rely on CMake::allBuildDirs() for returning well-formed paths? QStringList used = CMake::allBuildDirs( m_project ); bdCreator.setAlreadyUsed(used); bdCreator.setCMakeBinary(Path(CMake::findExecutable())); if(bdCreator.exec()) { - QString newbuilddir = bdCreator.buildFolder().toLocalFile(); - m_prefsUi->buildDirs->addItem(newbuilddir); - - int buildDirCount = m_prefsUi->buildDirs->count(); - int addedBuildDirIndex = buildDirCount - 1; - m_prefsUi->buildDirs->setCurrentIndex(addedBuildDirIndex); - m_prefsUi->removeBuildDir->setEnabled(true); + int addedBuildDirIndex = m_prefsUi->buildDirs->count(); // Initialize the kconfig items with the values from the dialog, this ensures the settings // end up in the config file once the changes are saved @@ -319,14 +310,20 @@ qCDebug(CMAKE) << "adding to cmake config: build type " << bdCreator.buildType(); qCDebug(CMAKE) << "adding to cmake config: cmake binary " << bdCreator.cmakeBinary(); qCDebug(CMAKE) << "adding to cmake config: environment empty"; - CMake::setBuildDirCount( m_project, buildDirCount ); + CMake::setOverrideBuildDirIndex( m_project, addedBuildDirIndex ); + CMake::setBuildDirCount( m_project, addedBuildDirIndex + 1 ); CMake::setCurrentBuildDir( m_project, bdCreator.buildFolder() ); CMake::setCurrentInstallDir( m_project, bdCreator.installPrefix() ); CMake::setCurrentExtraArguments( m_project, bdCreator.extraArguments() ); CMake::setCurrentBuildType( m_project, bdCreator.buildType() ); CMake::setCurrentCMakeBinary( m_project, bdCreator.cmakeBinary() ); CMake::setCurrentEnvironment( m_project, QString() ); + QString newbuilddir = bdCreator.buildFolder().toLocalFile(); + m_prefsUi->buildDirs->addItem( newbuilddir ); + m_prefsUi->buildDirs->setCurrentIndex( addedBuildDirIndex ); + m_prefsUi->removeBuildDir->setEnabled( true ); + qCDebug(CMAKE) << "Emitting changed signal for cmake kcm"; emit changed(); } diff --git a/projectmanagers/cmake/tests/CMakeLists.txt b/projectmanagers/cmake/tests/CMakeLists.txt --- a/projectmanagers/cmake/tests/CMakeLists.txt +++ b/projectmanagers/cmake/tests/CMakeLists.txt @@ -24,6 +24,8 @@ kdevcmake_add_test(test_cmakemanager KDev::Language KDev::Tests KDev::Project kdevcmakemanagernosettings) # kdevcmake_add_test(ctestfindsuitestest KDev::Language KDev::Tests) +kdevcmake_add_test(test_cmakeserver KDev::Language KDev::Tests KDev::Project kdevcmakemanagernosettings) + # this is not a unit test but a testing tool, kept here for convenience add_executable(kdevprojectopen kdevprojectopen.cpp) target_link_libraries(kdevprojectopen Qt5::Test KDev::Project KDev::Tests kdevcmakecommon) diff --git a/projectmanagers/cmake/tests/cmakeprojectvisitortest.cpp b/projectmanagers/cmake/tests/cmakeprojectvisitortest.cpp --- a/projectmanagers/cmake/tests/cmakeprojectvisitortest.cpp +++ b/projectmanagers/cmake/tests/cmakeprojectvisitortest.cpp @@ -520,7 +520,7 @@ results.clear(); results << StringPair("result", ""); QTest::newRow("empty set with scope") << - "set(result ${nonexistant} PARENT_SCOPE)\n" + "set(result ${nonexistent} PARENT_SCOPE)\n" << cacheValues << results; } diff --git a/projectmanagers/cmake/tests/manual/kf5_app/CMakeLists.txt b/projectmanagers/cmake/tests/manual/kf5_app/CMakeLists.txt --- a/projectmanagers/cmake/tests/manual/kf5_app/CMakeLists.txt +++ b/projectmanagers/cmake/tests/manual/kf5_app/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.0) find_package(ECM 0.0.9 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${KDevelop_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH}) diff --git a/projectmanagers/cmake/tests/manual/target_includes/CMakeLists.txt b/projectmanagers/cmake/tests/manual/target_includes/CMakeLists.txt --- a/projectmanagers/cmake/tests/manual/target_includes/CMakeLists.txt +++ b/projectmanagers/cmake/tests/manual/target_includes/CMakeLists.txt @@ -3,4 +3,4 @@ project(target_includes) add_executable(target main.cpp) -set_property(TARGET target APPEND PROPERTY INCLUDE_DIRECTORIES "includes") +set_property(TARGET target APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/includes") diff --git a/projectmanagers/cmake/tests/paths.h.cmake b/projectmanagers/cmake/tests/paths.h.cmake --- a/projectmanagers/cmake/tests/paths.h.cmake +++ b/projectmanagers/cmake/tests/paths.h.cmake @@ -1,4 +1,5 @@ #define CMAKE_TESTS_PROJECTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/manual" +#define CMAKE_TESTS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" #define CMAKE_INSTALLED_MODULES "${DATA_INSTALL_DIR}/cmake/modules" #define TEST_PREFIX_PATH "${CMAKE_PREFIX_PATH};${CMAKE_INSTALL_PREFIX}" #define TEST_ENV_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}" diff --git a/projectmanagers/cmake/tests/test_cmakemanager.cpp b/projectmanagers/cmake/tests/test_cmakemanager.cpp --- a/projectmanagers/cmake/tests/test_cmakemanager.cpp +++ b/projectmanagers/cmake/tests/test_cmakemanager.cpp @@ -277,10 +277,10 @@ { IProject* project = loadProject("custom_target_sources"); - QEXPECT_FAIL("", "Will fix soon, hopefully", Abort); QList targets = project->buildSystemManager()->targets(project->projectItem()); QVERIFY(targets.size() == 1); + QEXPECT_FAIL("", "Will fix soon, hopefully", Abort); ProjectTargetItem *target = targets.first(); QCOMPARE(target->fileList().size(), 1); QCOMPARE(target->fileList().first()->baseName(), QStringLiteral("foo.cpp")); @@ -343,7 +343,7 @@ Path sourceDir = project->path(); Path buildDir(sourceDir, "build/"); - CMakeImportJob* job = new CMakeImportJob(project, this); + auto job = new CMakeImportJsonJob(project, this); job->start(); } diff --git a/projectmanagers/cmake/tests/test_cmakeserver.cpp b/projectmanagers/cmake/tests/test_cmakeserver.cpp new file mode 100644 --- /dev/null +++ b/projectmanagers/cmake/tests/test_cmakeserver.cpp @@ -0,0 +1,74 @@ +/* KDevelop CMake Support + * + * Copyright 2017 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include "testhelpers.h" +#include + +using namespace KDevelop; + +class CMakeServerTest : public QObject +{ +Q_OBJECT +private slots: + void testRun() + { + CMakeServer server(this); + QSignalSpy spyConnected(&server, &CMakeServer::connected); + QVERIFY(server.isServerAvailable() || spyConnected.wait()); + + QSignalSpy spy(&server, &CMakeServer::response); + + QJsonObject codeModel; + int errors = 0; + connect(&server, &CMakeServer::response, this, [&errors, &codeModel, &server](const QJsonObject &response) { + if (response.value("type") == QLatin1String("reply")) { + if (response.value("inReplyTo") == QLatin1String("configure")) + server.compute(); + else if (response.value("inReplyTo") == QLatin1String("compute")) + server.codemodel(); + else if(response.value("inReplyTo") == QLatin1String("codemodel")) + codeModel = response; + } else if(response.value("type") == QLatin1String("error")) { + ++errors; + } + }); + + const QString name = "single_subdirectory"; + const auto paths = projectPaths(name); + const QString builddir = QStringLiteral(CMAKE_TESTS_BINARY_DIR "/cmake-server-test-builddir/") + name; + QVERIFY(QDir(builddir).removeRecursively()); + QVERIFY(QDir(builddir).mkpath(builddir)); + + QVERIFY(spy.wait()); + server.handshake(paths.sourceDir, Path(builddir)); + QVERIFY(spy.wait()); + server.configure({}); + while(codeModel.isEmpty()) + QVERIFY(spy.wait()); + QCOMPARE(errors, 0); + QVERIFY(!codeModel.isEmpty()); + qDebug() << "codemodel" << codeModel; + } +}; + +QTEST_MAIN( CMakeServerTest ) + +#include "test_cmakeserver.moc" diff --git a/projectmanagers/cmake/tests/testhelpers.h b/projectmanagers/cmake/tests/testhelpers.h --- a/projectmanagers/cmake/tests/testhelpers.h +++ b/projectmanagers/cmake/tests/testhelpers.h @@ -132,8 +132,9 @@ KDevelop::ICore::self()->projectController()->openProject(paths.projectFile.toUrl()); - if ( spy.isEmpty() && !spy.wait(30000) ) + if ( spy.isEmpty() && !spy.wait(30000) ) { qFatal( "Timeout while waiting for opened signal" ); + } KDevelop::IProject* project = KDevelop::ICore::self()->projectController()->findProjectByName(name); Q_ASSERT(project); diff --git a/projectmanagers/custom-buildsystem/CMakeLists.txt b/projectmanagers/custom-buildsystem/CMakeLists.txt --- a/projectmanagers/custom-buildsystem/CMakeLists.txt +++ b/projectmanagers/custom-buildsystem/CMakeLists.txt @@ -8,6 +8,7 @@ custombuildsystemconfig.cpp custombuildsystemplugin.cpp custombuildjob.cpp + configconstants.cpp configwidget.cpp custombuildsystemconfigwidget.cpp kcm_custombuildsystem.cpp diff --git a/projectmanagers/custom-buildsystem/configconstants.h b/projectmanagers/custom-buildsystem/configconstants.h --- a/projectmanagers/custom-buildsystem/configconstants.h +++ b/projectmanagers/custom-buildsystem/configconstants.h @@ -20,23 +20,23 @@ #ifndef CONFIGCONSTANTS_H #define CONFIGCONSTANTS_H -#include +class QString; namespace ConfigConstants { - const QString buildConfigPrefix("BuildConfig"); - const QString buildDirKey("BuildDir"); - const QString currentConfigKey("CurrentConfiguration"); - const QString toolGroupPrefix("Tool"); - const QString toolArguments("Arguments"); - const QString toolExecutable("Executable"); - const QString toolEnvironment("Environment"); - const QString toolType("Type"); - const QString toolEnabled("Enabled"); - const QString projectPathPrefix("ProjectPath"); - const QString projectPathKey("Path"); - const QString customBuildSystemGroup("CustomBuildSystem"); - const QString configTitleKey("Title"); + QString buildConfigPrefix(); + QString buildDirKey(); + QString currentConfigKey(); + QString toolGroupPrefix(); + QString toolArguments(); + QString toolExecutable(); + QString toolEnvironment(); + QString toolType(); + QString toolEnabled(); + QString projectPathPrefix(); + QString projectPathKey(); + QString customBuildSystemGroup(); + QString configTitleKey(); } #endif diff --git a/projectmanagers/custom-buildsystem/configconstants.h b/projectmanagers/custom-buildsystem/configconstants.cpp copy from projectmanagers/custom-buildsystem/configconstants.h copy to projectmanagers/custom-buildsystem/configconstants.cpp --- a/projectmanagers/custom-buildsystem/configconstants.h +++ b/projectmanagers/custom-buildsystem/configconstants.cpp @@ -17,26 +17,23 @@ * along with this program; if not, see . * ************************************************************************/ -#ifndef CONFIGCONSTANTS_H -#define CONFIGCONSTANTS_H +#include "configconstants.h" #include namespace ConfigConstants { - const QString buildConfigPrefix("BuildConfig"); - const QString buildDirKey("BuildDir"); - const QString currentConfigKey("CurrentConfiguration"); - const QString toolGroupPrefix("Tool"); - const QString toolArguments("Arguments"); - const QString toolExecutable("Executable"); - const QString toolEnvironment("Environment"); - const QString toolType("Type"); - const QString toolEnabled("Enabled"); - const QString projectPathPrefix("ProjectPath"); - const QString projectPathKey("Path"); - const QString customBuildSystemGroup("CustomBuildSystem"); - const QString configTitleKey("Title"); + QString buildConfigPrefix() { return QStringLiteral("BuildConfig"); } + QString buildDirKey() { return QStringLiteral("BuildDir"); } + QString currentConfigKey() { return QStringLiteral("CurrentConfiguration"); } + QString toolGroupPrefix() { return QStringLiteral("Tool"); } + QString toolArguments() { return QStringLiteral("Arguments"); } + QString toolExecutable() { return QStringLiteral("Executable"); } + QString toolEnvironment() { return QStringLiteral("Environment"); } + QString toolType() { return QStringLiteral("Type"); } + QString toolEnabled() { return QStringLiteral("Enabled"); } + QString projectPathPrefix() { return QStringLiteral("ProjectPath"); } + QString projectPathKey() { return QStringLiteral("Path"); } + QString customBuildSystemGroup() { return QStringLiteral("CustomBuildSystem"); } + QString configTitleKey() { return QStringLiteral("Title"); } } - -#endif diff --git a/projectmanagers/custom-buildsystem/configwidget.h b/projectmanagers/custom-buildsystem/configwidget.h --- a/projectmanagers/custom-buildsystem/configwidget.h +++ b/projectmanagers/custom-buildsystem/configwidget.h @@ -38,7 +38,7 @@ { Q_OBJECT public: - ConfigWidget( QWidget* parent = nullptr ); + explicit ConfigWidget( QWidget* parent = nullptr ); void loadConfig( CustomBuildSystemConfig cfg ); CustomBuildSystemConfig config() const; void clear(); diff --git a/projectmanagers/custom-buildsystem/custombuildjob.cpp b/projectmanagers/custom-buildsystem/custombuildjob.cpp --- a/projectmanagers/custom-buildsystem/custombuildjob.cpp +++ b/projectmanagers/custom-buildsystem/custombuildjob.cpp @@ -47,19 +47,19 @@ QString subgrpname; switch( type ) { case CustomBuildSystemTool::Build: - subgrpname = QString( "%1Build" ).arg( ConfigConstants::toolGroupPrefix ); + subgrpname = ConfigConstants::toolGroupPrefix() + QLatin1String("Build"); break; case CustomBuildSystemTool::Clean: - subgrpname = QString( "%1Clean" ).arg( ConfigConstants::toolGroupPrefix ); + subgrpname = ConfigConstants::toolGroupPrefix() + QLatin1String("Clean"); break; case CustomBuildSystemTool::Install: - subgrpname = QString( "%1Install" ).arg( ConfigConstants::toolGroupPrefix ); + subgrpname = ConfigConstants::toolGroupPrefix() + QLatin1String("Install"); break; case CustomBuildSystemTool::Configure: - subgrpname = QString( "%1Configure" ).arg( ConfigConstants::toolGroupPrefix ); + subgrpname = ConfigConstants::toolGroupPrefix() + QLatin1String("Configure"); break; case CustomBuildSystemTool::Prune: - subgrpname = QString( "%1Prune" ).arg( ConfigConstants::toolGroupPrefix ); + subgrpname = ConfigConstants::toolGroupPrefix() + QLatin1String("Prune"); break; case CustomBuildSystemTool::Undefined: return; @@ -69,10 +69,10 @@ KConfigGroup g = plugin->configuration( item->project() ); if(g.isValid()) { KConfigGroup grp = g.group( subgrpname ); - enabled = grp.readEntry( ConfigConstants::toolEnabled, false ); - cmd = grp.readEntry( ConfigConstants::toolExecutable, QUrl() ).toLocalFile(); - environment = grp.readEntry( ConfigConstants::toolEnvironment, "" ); - arguments = grp.readEntry( ConfigConstants::toolArguments, "" ); + enabled = grp.readEntry(ConfigConstants::toolEnabled(), false); + cmd = grp.readEntry(ConfigConstants::toolExecutable(), QUrl()).toLocalFile(); + environment = grp.readEntry(ConfigConstants::toolEnvironment(), QString()); + arguments = grp.readEntry(ConfigConstants::toolArguments(), QString()); } QString title; diff --git a/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.h b/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.h --- a/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.h +++ b/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.h @@ -41,7 +41,7 @@ { Q_OBJECT public: - CustomBuildSystemConfigWidget( QWidget* parent ); + explicit CustomBuildSystemConfigWidget( QWidget* parent ); void loadFrom( KConfig* ); void saveTo( KConfig*, KDevelop::IProject* project ); void loadDefaults(); diff --git a/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.cpp b/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.cpp --- a/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.cpp +++ b/projectmanagers/custom-buildsystem/custombuildsystemconfigwidget.cpp @@ -44,7 +44,7 @@ Q_ASSERT( type >= 0 && type < toolTypeCount ); Q_UNUSED( toolTypeCount ); - return ConfigConstants::toolGroupPrefix + toolTypes[type]; + return ConfigConstants::toolGroupPrefix() + toolTypes[type]; } } @@ -79,31 +79,31 @@ { ui->currentConfig->clear(); QStringList groupNameList; - KConfigGroup grp = cfg->group( ConfigConstants::customBuildSystemGroup ); + KConfigGroup grp = cfg->group(ConfigConstants::customBuildSystemGroup()); foreach( const QString& grpName, grp.groupList() ) { KConfigGroup subgrp = grp.group( grpName ); CustomBuildSystemConfig config; - config.title = subgrp.readEntry( ConfigConstants::configTitleKey, QString() ); - config.buildDir = subgrp.readEntry( ConfigConstants::buildDirKey, QUrl() ); + config.title = subgrp.readEntry(ConfigConstants::configTitleKey(), QString()); + config.buildDir = subgrp.readEntry(ConfigConstants::buildDirKey(), QUrl()); foreach( const QString& subgrpName, subgrp.groupList() ) { - if( subgrpName.startsWith( ConfigConstants::toolGroupPrefix ) ) { + if (subgrpName.startsWith(ConfigConstants::toolGroupPrefix())) { KConfigGroup toolgrp = subgrp.group( subgrpName ); CustomBuildSystemTool tool; - tool.arguments = toolgrp.readEntry( ConfigConstants::toolArguments, "" ); - tool.executable = toolgrp.readEntry( ConfigConstants::toolExecutable, QUrl() ); - tool.envGrp = toolgrp.readEntry( ConfigConstants::toolEnvironment, QString() ); - tool.enabled = toolgrp.readEntry( ConfigConstants::toolEnabled, false ); - tool.type = CustomBuildSystemTool::ActionType( toolgrp.readEntry( ConfigConstants::toolType, 0 ) ); + tool.arguments = toolgrp.readEntry(ConfigConstants::toolArguments(), QString()); + tool.executable = toolgrp.readEntry(ConfigConstants::toolExecutable(), QUrl()); + tool.envGrp = toolgrp.readEntry(ConfigConstants::toolEnvironment(), QString()); + tool.enabled = toolgrp.readEntry(ConfigConstants::toolEnabled(), false); + tool.type = CustomBuildSystemTool::ActionType(toolgrp.readEntry(ConfigConstants::toolType(), 0)); config.tools[tool.type] = tool; } } configs << config; ui->currentConfig->addItem( config.title ); groupNameList << grpName; } - int idx = groupNameList.indexOf( grp.readEntry( ConfigConstants::currentConfigKey, "" ) ); + int idx = groupNameList.indexOf(grp.readEntry(ConfigConstants::currentConfigKey(), QString())); if( !groupNameList.isEmpty() && idx < 0 ) idx = 0; @@ -114,28 +114,28 @@ void CustomBuildSystemConfigWidget::saveConfig( KConfigGroup& grp, CustomBuildSystemConfig& c, int index ) { // Generate group name, access and clear it - KConfigGroup subgrp = grp.group( ConfigConstants::buildConfigPrefix + QString::number(index) ); + KConfigGroup subgrp = grp.group(ConfigConstants::buildConfigPrefix() + QString::number(index)); subgrp.deleteGroup(); // Write current configuration key, if our group is current if( ui->currentConfig->currentIndex() == index ) - grp.writeEntry( ConfigConstants::currentConfigKey, subgrp.name() ); + grp.writeEntry(ConfigConstants::currentConfigKey(), subgrp.name()); - subgrp.writeEntry( ConfigConstants::configTitleKey, c.title ); - subgrp.writeEntry( ConfigConstants::buildDirKey, c.buildDir ); + subgrp.writeEntry(ConfigConstants::configTitleKey(), c.title); + subgrp.writeEntry(ConfigConstants::buildDirKey(), c.buildDir); foreach( const CustomBuildSystemTool& tool, c.tools ) { KConfigGroup toolgrp = subgrp.group( generateToolGroupName( tool.type ) ); - toolgrp.writeEntry( ConfigConstants::toolType, int(tool.type) ); - toolgrp.writeEntry( ConfigConstants::toolEnvironment , tool.envGrp ); - toolgrp.writeEntry( ConfigConstants::toolEnabled, tool.enabled ); - toolgrp.writeEntry( ConfigConstants::toolExecutable, tool.executable ); - toolgrp.writeEntry( ConfigConstants::toolArguments, tool.arguments ); + toolgrp.writeEntry(ConfigConstants::toolType(), int(tool.type)); + toolgrp.writeEntry(ConfigConstants::toolEnvironment(), tool.envGrp); + toolgrp.writeEntry(ConfigConstants::toolEnabled(), tool.enabled); + toolgrp.writeEntry(ConfigConstants::toolExecutable(), tool.executable); + toolgrp.writeEntry(ConfigConstants::toolArguments(), tool.arguments); } } void CustomBuildSystemConfigWidget::saveTo( KConfig* cfg, KDevelop::IProject* /*project*/ ) { - KConfigGroup subgrp = cfg->group( ConfigConstants::customBuildSystemGroup ); + KConfigGroup subgrp = cfg->group(ConfigConstants::customBuildSystemGroup()); subgrp.deleteGroup(); for( int i = 0; i < ui->currentConfig->count(); i++ ) { configs[i].title = ui->currentConfig->itemText(i); diff --git a/projectmanagers/custom-buildsystem/custombuildsystemplugin.cpp b/projectmanagers/custom-buildsystem/custombuildsystemplugin.cpp --- a/projectmanagers/custom-buildsystem/custombuildsystemplugin.cpp +++ b/projectmanagers/custom-buildsystem/custombuildsystemplugin.cpp @@ -91,7 +91,7 @@ return Path(); } - Path builddir(grp.readEntry( ConfigConstants::buildDirKey, QUrl() )); + Path builddir(grp.readEntry(ConfigConstants::buildDirKey(), QUrl())); if(!builddir.isValid() ) // set builddir to default if project contains a buildDirKey that does not have a value { builddir = item->project()->path(); @@ -175,9 +175,9 @@ KConfigGroup CustomBuildSystem::configuration( IProject* project ) const { - KConfigGroup grp = project->projectConfiguration()->group( ConfigConstants::customBuildSystemGroup ); - if(grp.isValid() && grp.hasKey(ConfigConstants::currentConfigKey)) - return grp.group( grp.readEntry( ConfigConstants::currentConfigKey ) ); + KConfigGroup grp = project->projectConfiguration()->group(ConfigConstants::customBuildSystemGroup()); + if (grp.isValid() && grp.hasKey(ConfigConstants::currentConfigKey())) + return grp.group(grp.readEntry(ConfigConstants::currentConfigKey())); else return KConfigGroup(); } diff --git a/projectmanagers/custom-buildsystem/tests/CMakeLists.txt b/projectmanagers/custom-buildsystem/tests/CMakeLists.txt --- a/projectmanagers/custom-buildsystem/tests/CMakeLists.txt +++ b/projectmanagers/custom-buildsystem/tests/CMakeLists.txt @@ -8,6 +8,7 @@ # Useful for testing UI ideas quickly set( kcm_uitest_SRCS kcmuitestmain.cpp ../custombuildsystemconfigwidget.cpp + ../configconstants.cpp ../configwidget.cpp ../debugarea.cpp ) diff --git a/projectmanagers/custom-buildsystem/tests/projects/builddirproject/.kdev4/builddirproject.kdev4 b/projectmanagers/custom-buildsystem/tests/projects/builddirproject/.kdev4/builddirproject.kdev4 new file mode 100644 --- /dev/null +++ b/projectmanagers/custom-buildsystem/tests/projects/builddirproject/.kdev4/builddirproject.kdev4 @@ -0,0 +1,55 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00) + +[CustomBuildSystem] +CurrentConfiguration=BuildConfig0 + +[CustomBuildSystem][BuildConfig0] +BuildDir= +Title=mainbuild + +[CustomBuildSystem][BuildConfig0][ToolBuild] +Arguments= +Enabled=false +Environment= +Executable= +Type=0 + +[CustomBuildSystem][BuildConfig0][ToolClean] +Arguments= +Enabled=false +Environment= +Executable= +Type=3 + +[CustomBuildSystem][BuildConfig0][ToolConfigure] +Arguments= +Enabled=false +Environment= +Executable= +Type=1 + +[CustomBuildSystem][BuildConfig0][ToolInstall] +Arguments= +Enabled=false +Environment= +Executable= +Type=2 + +[CustomBuildSystem][BuildConfig0][ToolPrune] +Arguments= +Enabled=false +Environment= +Executable= +Type=4 + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[MakeBuilder] +Number Of Jobs=1 + +[Project] +VersionControlSupport=kdevgit diff --git a/projectmanagers/custom-buildsystem/tests/projects/multipathproject/.kdev4/multipathproject.kdev4 b/projectmanagers/custom-buildsystem/tests/projects/multipathproject/.kdev4/multipathproject.kdev4 new file mode 100644 --- /dev/null +++ b/projectmanagers/custom-buildsystem/tests/projects/multipathproject/.kdev4/multipathproject.kdev4 @@ -0,0 +1,45 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00 \x00M\x00u\x00l\x00t\x00i\x00P\x00a\x00t\x00h\x00P\x00r\x00o\x00j\x00e\x00c\x00t) + +[CustomBuildSystem] +CurrentConfiguration=BuildConfig0 + +[CustomBuildSystem][BuildConfig0] +BuildDir=file:///home/andreas/projects/testcustom/build2 +Title=main + +[CustomBuildSystem][BuildConfig0][ToolBuild] +Arguments= +Enabled=false +Environment= +Executable= +Type=0 + +[CustomBuildSystem][BuildConfig0][ToolClean] +Arguments= +Enabled=false +Environment= +Executable= +Type=3 + +[CustomBuildSystem][BuildConfig0][ToolConfigure] +Arguments= +Enabled=false +Environment= +Executable= +Type=1 + +[CustomBuildSystem][BuildConfig0][ToolInstall] +Arguments= +Enabled=false +Environment= +Executable= +Type=2 + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Project] +VersionControlSupport= diff --git a/projectmanagers/custom-buildsystem/tests/projects/simpleproject/.kdev4/simpleproject.kdev4 b/projectmanagers/custom-buildsystem/tests/projects/simpleproject/.kdev4/simpleproject.kdev4 new file mode 100644 --- /dev/null +++ b/projectmanagers/custom-buildsystem/tests/projects/simpleproject/.kdev4/simpleproject.kdev4 @@ -0,0 +1,45 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x1a\x00S\x00i\x00m\x00p\x00l\x00e\x00P\x00r\x00o\x00j\x00e\x00c\x00t) + +[CustomBuildSystem] +CurrentConfiguration=BuildConfig0 + +[CustomBuildSystem][BuildConfig0] +BuildDir=file:///home/andreas/projects/testcustom/build +Title=mainbuild + +[CustomBuildSystem][BuildConfig0][ToolBuild] +Arguments= +Enabled=false +Environment= +Executable= +Type=0 + +[CustomBuildSystem][BuildConfig0][ToolClean] +Arguments= +Enabled=false +Environment= +Executable= +Type=3 + +[CustomBuildSystem][BuildConfig0][ToolConfigure] +Arguments= +Enabled=false +Environment= +Executable= +Type=1 + +[CustomBuildSystem][BuildConfig0][ToolInstall] +Arguments= +Enabled=false +Environment= +Executable= +Type=2 + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Project] +VersionControlSupport= diff --git a/projectmanagers/custommake/custommakemanager.cpp b/projectmanagers/custommake/custommakemanager.cpp --- a/projectmanagers/custommake/custommakemanager.cpp +++ b/projectmanagers/custommake/custommakemanager.cpp @@ -48,7 +48,7 @@ class CustomMakeProvider : public IDefinesAndIncludesManager::BackgroundProvider { public: - CustomMakeProvider(CustomMakeManager* manager) + explicit CustomMakeProvider(CustomMakeManager* manager) : m_customMakeManager(manager) , m_resolver(new MakeFileResolver()) {} diff --git a/projectmanagers/custommake/makefileresolver/makefileresolver.h b/projectmanagers/custommake/makefileresolver/makefileresolver.h --- a/projectmanagers/custommake/makefileresolver/makefileresolver.h +++ b/projectmanagers/custommake/makefileresolver/makefileresolver.h @@ -31,7 +31,7 @@ struct PathResolutionResult { - PathResolutionResult(bool success = false, const QString& errorMessage = QString(), const QString& longErrorMessage = QString()); + explicit PathResolutionResult(bool success = false, const QString& errorMessage = QString(), const QString& longErrorMessage = QString()); bool success; QString errorMessage; @@ -73,6 +73,8 @@ void enableMakeResolution(bool enable); PathResolutionResult processOutput(const QString& fullOutput, const QString& workingDirectory) const; + static QRegularExpression defineRegularExpression(); + private: PathResolutionResult resolveIncludePath( const QString& file, const QString& workingDirectory, int maxStepsUp = 20 ); diff --git a/projectmanagers/custommake/makefileresolver/makefileresolver.cpp b/projectmanagers/custommake/makefileresolver/makefileresolver.cpp --- a/projectmanagers/custommake/makefileresolver/makefileresolver.cpp +++ b/projectmanagers/custommake/makefileresolver/makefileresolver.cpp @@ -168,7 +168,7 @@ class SourcePathInformation { public: - SourcePathInformation(const QString& path) + explicit SourcePathInformation(const QString& path) : m_path(path) , m_isUnsermake(false) , m_shouldTouchFiles(false) @@ -662,7 +662,7 @@ return ret; } -static QRegularExpression defineRegularExpression() +QRegularExpression MakeFileResolver::defineRegularExpression() { static const QRegularExpression pattern( "-D([^\\s=]+)(?:=(?:\"(.*?)(? statements; }; diff --git a/projectmanagers/qmake/parser/qmakedebugvisitor.h b/projectmanagers/qmake/parser/qmakedebugvisitor.h --- a/projectmanagers/qmake/parser/qmakedebugvisitor.h +++ b/projectmanagers/qmake/parser/qmakedebugvisitor.h @@ -33,7 +33,7 @@ { public: - DebugVisitor(QMake::Parser* parser); + explicit DebugVisitor(QMake::Parser* parser); void visitArgumentList( ArgumentListAst *node ) override; void visitFunctionArguments( FunctionArgumentsAst *node ) override; void visitOrOperator( OrOperatorAst *node ) override; diff --git a/projectmanagers/qmake/parser/tests/assignmenttest.h b/projectmanagers/qmake/parser/tests/assignmenttest.h --- a/projectmanagers/qmake/parser/tests/assignmenttest.h +++ b/projectmanagers/qmake/parser/tests/assignmenttest.h @@ -35,7 +35,7 @@ { Q_OBJECT public: - AssignmentTest( QObject* parent = nullptr ); + explicit AssignmentTest( QObject* parent = nullptr ); ~AssignmentTest() override; private slots: void init(); diff --git a/projectmanagers/qmake/parser/tests/functionscopetest.h b/projectmanagers/qmake/parser/tests/functionscopetest.h --- a/projectmanagers/qmake/parser/tests/functionscopetest.h +++ b/projectmanagers/qmake/parser/tests/functionscopetest.h @@ -37,7 +37,7 @@ { Q_OBJECT public: - FunctionScopeTest( QObject* parent = nullptr ); + explicit FunctionScopeTest( QObject* parent = nullptr ); ~FunctionScopeTest() override; private slots: void init(); diff --git a/projectmanagers/qmake/parser/tests/lexertest.h b/projectmanagers/qmake/parser/tests/lexertest.h --- a/projectmanagers/qmake/parser/tests/lexertest.h +++ b/projectmanagers/qmake/parser/tests/lexertest.h @@ -30,7 +30,7 @@ { Q_OBJECT public: - LexerTest( QObject* parent = nullptr ); + explicit LexerTest( QObject* parent = nullptr ); ~LexerTest() override; private slots: void init(); diff --git a/projectmanagers/qmake/parser/tests/parsetest.h b/projectmanagers/qmake/parser/tests/parsetest.h --- a/projectmanagers/qmake/parser/tests/parsetest.h +++ b/projectmanagers/qmake/parser/tests/parsetest.h @@ -33,7 +33,7 @@ { Q_OBJECT public: - ParseTest( QObject* parent = nullptr ); + explicit ParseTest( QObject* parent = nullptr ); ~ParseTest() override; private slots: void init(); diff --git a/projectmanagers/qmake/parser/tests/scopetest.h b/projectmanagers/qmake/parser/tests/scopetest.h --- a/projectmanagers/qmake/parser/tests/scopetest.h +++ b/projectmanagers/qmake/parser/tests/scopetest.h @@ -37,7 +37,7 @@ { Q_OBJECT public: - ScopeTest( QObject* parent = nullptr ); + explicit ScopeTest( QObject* parent = nullptr ); ~ScopeTest() override; private slots: void init(); diff --git a/projectmanagers/qmake/qmakecache.h b/projectmanagers/qmake/qmakecache.h --- a/projectmanagers/qmake/qmakecache.h +++ b/projectmanagers/qmake/qmakecache.h @@ -28,7 +28,7 @@ class QMakeCache : public QMakeFile { public: - QMakeCache( const QString& cachefile ); + explicit QMakeCache( const QString& cachefile ); void setMkSpecs( QMakeMkSpecs* specs ); bool read() override; private: diff --git a/projectmanagers/qmake/qmakefile.h b/projectmanagers/qmake/qmakefile.h --- a/projectmanagers/qmake/qmakefile.h +++ b/projectmanagers/qmake/qmakefile.h @@ -43,7 +43,7 @@ class QMakeFile : public QMakeVariableResolver { public: - QMakeFile( QString file ); + explicit QMakeFile( QString file ); virtual ~QMakeFile(); virtual bool read(); QString absoluteDir() const; diff --git a/projectmanagers/qmake/qmakeprojectfile.h b/projectmanagers/qmake/qmakeprojectfile.h --- a/projectmanagers/qmake/qmakeprojectfile.h +++ b/projectmanagers/qmake/qmakeprojectfile.h @@ -40,7 +40,7 @@ typedef QPair< QString, QString > DefinePair; static const QStringList FileVariables; - QMakeProjectFile( const QString& projectfile ); + explicit QMakeProjectFile( const QString& projectfile ); ~QMakeProjectFile(); bool read() override; diff --git a/projectmanagers/qmake/tests/test_qmakeproject.h b/projectmanagers/qmake/tests/test_qmakeproject.h --- a/projectmanagers/qmake/tests/test_qmakeproject.h +++ b/projectmanagers/qmake/tests/test_qmakeproject.h @@ -32,7 +32,7 @@ Q_OBJECT public: - TestQMakeProject(QObject* parent = nullptr); + explicit TestQMakeProject(QObject* parent = nullptr); ~TestQMakeProject() override; private slots: diff --git a/providers/ghprovider/ghlineedit.h b/providers/ghprovider/ghlineedit.h --- a/providers/ghprovider/ghlineedit.h +++ b/providers/ghprovider/ghlineedit.h @@ -48,13 +48,10 @@ /// Destructor. ~LineEdit() override; +protected: /// Overridden from QLineEdit. void keyPressEvent(QKeyEvent *e) override; -signals: - /// Emitted when the return key has been pressed. - void returnPressed(); - private slots: /// The timer has timed out: stop it and emit the returnPressed signal. void timeOut(); diff --git a/providers/kdeprovider/kdeprojectsmodel.h b/providers/kdeprovider/kdeprojectsmodel.h --- a/providers/kdeprovider/kdeprojectsmodel.h +++ b/providers/kdeprovider/kdeprojectsmodel.h @@ -48,7 +48,7 @@ class SourceItem : public QStandardItem { public: - SourceItem(const Source& s); + explicit SourceItem(const Source& s); QVariant data(int role = Qt::UserRole + 1) const override; private: diff --git a/providers/kdeprovider/kdeproviderwidget.h b/providers/kdeprovider/kdeproviderwidget.h --- a/providers/kdeprovider/kdeproviderwidget.h +++ b/providers/kdeprovider/kdeproviderwidget.h @@ -31,7 +31,7 @@ { Q_OBJECT public: - KDEProviderWidget(QWidget* parent = nullptr); + explicit KDEProviderWidget(QWidget* parent = nullptr); KDevelop::VcsJob* createWorkingCopy(const QUrl &destinationDirectory) override; bool isCorrect() const override; diff --git a/providers/kdeprovider/kdeproviderwidget.cpp b/providers/kdeprovider/kdeproviderwidget.cpp --- a/providers/kdeprovider/kdeproviderwidget.cpp +++ b/providers/kdeprovider/kdeproviderwidget.cpp @@ -41,9 +41,9 @@ KDEProviderWidget::KDEProviderWidget(QWidget* parent) : IProjectProviderWidget(parent) { - setLayout(new QVBoxLayout()); + setLayout(new QVBoxLayout); m_projects = new QListView(this); - QHBoxLayout* topLayout = new QHBoxLayout(this); + QHBoxLayout* topLayout = new QHBoxLayout; KFilterProxySearchLine* filterLine = new KFilterProxySearchLine(this); KDEProjectsModel* model = new KDEProjectsModel(this); KDEProjectsReader* reader = new KDEProjectsReader(model, model); diff --git a/release-scripts/update-versions.sh b/release-scripts/update-versions.sh --- a/release-scripts/update-versions.sh +++ b/release-scripts/update-versions.sh @@ -1,26 +1,27 @@ -#!/usr/bin/env fish +#!/bin/bash -set MAJOR_VERSION 5 -set MINOR_VERSION 0 -set PATCH_VERSION 80 -set BRANCH 5.1 +set -x -function do_replace - git checkout $BRANCH - sed -i "s/set(.*$argv""_VERSION_MAJOR .*)/set($argv""_VERSION_MAJOR $MAJOR_VERSION)/g" CMakeLists.txt - sed -i "s/set(.*$argv""_VERSION_MINOR .*)/set($argv""_VERSION_MINOR $MINOR_VERSION)/g" CMakeLists.txt - sed -i "s/set(.*$argv""_VERSION_PATCH .*)/set($argv""_VERSION_PATCH $PATCH_VERSION)/g" CMakeLists.txt - git diff - git commit -a -m "Update version number to $MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION" - git push --set-upstream origin $BRANCH -end +MAJOR_VERSION=5 +MINOR_VERSION=1 +PATCH_VERSION=40 +BRANCH=master -cs kdev-python -do_replace KDEVPYTHON -cs kdev-php -do_replace KDEVPHP -cs kdevelop -do_replace KDEVELOP -cs kdevplatform -do_replace KDEVPLATFORM +do_replace() { + local project=$1 + echo $MINOR_VERSION + + git checkout $BRANCH + sed -i -e "s/set(.*${project}_VERSION_MAJOR .*)/set(${project}_VERSION_MAJOR $MAJOR_VERSION)/g" CMakeLists.txt + sed -i -e "s/set(.*${project}_VERSION_MINOR .*)/set(${project}_VERSION_MINOR $MINOR_VERSION)/g" CMakeLists.txt + sed -i -e "s/set(.*${project}_VERSION_PATCH .*)/set(${project}_VERSION_PATCH $PATCH_VERSION)/g" CMakeLists.txt + git diff CMakeLists.txt + git commit CMakeLists.txt -m "Update version number to $MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION" + git push origin $BRANCH +} + +(cd kdevplatform; do_replace KDEVPLATFORM) +(cd kdevelop; do_replace KDEVELOP) +(cd kdev-python; do_replace KDEVPYTHON) +(cd kdev-php; do_replace KDEVPHP) diff --git a/utils/okteta/oktetadocument.cpp b/utils/okteta/oktetadocument.cpp --- a/utils/okteta/oktetadocument.cpp +++ b/utils/okteta/oktetadocument.cpp @@ -59,9 +59,10 @@ { OktetaDocument::OktetaDocument( const QUrl &url , ICore* core ) - : Sublime::UrlDocument( core->uiController()->controller(), url ), - IDocument( core ), - mByteArrayDocument( nullptr ) + : Sublime::UrlDocument( core->uiController()->controller(), url ) + , IDocument( core ) + , mPlugin( nullptr ) + , mByteArrayDocument( nullptr ) { } @@ -191,6 +192,8 @@ void OktetaDocument::activate( Sublime::View* view, KParts::MainWindow* mainWindow ) { + Q_UNUSED(view); + Q_UNUSED(mainWindow); notifyActivated(); } @@ -201,6 +204,8 @@ Sublime::View* OktetaDocument::newView( Sublime::Document* document ) { + Q_UNUSED(document); + if( mByteArrayDocument == nullptr ) { Kasten::ByteArrayRawFileSynchronizerFactory* synchronizerFactory = @@ -210,7 +215,7 @@ Kasten::AbstractLoadJob* loadJob = synchronizer->startLoad( url() ); connect( loadJob, &Kasten::AbstractLoadJob::documentLoaded, this, &OktetaDocument::onByteArrayDocumentLoaded ); - const bool syncSucceeded = Kasten::JobManager::executeJob( loadJob ); + Kasten::JobManager::executeJob( loadJob ); delete synchronizerFactory; }