[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdev-clang/wip/maciej/tooling] refactoring: Move all refactoring actions to background
From:       Maciej Poleski <d82ks8djf82msd83hf8sc02lqb5gh5 () gmail ! com>
Date:       2015-08-01 1:16:58
Message-ID: E1ZLLQ2-0003gw-GS () scm ! kde ! org
[Download RAW message or body]

Git commit cf1679ce62ea927e4c1f006d477bd0a1577708bf by Maciej Poleski.
Committed on 01/08/2015 at 01:16.
Pushed by mpoleski into branch 'wip/maciej/tooling'.

Move all refactoring actions to background

By the way remove old interface.h

M  +0    -1    refactoring/CMakeLists.txt
C  +26   -18   refactoring/actionwatcher.cpp [from: refactoring/kdevrefactorings.cpp \
- 053% similarity] C  +23   -12   refactoring/actionwatcher.h [from: \
refactoring/nooprefactoring.cpp - 064% similarity] M  +22   -7    \
refactoring/changesignaturerefactoring.cpp M  +11   -0    \
refactoring/changesignaturerefactoring.h M  +20   -11   \
refactoring/contextmenumutator.cpp M  +1    -1    \
refactoring/declarationcomparator.cpp M  +0    -1    refactoring/documentcache.cpp
M  +12   -6    refactoring/encapsulatefieldrefactoring.cpp
D  +0    -117  refactoring/interface.cpp
D  +0    -152  refactoring/interface.h
M  +0    -1    refactoring/kdevrefactorings.cpp
M  +0    -1    refactoring/kdevrefactorings.h
M  +1    -1    refactoring/nooprefactoring.cpp
M  +38   -3    refactoring/refactoring.cpp
M  +14   -7    refactoring/refactoring.h
M  +21   -0    refactoring/refactoringcontext.cpp
M  +11   -4    refactoring/refactoringcontext.h
M  +25   -15   refactoring/renamefielddeclrefactoring.cpp
M  +8    -0    refactoring/renamefielddeclrefactoring.h
M  +30   -17   refactoring/renamefielddeclturefactoring.cpp
M  +8    -0    refactoring/renamefielddeclturefactoring.h
M  +15   -17   refactoring/renamevardeclrefactoring.cpp

http://commits.kde.org/kdev-clang/cf1679ce62ea927e4c1f006d477bd0a1577708bf

diff --git a/refactoring/CMakeLists.txt b/refactoring/CMakeLists.txt
index c9b7e90..f916151 100644
--- a/refactoring/CMakeLists.txt
+++ b/refactoring/CMakeLists.txt
@@ -2,7 +2,6 @@
 set(CMAKE_AUTOUIC ON)
 
 set(SRCS
-    interface.cpp
     utils.cpp
     documentcache.cpp
     refactoring.cpp
diff --git a/refactoring/kdevrefactorings.cpp b/refactoring/actionwatcher.cpp
similarity index 53%
copy from refactoring/kdevrefactorings.cpp
copy to refactoring/actionwatcher.cpp
index 07ad6b6..9ac24fa 100644
--- a/refactoring/kdevrefactorings.cpp
+++ b/refactoring/actionwatcher.cpp
@@ -19,32 +19,40 @@
     Boston, MA 02110-1301, USA.
 */
 
-// KDevelop
-#include <language/interfaces/editorcontext.h>
+#include <QAction>
 
-#include "kdevrefactorings.h"
-#include "refactoringcontext.h"
-#include "refactoringmanager.h"
-
-#include "../clangsupport.h"
+#include "actionwatcher.h"
+#include "debug.h"
 
+ActionWatcher::ActionWatcher(QAction *action)
+    : QObject(action)
+{
+    registerAssociatedWidgets();
+}
 
-using namespace KDevelop;
-using namespace Refactorings;
+QAction *ActionWatcher::parent()
+{
+    return static_cast<QAction *>(QObject::parent());
+}
 
-KDevRefactorings::KDevRefactorings(ClangSupport *parent)
-    : QObject(parent)
-    , m_refactoringsContext(new RefactoringContext(this))
-    , m_refactoringManager(new RefactoringManager(this))
+void ActionWatcher::decreaseCount()
 {
+    m_count--;
+    if (m_count == 0) {
+        registerAssociatedWidgets();
+    }
 }
 
-void KDevRefactorings::fillContextMenu(ContextMenuExtension &extension, Context \
*context) +void ActionWatcher::registerAssociatedWidgets()
 {
-    if (EditorContext *ctx = dynamic_cast<EditorContext *>(context)) {
-        m_refactoringManager->fillContextMenu(extension, ctx);
+    // Consider watching for ActionEvents - action may be removed from widget before \
destruction +    const auto &widgets = parent()->associatedWidgets();
+    m_count = widgets.count();
+    if (m_count == 0) {
+        parent()->deleteLater();
     } else {
-        // I assume the above works anytime we ask for context menu for code
-        Q_ASSERT(!context->hasType(Context::CodeContext));
+        for (QWidget *w : widgets) {
+            connect(w, &QObject::destroyed, this, &ActionWatcher::decreaseCount);
+        }
     }
 }
diff --git a/refactoring/nooprefactoring.cpp b/refactoring/actionwatcher.h
similarity index 64%
copy from refactoring/nooprefactoring.cpp
copy to refactoring/actionwatcher.h
index c62bece..6a12985 100644
--- a/refactoring/nooprefactoring.cpp
+++ b/refactoring/actionwatcher.h
@@ -19,20 +19,31 @@
     Boston, MA 02110-1301, USA.
 */
 
-#include "nooprefactoring.h"
+#ifndef KDEV_CLANG_QACTIONWATCHER_H
+#define KDEV_CLANG_QACTIONWATCHER_H
 
-#include "documentcache.h"
+#include <QObject>
 
-#include "../util/clangdebug.h"
+class QAction;
 
-QString NoopRefactoring::name() const
+/**
+ * Watches associated widgets and deletes action when last associated widget is \
destroyed + */
+class ActionWatcher : public QObject
 {
-    return QStringLiteral("do nothing");
-}
+    Q_OBJECT;
+    Q_DISABLE_COPY(ActionWatcher);
+public:
+    ActionWatcher(QAction *action);
 
-llvm::ErrorOr<clang::tooling::Replacements> \
                NoopRefactoring::invoke(RefactoringContext *ctx)
-{
-    Q_UNUSED(ctx);
-    clangDebug() << "Did nothing (dummy refactoring action)";
-    return clang::tooling::Replacements();
-}
\ No newline at end of file
+private:
+    QAction *parent();
+    void decreaseCount();
+    void registerAssociatedWidgets();
+
+private:
+    int m_count;
+};
+
+
+#endif //KDEV_CLANG_QACTIONWATCHER_H
diff --git a/refactoring/changesignaturerefactoring.cpp \
b/refactoring/changesignaturerefactoring.cpp index 94bf79f..965c6e0 100644
--- a/refactoring/changesignaturerefactoring.cpp
+++ b/refactoring/changesignaturerefactoring.cpp
@@ -79,7 +79,7 @@ private:
 
 ChangeSignatureRefactoring::ChangeSignatureRefactoring(const FunctionDecl \
*functionDecl)  : Refactoring(nullptr)
-      , m_infoPack(InfoPack::fromFunctionDecl(functionDecl))
+    , m_infoPack(InfoPack::fromFunctionDecl(functionDecl))
 {
 }
 
@@ -94,24 +94,39 @@ llvm::ErrorOr<clang::tooling::Replacements> \
ChangeSignatureRefactoring::invoke(  return cancelledResult();
     }
 
-    auto &tool = ctx->cache->refactoringTool();
+    auto infoPack = dialog->infoPack(); // C++14...
+    auto changePack = dialog->changePack();
+    return ctx->scheduleRefactoring(
+        [infoPack, changePack](RefactoringTool &tool)
+        {
+            Refactorings::ChangeSignature::run(infoPack, changePack, tool);
+            return tool.getReplacements();
+        }
+    );
+}
 
+namespace Refactorings
+{
+namespace ChangeSignature
+{
+int run(const InfoPack *infoPack, const ChangePack *changePack, RefactoringTool \
&tool) +{
     auto declRefExprMatcher = declRefExpr(to(functionDecl())).bind("DeclRefExpr");
     auto memberExprMatcher = memberExpr().bind("MemberExpr");
     auto functionDeclMatcher = functionDecl().bind("FunctionDecl");
     auto functionCallMatcher = callExpr().bind("CallExpr");
 
-    Translator translator(&m_infoPack->declarationComparator(), dialog->infoPack(),
-                          dialog->changePack(), tool.getReplacements());
+    Translator translator(&infoPack->declarationComparator(), infoPack, changePack,
+                          tool.getReplacements());
     MatchFinder finder;
     finder.addMatcher(declRefExprMatcher, &translator);
     finder.addMatcher(memberExprMatcher, &translator);
     finder.addMatcher(functionDeclMatcher, &translator);
     finder.addMatcher(functionCallMatcher, &translator);
 
-    tool.run(newFrontendActionFactory(&finder).get());
-
-    return tool.getReplacements();
+    return tool.run(newFrontendActionFactory(&finder).get());
+}
+}
 }
 
 QString ChangeSignatureRefactoring::name() const
diff --git a/refactoring/changesignaturerefactoring.h \
b/refactoring/changesignaturerefactoring.h index 36098e1..3e0488b 100644
--- a/refactoring/changesignaturerefactoring.h
+++ b/refactoring/changesignaturerefactoring.h
@@ -48,5 +48,16 @@ private:
     std::unique_ptr<const InfoPack> m_infoPack;
 };
 
+namespace Refactorings
+{
+namespace ChangeSignature
+{
+using InfoPack = ChangeSignatureRefactoring::InfoPack;
+using ChangePack = ChangeSignatureRefactoring::ChangePack;
+
+int run(const InfoPack *infoPack, const ChangePack *changePack,
+        clang::tooling::RefactoringTool &tool);
+}
+}
 
 #endif //KDEV_CLANG_CHANGESIGNATUREREFACTORING_H
diff --git a/refactoring/contextmenumutator.cpp b/refactoring/contextmenumutator.cpp
index 5264a42..bb8f556 100644
--- a/refactoring/contextmenumutator.cpp
+++ b/refactoring/contextmenumutator.cpp
@@ -30,11 +30,18 @@
 #include <interfaces/contextmenuextension.h>
 #include <language/interfaces/editorcontext.h>
 
+// Clang
+#include <clang/Tooling/Core/Replacement.h>
+
 #include "contextmenumutator.h"
 #include "refactoringmanager.h"
 #include "kdevrefactorings.h"
 #include "actionwatcher.h"
+#include "refactoringcontext.h"
+#include "utils.h"
 
+using namespace clang;
+using namespace clang::tooling;
 using namespace KDevelop;
 
 ContextMenuMutator::ContextMenuMutator(ContextMenuExtension &extension, \
RefactoringManager *parent) @@ -89,21 +96,23 @@ QWidget \
*ContextMenuMutator::menuForWidget(QWidget *widget)  void \
ContextMenuMutator::endFillingContextMenu(const QVector<Refactoring *> &refactorings) \
{  QList<QAction *> actions;
-    auto refactoringContext = parent()->parent()->refactoringContext();
+    auto ctx = parent()->parent()->refactoringContext();
     for (auto refactorAction : refactorings) {
         QAction *action = new QAction(refactorAction->name(), parent());
         refactorAction->setParent(action);  // delete as necessary
-        connect(action, &QAction::triggered, [this, refactoringContext, \
refactorAction]() +        connect(action, &QAction::triggered, [this, ctx, \
refactorAction]()  {
-            // TODO: don't use refactorThis
-            auto changes = Refactorings::refactorThis(refactoringContext, \
                refactorAction,
-                                                      {}, {});
-            // FIXME:
-            // use background thread
-            // ... provided with ability to show GUI
-            // show busy indicator
-
-            changes.applyAllChanges();
+            auto result = refactorAction->invoke(ctx);
+            if (!result) {
+                ctx->reportError(result.getError());
+            }
+            auto changes = toDocumentChangeSet(result.get(), ctx->cache,
+                                               \
ctx->cache->refactoringTool().getFiles()); +            if (!changes) {
+                ctx->reportError(changes.getError());
+            } else {
+                changes.get().applyAllChanges();
+            }
         });
         actions.push_back(action);
     }
diff --git a/refactoring/declarationcomparator.cpp \
b/refactoring/declarationcomparator.cpp index 5bec32b..957e694 100644
--- a/refactoring/declarationcomparator.cpp
+++ b/refactoring/declarationcomparator.cpp
@@ -21,4 +21,4 @@
 
 #include "declarationcomparator.h"
 
-DeclarationComparator::~DeclarationComparator() = default;
\ No newline at end of file
+DeclarationComparator::~DeclarationComparator() = default;
diff --git a/refactoring/documentcache.cpp b/refactoring/documentcache.cpp
index 2fae5b7..e8c1016 100644
--- a/refactoring/documentcache.cpp
+++ b/refactoring/documentcache.cpp
@@ -28,7 +28,6 @@
 
 #include "refactoringcontext.h"
 #include "utils.h"
-#include "interface.h"
 #include "../util/clangdebug.h"
 
 using namespace KDevelop;
diff --git a/refactoring/encapsulatefieldrefactoring.cpp \
b/refactoring/encapsulatefieldrefactoring.cpp index 4fb397f..6f137a5 100644
--- a/refactoring/encapsulatefieldrefactoring.cpp
+++ b/refactoring/encapsulatefieldrefactoring.cpp
@@ -102,12 +102,18 @@ llvm::ErrorOr<clang::tooling::Replacements> \
EncapsulateFieldRefactoring::invoke(  return cancelledResult();
     }
 
-    auto &tool = ctx->cache->refactoringTool();
-
-    Refactorings::EncapsulateField::run(tool, m_changePack.get(), &m_declDispatcher,
-                                        &m_recordDeclDispatcher, m_recordName);
-
-    return tool.getReplacements();
+    const ChangePack *changePack = m_changePack.get(); // C++14...
+    auto declDispatcher = m_declDispatcher;
+    auto recordDeclDispatcher = m_recordDeclDispatcher;
+    auto recordName = m_recordName;
+    return ctx->scheduleRefactoring(
+        [changePack, declDispatcher, recordDeclDispatcher, \
recordName](RefactoringTool &tool) +        {
+            Refactorings::EncapsulateField::run(tool, changePack, &declDispatcher,
+                                                &recordDeclDispatcher, recordName);
+            return tool.getReplacements();
+        }
+    );
 }
 
 namespace Refactorings
diff --git a/refactoring/interface.cpp b/refactoring/interface.cpp
deleted file mode 100644
index 63379bc..0000000
--- a/refactoring/interface.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-    This file is part of KDevelop
-
-    Copyright 2015 Maciej Poleski <d82ks8djf82msd83hf8sc02lqb5gh5@gmail.com>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public License
-    along with this library; see the file COPYING.LIB.  If not, write to
-    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-    Boston, MA 02110-1301, USA.
-*/
-
-#include "interface.h"
-
-// KF5
-#include <KI18n/klocalizedstring.h>
-
-// Clang
-#include <clang/Tooling/Refactoring.h>
-
-#include "utils.h"
-#include "refactoringcontext.h"
-#include "documentcache.h"
-#include "refactoringinfo.h"
-
-#include "nooprefactoring.h"
-#include "renamevardeclrefactoring.h"
-
-#include "../util/clangdebug.h"
-
-namespace Refactorings
-{
-
-//////////////////////// Compilation Database
-
-// Maybe skip this opaque pointer? (but would leak details...)
-struct CompilationDatabase_t
-{
-    std::unique_ptr<clang::tooling::CompilationDatabase> database;
-};
-
-CompilationDatabase createCompilationDatabase(const std::string &buildPath, \
                ProjectKind kind,
-                                              QString &errorMessage)
-{
-    if (kind != ProjectKind::CMAKE) {
-        errorMessage = i18n("Only CMake projects are supported for now");
-        return nullptr;
-    }
-    auto result = makeCompilationDatabaseFromCMake(buildPath, errorMessage);
-    if (result == nullptr) {
-        return nullptr;
-    }
-    return new CompilationDatabase_t{std::move(result)};
-};
-
-CompilationDatabase createCMakeCompilationDatabase(const std::string &buildPath)
-{
-    QString error;  // ignored, required by Clang API
-    auto cd = makeCompilationDatabaseFromCMake(buildPath, error);
-    if (cd == nullptr) {
-        return nullptr;
-    } else {
-        return new CompilationDatabase_t{std::move(cd)};
-    }
-}
-
-void releaseCompilationDatabase(CompilationDatabase db)
-{
-    delete db;
-}
-
-///////////////// Refactoring Context
-
-KDevelop::DocumentChangeSet refactorThis(RefactoringsContext rc, RefactoringKind \
                refactoringKind,
-                                         const QUrl &sourceFile,
-                                         const KTextEditor::Cursor &position)
-{
-    Q_ASSERT(rc);
-    Refactoring *refactoring = dynamic_cast<Refactoring *>(refactoringKind);
-    Q_ASSERT(refactoring);
-    // FIXME: introduce RefactoringManager to maintain pool of refactorings and such \
                translations
-
-    auto result = refactoring->invoke(rc);
-    // TODO: introduce union type for {Location, What}
-
-    if (!result) {
-        // TODO: notify
-        clangDebug() << "Refactoring failed: " << \
                result.getError().message().c_str();
-        return KDevelop::DocumentChangeSet();
-    }
-
-    auto changes = toDocumentChangeSet(result.get(), rc->cache, \
                rc->cache->refactoringTool().getFiles());
-    if (!changes) {
-        // TODO: notify
-        clangDebug() << "Translation Replacements to DocumentChangeSet failed " <<
-                     result.getError().message().c_str();
-        return KDevelop::DocumentChangeSet();
-    }
-    return changes.get();
-}
-
-// TODO: consider removing this function
-std::vector<std::string> sources(CompilationDatabase db)
-{
-    return db->database->getAllFiles();
-}
-
-};
diff --git a/refactoring/interface.h b/refactoring/interface.h
deleted file mode 100644
index 5ba386b..0000000
--- a/refactoring/interface.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-    This file is part of KDevelop
-
-    Copyright 2015 Maciej Poleski <d82ks8djf82msd83hf8sc02lqb5gh5@gmail.com>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library 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
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public License
-    along with this library; see the file COPYING.LIB.  If not, write to
-    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-    Boston, MA 02110-1301, USA.
-*/
-
-// This header file should be independent of any Clang libraries both
-// compile time and run time.
-// All of refactorings features will be accessible from here
-
-#ifndef KDEV_CLANG_INTERFACE_H
-#define KDEV_CLANG_INTERFACE_H
-
-// C++
-#include <vector>
-#include <string>
-#include <unordered_map>
-
-// Qt
-#include <QUrl>
-#include <QString>
-
-// KF5
-#include <KTextEditor/ktexteditor/cursor.h>
-
-// KDevelop
-#include <language/codegen/documentchangeset.h>
-
-namespace KDevelop
-{
-class IDocumentController;
-};
-
-class RefactoringInfo;
-class RefactoringContext;
-
-namespace Refactorings
-{
-
-struct CompilationDatabase_t;
-struct RefactoringsContext_t;
-
-// All std::strings appearing here may be replaced to something different
-// if necessary (QString, QUrl, ...)
-// All functions provided here get C linkage. These (few) functions as designed
-// to provide interoperability with KDevelop based on stable, predictable ABI.
-// It can bu used later to dlopen implementation, or as "engine" in standalone
-// executable.
-// Note: some types are not fully known now. typedefs will change soon
-
-
-// CompilationDatabase will be used internally, but needs initialization
-typedef CompilationDatabase_t *CompilationDatabase;
-
-// All data which can be required for any operation of this library.
-// It is CompilationDatabase, ClangTool (with virtual files), ...
-typedef RefactoringContext *RefactoringsContext;
-
-// Short information about one particular kind of refactoring.
-typedef RefactoringInfo *RefactoringKind;
-
-enum class ProjectKind
-{
-    CMAKE,      // CMake project are already nice
-    NON_CMAKE,  // Non CMake are nice after use of Bear
-};  // Where "nice" means prepared compile_commands.json file
-
-/**
- * Prepares and returns compilation database for given project build path.
- * Note: result of this operation is deprecated by any change in project
- * structure (adding new file, removing, renaming, changing flags, ...).
- * In such a case new object must be created using this function.
- *
- * @param buildPath build path for given project (ex. CMAKE_BINARY_DIR)
- * @param kind CMAKE if underlying project is a configured CMake project
- *             with CMAKE_EXPORT_COMPILE_COMMANDS enabled, NON_CMAKE otherwise
- * @param errorMessage will be set to error message if any occurred
- * @return Compilation database for given project
- */
-CompilationDatabase createCompilationDatabase(const std::string &buildPath, \
                ProjectKind kind,
-                                              QString &errorMessage);
-
-/**
- * Simpler version of the above only for CMake projects as requested in
- * https://git.reviewboard.kde.org/r/123963/#comment55684 and
- * https://git.reviewboard.kde.org/r/123963/#comment55548
- *
- * @return nullptr on error
- */
-CompilationDatabase createCMakeCompilationDatabase(const std::string &buildPath);
-
-/**
- * Frees resources used by given compilation database.
- * NOTE: You mustn't release database given to @c createRefactoringsContext
- * as that function takes ownership of compilation database.
- *
- * @param db compilation database to be released
- */
-void releaseCompilationDatabase(CompilationDatabase db);
-
-// TODO: mergeCompilationDatabases - handle refactorings between projects
-
-/**
- * Returns list of all sources from given CompilationDatabase
- *
- * @note: dedicated to provide @c sources for @c createRefactoringsContext
- */
-std::vector<std::string> sources(CompilationDatabase db);
-
-/**
- * Invokes selected refactoring action on selected place in file.
- *
- * @param rc Initialized refactorings context
- * @param refactoring A refactoring kind we are going to apply here
- * @param sourceFile source file name (full path)
- * @param position position in source file which we are going to work on
- */
-KDevelop::DocumentChangeSet refactorThis(RefactoringsContext rc, RefactoringKind \
                refactoring,
-                                         const QUrl &sourceFile,
-                                         const KTextEditor::Cursor &position);
-// NOTE: We have to cooperate with cache here (it is guaranteed that sourceFile is \
                in cache,
-// as this file is already opened). Maybe it is more reasonable to provide Document* \
                here?
-// Especially when DocumentCache middleware will be IDocumentController aware.
-// NOTE: position (Cursor) is not nice - will need translation to offset.
-// NOTE: We are going to need some GUI handle here. Probably something like QWidget* \
                parent
-// will be introduced as additional parameter (but it will bind this interface to Qt \
                Widgets).
-// NOTE: Can we block calling thread? I would say no. We are going to need Qt \
                wrapper/continuation
-// here.
-
-
-// TODO: refactorThis(RefactoringsContext, RefactoringKind, Location, ...)
-// TODO: refactor(RefactoringsContext, RefactoringKind, What, ...)
-// ^^^^ will return DocumentChangeSet
-
-};
-
-#endif //KDEV_CLANG_INTERFACE_H
diff --git a/refactoring/kdevrefactorings.cpp b/refactoring/kdevrefactorings.cpp
index 07ad6b6..42e3d20 100644
--- a/refactoring/kdevrefactorings.cpp
+++ b/refactoring/kdevrefactorings.cpp
@@ -30,7 +30,6 @@
 
 
 using namespace KDevelop;
-using namespace Refactorings;
 
 KDevRefactorings::KDevRefactorings(ClangSupport *parent)
     : QObject(parent)
diff --git a/refactoring/kdevrefactorings.h b/refactoring/kdevrefactorings.h
index f44d68d..d906854 100644
--- a/refactoring/kdevrefactorings.h
+++ b/refactoring/kdevrefactorings.h
@@ -34,7 +34,6 @@
 #include <interfaces/context.h>
 #include <interfaces/iproject.h>
 
-#include "interface.h"
 #include "refactoring.h"
 
 class ClangSupport;
diff --git a/refactoring/nooprefactoring.cpp b/refactoring/nooprefactoring.cpp
index c62bece..abd32ef 100644
--- a/refactoring/nooprefactoring.cpp
+++ b/refactoring/nooprefactoring.cpp
@@ -35,4 +35,4 @@ llvm::ErrorOr<clang::tooling::Replacements> \
NoopRefactoring::invoke(RefactoringC  Q_UNUSED(ctx);
     clangDebug() << "Did nothing (dummy refactoring action)";
     return clang::tooling::Replacements();
-}
\ No newline at end of file
+}
diff --git a/refactoring/refactoring.cpp b/refactoring/refactoring.cpp
index 3644bfc..d529e7e 100644
--- a/refactoring/refactoring.cpp
+++ b/refactoring/refactoring.cpp
@@ -19,16 +19,51 @@
     Boston, MA 02110-1301, USA.
 */
 
+// Qt
+#include <QDialog>
+#include <QLabel>
+#include <QVBoxLayout>
+
+// KF5
+#include <KLocalizedString>
+
+// Clang
 #include <clang/Tooling/Core/Replacement.h>
 
 #include "refactoring.h"
 
+using namespace clang;
+using namespace clang::tooling;
+
 Refactoring::Refactoring(QObject *parent)
     : QObject(parent)
 {
 }
 
-llvm::ErrorOr<clang::tooling::Replacements> Refactoring::cancelledResult()
+llvm::ErrorOr<Replacements> Refactoring::cancelledResult()
+{
+    return Replacements{};
+}
+
+QDialog *Refactoring::newBusyDialog()
 {
-    return clang::tooling::Replacements{};
-}
\ No newline at end of file
+    // Very simple placeholder
+    // TODO: progress bar and cancel button (this is not trivial task!)
+    QDialog *result = new QDialog();
+    QVBoxLayout *layout = new QVBoxLayout();
+    QLabel *label = new QLabel(i18n("Refactoring..."));
+    layout->addWidget(label);
+    result->setLayout(layout);
+    return result;
+}
+
+std::function<void(Replacements)> Refactoring::uiLockerCallback(QDialog *uiLocker,
+                                                                Replacements \
&result) +{
+    return [uiLocker, &result](Replacements repl)
+    {
+        result = std::move(repl);
+        uiLocker->accept();
+        // TODO: dialog probably can be closed anyway, detect and clear replacements
+    };
+}
diff --git a/refactoring/refactoring.h b/refactoring/refactoring.h
index caa49a1..3ef8bc7 100644
--- a/refactoring/refactoring.h
+++ b/refactoring/refactoring.h
@@ -22,21 +22,18 @@
 #ifndef KDEV_CLANG_REFACTORING_H
 #define KDEV_CLANG_REFACTORING_H
 
-#include "refactoringinfo.h"
-
 // Qt
 #include <QObject>
-#include <QUrl>
-
-// KF5
-#include <KTextEditor/ktexteditor/cursor.h>
 
 // Clang
 #include <clang/Tooling/Tooling.h>
 #include <clang/Tooling/Core/Replacement.h>
 #include <clang/Tooling/Refactoring.h>
 
-#include "interface.h"
+#include "refactoringinfo.h"
+#include "refactoringcontext.h"
+
+class QDialog;
 
 class DocumentCache;
 
@@ -47,6 +44,10 @@ class Refactoring : public QObject, public RefactoringInfo
 {
     Q_OBJECT;
     Q_DISABLE_COPY(Refactoring);
+
+    friend clang::tooling::Replacements RefactoringContext::scheduleRefactoring(
+        std::function<clang::tooling::Replacements(clang::tooling::RefactoringTool \
&)>); +
     // TODO: interface as needed
 public:
     Refactoring(QObject *parent);
@@ -56,6 +57,12 @@ public:
 
 protected:
     static llvm::ErrorOr<clang::tooling::Replacements> cancelledResult();  // \
Returned on cancel +    // TODO: Returned on interrupt (implement with care!)
+
+    /// GUI placeholder when refactoring action takes place and UI should be blocked
+    static QDialog *newBusyDialog();
+    static std::function<void(clang::tooling::Replacements)> uiLockerCallback(
+        QDialog *uiLocker, clang::tooling::Replacements &result);
 };
 
 
diff --git a/refactoring/refactoringcontext.cpp b/refactoring/refactoringcontext.cpp
index 6ee38ac..472f588 100644
--- a/refactoring/refactoringcontext.cpp
+++ b/refactoring/refactoringcontext.cpp
@@ -19,8 +19,12 @@
     Boston, MA 02110-1301, USA.
 */
 
+// Qt
+#include <QMessageBox>
+
 // KF5
 #include <KJob>
+#include <KLocalizedString>
 
 // KDevelop
 #include <interfaces/icore.h>
@@ -38,6 +42,8 @@
 #include "debug.h"
 
 using namespace KDevelop;
+using namespace clang;
+using namespace clang::tooling;
 
 RefactoringContext::RefactoringContext(KDevRefactorings *parent)
     : QObject(parent)
@@ -67,6 +73,11 @@ llvm::ErrorOr<unsigned> RefactoringContext::offset(const \
                std::string &sourceFile
     return toOffset(sourceFile, position, cache->refactoringTool(), cache);
 }
 
+void RefactoringContext::reportError(const std::error_code &error)
+{
+    QMessageBox::critical(nullptr, i18n("Error occurred"), \
QString::fromStdString(error.message())); +}
+
 void RefactoringContext::projectOpened(IProject *project)
 {
     Q_ASSERT(project);
@@ -106,6 +117,16 @@ void RefactoringContext::projectConfigured(IProject *project)
     refactorDebug() << "RefactoringsContext sucessfully (re)generated!";
 }
 
+Replacements RefactoringContext::scheduleRefactoring(
+    std::function<Replacements(RefactoringTool &)> task)
+{
+    QDialog *uiLocker = Refactoring::newBusyDialog();
+    Replacements result;
+    schedule(task, Refactoring::uiLockerCallback(uiLocker, result));
+    uiLocker->exec();
+    return result;
+}
+
 void RefactoringContext::invokeCallback(std::function<void()> callback)
 {
     callback();
diff --git a/refactoring/refactoringcontext.h b/refactoring/refactoringcontext.h
index ce370b1..0e996f0 100644
--- a/refactoring/refactoringcontext.h
+++ b/refactoring/refactoringcontext.h
@@ -63,10 +63,17 @@ public:
     llvm::ErrorOr<unsigned> offset(const std::string &sourceFile,
                                    const KTextEditor::Cursor &position) const;
 
+    void reportError(const std::error_code &error);
+
     template<typename Task, typename Callback>
     void schedule(Task task, Callback callback);
     template<typename Task, typename Callback>
     void scheduleOnSingleFile(Task task, const std::string &filename, Callback \
callback); +    // Convenience method on top of @c schedule
+    clang::tooling::Replacements scheduleRefactoring(
+        std::function<clang::tooling::Replacements(clang::tooling::RefactoringTool \
&)> task); +
+    // TODO: schedule refactoring (with ui locker, with Replacements as result)
 
 private: // (slots)
     // Only one project for now
@@ -79,7 +86,7 @@ private slots:
 
 private:
     template<typename Task, typename Callback>
-    static std::function<void(clang::tooling::RefactoringTool &,
+    static std::function<void(clang::tooling::RefactoringTool,
                               std::function<void(std::function<void()>)>)> \
composeTask(  Task task, Callback callback);
 
@@ -94,19 +101,19 @@ private:
 Q_DECLARE_METATYPE(std::function<void()>);
 
 template<typename Task, typename Callback>
-std::function<void(clang::tooling::RefactoringTool &,
+std::function<void(clang::tooling::RefactoringTool,
                    std::function<void(std::function<void()>)>)> \
RefactoringContext::composeTask(  Task task, Callback callback)
 {
     return [task, callback](
-        clang::tooling::RefactoringTool &tool,
+        clang::tooling::RefactoringTool tool,
         std::function<void(std::function<void()>)> callbackScheduler)
     {
         auto result = task(tool);
         // By value! (TODO C++14: move result to lambda instead of copying)
         auto callbackInvoker = [callback, result]
         {
-            callback(result);
+            callback(std::move(result));
         };
         callbackScheduler(callbackInvoker);
     };
diff --git a/refactoring/renamefielddeclrefactoring.cpp \
b/refactoring/renamefielddeclrefactoring.cpp index 4e80af9..e1ab321 100644
--- a/refactoring/renamefielddeclrefactoring.cpp
+++ b/refactoring/renamefielddeclrefactoring.cpp
@@ -48,8 +48,8 @@ class Renamer : public MatchFinder::MatchCallback
 public:
     Renamer(const std::string &oldQualName, const std::string &newName, Replacements \
&replacements)  : m_oldQualName(oldQualName)
-          , m_newName(newName)
-          , m_replacements(replacements)
+        , m_newName(newName)
+        , m_replacements(replacements)
     {
     }
 
@@ -74,45 +74,55 @@ private:
 RenameFieldDeclRefactoring::RenameFieldDeclRefactoring(const std::string &oldName,
                                                        std::string oldQualName)
     : Refactoring(nullptr)
-      , m_oldFieldDeclName(oldName)
-      , m_oldQualName(std::move(oldQualName))
+    , m_oldFieldDeclName(oldName)
+    , m_oldQualName(std::move(oldQualName))
 {
 }
 
 llvm::ErrorOr<clang::tooling::Replacements> RenameFieldDeclRefactoring::invoke(
     RefactoringContext *ctx)
 {
-    auto &clangTool = ctx->cache->refactoringTool();
-
     const QString oldName = QString::fromStdString(m_oldFieldDeclName);
     const QString newName = QInputDialog::getText(nullptr, i18n("Rename field"),
                                                   i18n("Type new name of field"),
                                                   QLineEdit::Normal,
                                                   oldName);
     if (newName.isEmpty() || newName == oldName) {
-        return clangTool.getReplacements();
+        return cancelledResult();
     }
 
-    refactorDebug() << "Will rename" << m_oldFieldDeclName << "to:" << newName;
+    auto newNameS = newName.toStdString(); // C++14...
+    auto oldQualName = m_oldQualName;
+    return ctx->scheduleRefactoring(
+        [oldQualName, newNameS](RefactoringTool &tool)
+        {
+            Refactorings::RenameFieldDecl::run(oldQualName, newNameS, tool);
+            return tool.getReplacements();
+        });
+}
 
+namespace Refactorings
+{
+namespace RenameFieldDecl
+{
+int run(const std::string oldQualName, const std::string &newName, RefactoringTool \
&clangTool) +{
     auto memberExprMatcher = memberExpr().bind("MemberExpr");
     auto fieldDeclMatcher = fieldDecl().bind("FieldDecl");
 
-    Renamer renamer(m_oldQualName, newName.toStdString(), \
clangTool.getReplacements()); +    Renamer renamer(oldQualName, newName, \
clangTool.getReplacements());  MatchFinder finder;
     finder.addMatcher(memberExprMatcher, &renamer);
     finder.addMatcher(fieldDeclMatcher, &renamer);
 
-    clangTool.run(tooling::newFrontendActionFactory(&finder).get());
-
-    auto result = clangTool.getReplacements();
-    clangTool.getReplacements().clear();
-    return result;
+    return clangTool.run(tooling::newFrontendActionFactory(&finder).get());
+}
+}
 }
 
 QString RenameFieldDeclRefactoring::name() const
 {
-    return i18n("rename %1").arg(QString::fromStdString(m_oldQualName));
+    return i18n("rename [%1]").arg(QString::fromStdString(m_oldQualName));
 }
 
 void Renamer::run(const MatchFinder::MatchResult &result)
diff --git a/refactoring/renamefielddeclrefactoring.h \
b/refactoring/renamefielddeclrefactoring.h index 32b3a59..a39399d 100644
--- a/refactoring/renamefielddeclrefactoring.h
+++ b/refactoring/renamefielddeclrefactoring.h
@@ -39,5 +39,13 @@ private:
     const std::string m_oldQualName;
 };
 
+namespace Refactorings
+{
+namespace RenameFieldDecl
+{
+int run(const std::string oldQualName, const std::string &newName,
+        clang::tooling::RefactoringTool &clangTool);
+}
+}
 
 #endif //KDEV_CLANG_RENAMEFIELDDECLREFACTORING_H
diff --git a/refactoring/renamefielddeclturefactoring.cpp \
b/refactoring/renamefielddeclturefactoring.cpp index b85024f..dea9198 100644
--- a/refactoring/renamefielddeclturefactoring.cpp
+++ b/refactoring/renamefielddeclturefactoring.cpp
@@ -50,9 +50,9 @@ public:
     Renamer(const std::string &fileName, unsigned offset, const std::string \
&newName,  Replacements &replacements)
         : m_fileName(fileName)
-          , m_fileOffset(offset)
-          , m_newName(newName)
-          , m_replacements(replacements)
+        , m_fileOffset(offset)
+        , m_newName(newName)
+        , m_replacements(replacements)
     {
     }
 
@@ -79,46 +79,59 @@ RenameFieldDeclTURefactoring::RenameFieldDeclTURefactoring(const \
                std::string &fi
                                                            unsigned offset,
                                                            llvm::StringRef oldName)
     : Refactoring(nullptr)
-      , m_fileName(fileName)
-      , m_fileOffset(offset)
-      , m_oldFieldDeclName(oldName)
+    , m_fileName(fileName)
+    , m_fileOffset(offset)
+    , m_oldFieldDeclName(oldName)
 {
 }
 
 llvm::ErrorOr<clang::tooling::Replacements> RenameFieldDeclTURefactoring::invoke(
     RefactoringContext *ctx)
 {
-    auto &clangTool = ctx->cache->refactoringTool();
-
     const QString oldName = QString::fromStdString(m_oldFieldDeclName);
     const QString newName = QInputDialog::getText(nullptr, i18n("Rename field"),
                                                   i18n("Type new name of field"),
                                                   QLineEdit::Normal,
                                                   oldName);
     if (newName.isEmpty() || newName == oldName) {
-        return clangTool.getReplacements();
+        return cancelledResult();
     }
 
-    refactorDebug() << "Will rename" << m_oldFieldDeclName << "to:" << newName;
+    auto fileName = m_fileName; // C++14...
+    auto fileOffset = m_fileOffset;
+    auto newNameS = newName.toStdString();
+    return ctx->scheduleRefactoring(
+        [fileName, fileOffset, newNameS](RefactoringTool &tool)
+        {
+            Refactorings::RenameFieldTuDecl::run(fileName, fileOffset, newNameS, \
tool); +            return tool.getReplacements();
+        }
+    );
+}
 
+namespace Refactorings
+{
+namespace RenameFieldTuDecl
+{
+int run(const std::string fileName, unsigned fileOffset, const std::string &newName,
+        clang::tooling::RefactoringTool &clangTool)
+{
     auto memberExprMatcher = memberExpr().bind("MemberExpr");
     auto fieldDeclMatcher = fieldDecl().bind("FieldDecl");
 
-    Renamer renamer(m_fileName, m_fileOffset, newName.toStdString(), \
clangTool.getReplacements()); +    Renamer renamer(fileName, fileOffset, newName, \
clangTool.getReplacements());  MatchFinder finder;
     finder.addMatcher(memberExprMatcher, &renamer);
     finder.addMatcher(fieldDeclMatcher, &renamer);
 
-    clangTool.run(tooling::newFrontendActionFactory(&finder).get());
-
-    auto result = clangTool.getReplacements();
-    clangTool.getReplacements().clear();
-    return result;
+    return clangTool.run(tooling::newFrontendActionFactory(&finder).get());
+}
+}
 }
 
 QString RenameFieldDeclTURefactoring::name() const
 {
-    return i18n("rename %1").arg(QString::fromStdString(m_oldFieldDeclName));
+    return i18n("rename [%1]").arg(QString::fromStdString(m_oldFieldDeclName));
 }
 
 void Renamer::run(const MatchFinder::MatchResult &result)
diff --git a/refactoring/renamefielddeclturefactoring.h \
b/refactoring/renamefielddeclturefactoring.h index abc4b8e..6a5cb8b 100644
--- a/refactoring/renamefielddeclturefactoring.h
+++ b/refactoring/renamefielddeclturefactoring.h
@@ -42,5 +42,13 @@ private:
     const std::string m_oldFieldDeclName;
 };
 
+namespace Refactorings
+{
+namespace RenameFieldTuDecl
+{
+int run(const std::string fileName, unsigned fileOffset, const std::string &newName,
+        clang::tooling::RefactoringTool &clangTool);
+}
+}
 
 #endif //KDEV_CLANG_RENAMEFIELDDECLTUREFACTORING_H
diff --git a/refactoring/renamevardeclrefactoring.cpp \
b/refactoring/renamevardeclrefactoring.cpp index efb2661..e49eca7 100644
--- a/refactoring/renamevardeclrefactoring.cpp
+++ b/refactoring/renamevardeclrefactoring.cpp
@@ -19,8 +19,6 @@
     Boston, MA 02110-1301, USA.
 */
 
-#include "renamevardeclrefactoring.h"
-
 // Qt
 #include <QInputDialog>
 
@@ -33,6 +31,7 @@
 #include <clang/ASTMatchers/ASTMatchFinder.h>
 #include <refactoringcontext.h>
 
+#include "renamevardeclrefactoring.h"
 #include "documentcache.h"
 #include "declarationcomparator.h"
 #include "tudecldispatcher.h"
@@ -54,8 +53,8 @@ public:
     Renamer(const DeclarationComparator *declComparator, const string &newName,
             Replacements &replacements)
         : m_declDispatcher(declComparator)
-          , m_newName(newName)
-          , m_replacements(replacements)
+        , m_newName(newName)
+        , m_replacements(replacements)
     {
     }
 
@@ -76,32 +75,31 @@ private:
 RenameVarDeclRefactoring::RenameVarDeclRefactoring(unique_ptr<DeclarationComparator> \
                declComparator,
                                                    const string &declName, QObject \
*parent)  : Refactoring(parent)
-      , m_declComparator(std::move(declComparator))
-      , m_oldVarDeclName(declName)
+    , m_declComparator(std::move(declComparator))
+    , m_oldVarDeclName(declName)
 {
 }
 
-llvm::ErrorOr<clang::tooling::Replacements> RenameVarDeclRefactoring::invoke(
+llvm::ErrorOr<Replacements> RenameVarDeclRefactoring::invoke(
     RefactoringContext *ctx)
 {
-    auto &clangTool = ctx->cache->refactoringTool();
-
     const QString oldName = QString::fromStdString(m_oldVarDeclName);
     const QString newName = QInputDialog::getText(nullptr, i18n("Rename variable"),
                                                   i18n("Type new name of variable"),
                                                   QLineEdit::Normal,
                                                   oldName);
     if (newName.isEmpty() || newName == oldName) {
-        return clangTool.getReplacements();
+        return cancelledResult();
     }
 
-    refactorDebug() << "Will rename" << m_oldVarDeclName << "to:" << newName;
-
-    Refactorings::RenameVarDecl::run(m_declComparator.get(), newName.toStdString(), \
                clangTool);
-
-    auto result = clangTool.getReplacements();
-    clangTool.getReplacements().clear();
-    return result;
+    auto declCmp = m_declComparator.get();
+    auto name = newName.toStdString();
+    return ctx->scheduleRefactoring(
+        [declCmp, name](RefactoringTool &tool)
+        {
+            Refactorings::RenameVarDecl::run(declCmp, name, tool);
+            return tool.getReplacements();
+        });
 }
 
 namespace Refactorings


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic