[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kdev-clang/wip/maciej/tooling] refactoring: Introduced worker thread for time-consuming Clang actio
From: Maciej Poleski <d82ks8djf82msd83hf8sc02lqb5gh5 () gmail ! com>
Date: 2015-08-01 0:57:07
Message-ID: E1ZLL6p-00036k-HX () scm ! kde ! org
[Download RAW message or body]
Git commit 91c0926d27511067330f7b82696c822a0244a6f4 by Maciej Poleski.
Committed on 01/08/2015 at 00:56.
Pushed by mpoleski into branch 'wip/maciej/tooling'.
Introduced worker thread for time-consuming Clang actions. Move populating of context \
menu to background.
M +3 -0 refactoring/CMakeLists.txt
A +117 -0 refactoring/contextmenumutator.cpp [License: LGPL (v2+)]
C +26 -24 refactoring/contextmenumutator.h [from: \
refactoring/refactoringcontext.h - 054% similarity] M +0 -7 \
refactoring/interface.cpp M +0 -8 refactoring/interface.h
M +6 -90 refactoring/kdevrefactorings.cpp
M +8 -9 refactoring/kdevrefactorings.h
M +78 -4 refactoring/refactoringcontext.cpp
M +97 -2 refactoring/refactoringcontext.h
A +68 -0 refactoring/refactoringcontext_worker.cpp [License: LGPL (v2+)]
A +63 -0 refactoring/refactoringcontext_worker.h [License: LGPL (v2+)]
M +31 -11 refactoring/refactoringmanager.cpp
M +19 -17 refactoring/refactoringmanager.h
http://commits.kde.org/kdev-clang/91c0926d27511067330f7b82696c822a0244a6f4
diff --git a/refactoring/CMakeLists.txt b/refactoring/CMakeLists.txt
index 6c96491..c9b7e90 100644
--- a/refactoring/CMakeLists.txt
+++ b/refactoring/CMakeLists.txt
@@ -26,6 +26,9 @@ set(SRCS
encapsulatefieldrefactoring.cpp
encapsulatefielddialog.cpp
encapsulatefieldrefactoring_changepack.cpp
+ refactoringcontext_worker.cpp
+ contextmenumutator.cpp
+ actionwatcher.cpp
)
add_library(kdevclangrefactor STATIC
diff --git a/refactoring/contextmenumutator.cpp b/refactoring/contextmenumutator.cpp
new file mode 100644
index 0000000..5264a42
--- /dev/null
+++ b/refactoring/contextmenumutator.cpp
@@ -0,0 +1,117 @@
+/*
+ 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.
+*/
+
+// Qt
+#include <QAction>
+#include <QMenu>
+
+// KF5
+#include <KF5/KI18n/klocalizedstring.h>
+
+// KDevelop
+#include <interfaces/contextmenuextension.h>
+#include <language/interfaces/editorcontext.h>
+
+#include "contextmenumutator.h"
+#include "refactoringmanager.h"
+#include "kdevrefactorings.h"
+#include "actionwatcher.h"
+
+using namespace KDevelop;
+
+ContextMenuMutator::ContextMenuMutator(ContextMenuExtension &extension, \
RefactoringManager *parent) + : QObject(parent)
+ , m_placeholder(new QAction(i18n("preparing list..."), this))
+{
+ extension.addAction(ContextMenuExtension::RefactorGroup, m_placeholder);
+}
+
+RefactoringManager *ContextMenuMutator::parent()
+{
+ return static_cast<RefactoringManager *>(QObject::parent());
+}
+
+// Create submenu for refactoring actions if necessary and possible
+QWidget *ContextMenuMutator::menuForWidget(QWidget *widget)
+{
+ QMenu * const menu = dynamic_cast<QMenu *>(widget);
+ if (menu) {
+ int sectionSize = 0;
+ bool found = false;
+ for (QAction *a : menu->actions()) {
+ if (!a->isSeparator()) {
+ sectionSize++;
+ if (a == m_placeholder) {
+ found = true;
+ }
+ } else {
+ if (!found) {
+ sectionSize = 0;
+ } else {
+ break;
+ }
+ }
+ }
+ Q_ASSERT(sectionSize > 0);
+ if (sectionSize > 1) {
+ // do nothing
+ return widget;
+ } else {
+ // make submenu
+ QMenu *submenu = new QMenu(i18n("Refactor"), menu);
+ menu->insertMenu(m_placeholder, submenu);
+ return submenu;
+ }
+ } else {
+ // We can't create submenu
+ return widget;
+ }
+}
+
+void ContextMenuMutator::endFillingContextMenu(const QVector<Refactoring *> \
&refactorings) +{
+ QList<QAction *> actions;
+ auto refactoringContext = 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]() + {
+ // 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();
+ });
+ actions.push_back(action);
+ }
+ for (QWidget *w : m_placeholder->associatedWidgets()) {
+ menuForWidget(w)->insertActions(m_placeholder, actions);
+ }
+ for (QAction *a : actions) {
+ new ActionWatcher(a);
+ }
+ deleteLater();
+}
diff --git a/refactoring/refactoringcontext.h b/refactoring/contextmenumutator.h
similarity index 54%
copy from refactoring/refactoringcontext.h
copy to refactoring/contextmenumutator.h
index 91001cb..932e8c3 100644
--- a/refactoring/refactoringcontext.h
+++ b/refactoring/contextmenumutator.h
@@ -19,43 +19,45 @@
Boston, MA 02110-1301, USA.
*/
-#ifndef KDEV_CLANG_REFACTORINGCONTEXT_H
-#define KDEV_CLANG_REFACTORINGCONTEXT_H
+#ifndef KDEV_CLANG_CONTEXTMENUMUTATOR_H
+#define KDEV_CLANG_CONTEXTMENUMUTATOR_H
-// base class
+// Qt
#include <QObject>
-// KF5
-#include <KTextEditor/ktexteditor/cursor.h>
-
-// LLVM
-#include <llvm/Support/ErrorOr.h>
-
-// Clang
-#include <clang/Tooling/CompilationDatabase.h>
+class QAction;
+class QWidget;
namespace KDevelop
{
-class IDocumentController;
-};
+class ContextMenuExtension;
+
+class EditorContext;
+}
-class DocumentCache;
+class RefactoringManager;
-// TODO: join with DocumentCache, handle CompilationDatabase here
-class RefactoringContext : public QObject
+class Refactoring;
+
+class ContextMenuMutator : public QObject
{
Q_OBJECT;
- Q_DISABLE_COPY(RefactoringContext);
-
+ Q_DISABLE_COPY(ContextMenuMutator);
public:
- RefactoringContext(std::unique_ptr<clang::tooling::CompilationDatabase> \
database); + ContextMenuMutator(KDevelop::ContextMenuExtension &extension, \
RefactoringManager *parent); +
+ RefactoringManager *parent();
+
+private:
+ QWidget* menuForWidget(QWidget *widget);
- llvm::ErrorOr<unsigned> offset(const std::string &sourceFile,
- const KTextEditor::Cursor &position) const;
+public slots:
+ void endFillingContextMenu(const QVector<Refactoring *> &refactorings);
- std::unique_ptr<clang::tooling::CompilationDatabase> database;
- DocumentCache *cache;
+private:
+ QAction *m_placeholder;
};
+Q_DECLARE_METATYPE(ContextMenuMutator*);
-#endif //KDEV_CLANG_REFACTORINGCONTEXT_H
+#endif //KDEV_CLANG_CONTEXTMENUMUTATOR_H
diff --git a/refactoring/interface.cpp b/refactoring/interface.cpp
index 96e1260..63379bc 100644
--- a/refactoring/interface.cpp
+++ b/refactoring/interface.cpp
@@ -80,13 +80,6 @@ void releaseCompilationDatabase(CompilationDatabase db)
///////////////// Refactoring Context
-RefactoringsContext createRefactoringsContext(CompilationDatabase db)
-{
- auto result = new RefactoringContext(std::move(db->database));
- releaseCompilationDatabase(db);
- return result;
-}
-
KDevelop::DocumentChangeSet refactorThis(RefactoringsContext rc, RefactoringKind \
refactoringKind, const QUrl &sourceFile,
const KTextEditor::Cursor &position)
diff --git a/refactoring/interface.h b/refactoring/interface.h
index 4c4fb3b..5ba386b 100644
--- a/refactoring/interface.h
+++ b/refactoring/interface.h
@@ -123,14 +123,6 @@ void releaseCompilationDatabase(CompilationDatabase db);
std::vector<std::string> sources(CompilationDatabase db);
/**
- * Prepare and return main context for refactorings in KDevelop.
- *
- * @param db Up-to-date compilation database
- * @return Context for future use with refactorings
- */
-RefactoringsContext createRefactoringsContext(CompilationDatabase db);
-
-/**
* Invokes selected refactoring action on selected place in file.
*
* @param rc Initialized refactorings context
diff --git a/refactoring/kdevrefactorings.cpp b/refactoring/kdevrefactorings.cpp
index 1e9169b..07ad6b6 100644
--- a/refactoring/kdevrefactorings.cpp
+++ b/refactoring/kdevrefactorings.cpp
@@ -19,27 +19,12 @@
Boston, MA 02110-1301, USA.
*/
-#include "kdevrefactorings.h"
-
-// Qt
-#include <QAction>
-#include <QTimer>
-
-// KF5
-#include <KJob>
-
// KDevelop
#include <language/interfaces/editorcontext.h>
-#include <interfaces/icore.h>
-#include <interfaces/iproject.h>
-#include <interfaces/iprojectcontroller.h>
-#include <project/interfaces/ibuildsystemmanager.h>
-#include <project/interfaces/iprojectbuilder.h>
-#include <project/projectmodel.h>
-#include "interface.h"
+#include "kdevrefactorings.h"
+#include "refactoringcontext.h"
#include "refactoringmanager.h"
-#include "debug.h"
#include "../clangsupport.h"
@@ -48,87 +33,18 @@ using namespace KDevelop;
using namespace Refactorings;
KDevRefactorings::KDevRefactorings(ClangSupport *parent)
- : QObject(parent)
+ : QObject(parent)
+ , m_refactoringsContext(new RefactoringContext(this))
+ , m_refactoringManager(new RefactoringManager(this))
{
- m_refactoringManager = new RefactoringManager(this);
- connect(parent->core()->projectController(), &IProjectController::projectOpened,
- this, &KDevRefactorings::projectOpened);
- // handle projects() - alread opened projects
-
}
void KDevRefactorings::fillContextMenu(ContextMenuExtension &extension, Context \
*context) {
if (EditorContext *ctx = dynamic_cast<EditorContext *>(context)) {
- // NOTE: I assume ctx->positions() is "here" position
- auto refactorings = \
m_refactoringManager->allApplicableRefactorings(m_refactoringsContext,
- \
ctx->url(),
- \
ctx->position());
- for (auto refactorAction : refactorings) {
- QAction *action = new QAction(refactorAction->name(), this);
- refactorAction->setParent(action); // delete as necessary
- connect(action, &QAction::triggered, [this, refactorAction, ctx]()
- {
- // TODO: don't use refactorThis
- auto changes = refactorThis(m_refactoringsContext, refactorAction,
- ctx->url(),
- ctx->position());
- // FIXME:
- // use background thread
- // ... provided with ability to show GUI
- // show busy indicator
-
- changes.applyAllChanges();
- // NOTE: cache of ClangTool and FileSystem must be updated after \
application to
- // reflect changes in files
- });
-
- extension.addAction(ContextMenuExtension::RefactorGroup, action);
- }
+ m_refactoringManager->fillContextMenu(extension, ctx);
} else {
// I assume the above works anytime we ask for context menu for code
Q_ASSERT(!context->hasType(Context::CodeContext));
}
}
-
-void KDevRefactorings::projectOpened(IProject *project)
-{
- Q_ASSERT(project);
- refactorDebug() << project->name() << "opened";
- auto projectBuilder = project->buildSystemManager()->builder();
- // IProjectBuilder declares signal configured(), but is unused...
-
- // FIXME: configure only when necessary (and always when necessary)
- auto configureJob = projectBuilder->configure(project);
- connect(configureJob, &KJob::result, this, [this, project]()
- {
- projectConfigured(project);
- });
- configureJob->start();
- // wait for above connection to trigger further actions
-}
-
-void KDevRefactorings::projectConfigured(IProject *project)
-{
- Q_ASSERT(project);
- refactorDebug() << project->name() << "configured";
- auto buildSystemManager = project->buildSystemManager();
- Path buildPath = buildSystemManager->buildDirectory(project->projectItem());
- refactorDebug() << "build path:" << buildPath;
-
- // FIXME: do it async (in background)
- // FIXME: handle non-CMake project
- QString errorMessage;
- auto compilationDatabase = Refactorings::createCompilationDatabase(
- buildPath.toLocalFile().toStdString(), Refactorings::ProjectKind::CMAKE, \
errorMessage);
- if (!compilationDatabase) {
- // TODO: show message for that
- refactorDebug() << "Cannot create compilation database for" << \
project->name() << ":" <<
- errorMessage;
- return;
- }
- auto refactoringsContext = \
Refactorings::createRefactoringsContext(compilationDatabase);
- Q_ASSERT(refactoringsContext);
- m_refactoringsContext = refactoringsContext;
- refactorDebug() << "RefactoringsContext sucessfully (re)generated!";
-}
diff --git a/refactoring/kdevrefactorings.h b/refactoring/kdevrefactorings.h
index 13d7b2b..f44d68d 100644
--- a/refactoring/kdevrefactorings.h
+++ b/refactoring/kdevrefactorings.h
@@ -35,8 +35,10 @@
#include <interfaces/iproject.h>
#include "interface.h"
+#include "refactoring.h"
class ClangSupport;
+
class RefactoringManager;
/**
@@ -55,17 +57,14 @@ public:
// TODO: Handle configuration of projects to regenerate CompilationDatabase
// TODO: Handle above + changes in files (also creation) to update/regenerate \
RefactoringsContext
-private: // (slots)
- // Only one project for now
- void projectOpened(KDevelop::IProject* project);
- void projectConfigured(KDevelop::IProject* project);
-
- // TODO: (async)
- void createRefactoringsContext();
+ RefactoringContext *refactoringContext()
+ {
+ return m_refactoringsContext;
+ }
private:
- Refactorings::RefactoringsContext m_refactoringsContext = nullptr;
- RefactoringManager *m_refactoringManager;
+ RefactoringContext * const m_refactoringsContext;
+ RefactoringManager * const m_refactoringManager;
};
#endif //BUILD_REFACTORINGS
diff --git a/refactoring/refactoringcontext.cpp b/refactoring/refactoringcontext.cpp
index f9f90a7..6ee38ac 100644
--- a/refactoring/refactoringcontext.cpp
+++ b/refactoring/refactoringcontext.cpp
@@ -19,16 +19,46 @@
Boston, MA 02110-1301, USA.
*/
-#include "refactoringcontext.h"
+// KF5
+#include <KJob>
+
+// KDevelop
+#include <interfaces/icore.h>
+#include <interfaces/iproject.h>
+#include <interfaces/iprojectcontroller.h>
+#include <project/interfaces/ibuildsystemmanager.h>
+#include <project/interfaces/iprojectbuilder.h>
+#include <project/projectmodel.h>
+#include "refactoringcontext.h"
+#include "kdevrefactorings.h"
#include "documentcache.h"
+#include "refactoringcontext_worker.h"
#include "utils.h"
+#include "debug.h"
-RefactoringContext::RefactoringContext(
- std::unique_ptr<clang::tooling::CompilationDatabase> database)
- : database(std::move(database))
+using namespace KDevelop;
+
+RefactoringContext::RefactoringContext(KDevRefactorings *parent)
+ : QObject(parent)
{
+ qRegisterMetaType<std::function<void()>>();
cache = new DocumentCache(this);
+ m_worker = new Worker(this);
+
+ connect(m_worker, &Worker::taskFinished, this, \
&RefactoringContext::invokeCallback); + // Will not call-back if this \
RefactoringContext have been destroyed concurrently +
+ connect(ICore::self()->projectController(), &IProjectController::projectOpened,
+ this, &RefactoringContext::projectOpened);
+ // handle projects() - alread opened projects
+
+ m_worker->start();
+}
+
+KDevRefactorings *RefactoringContext::parent()
+{
+ return static_cast<KDevRefactorings *>(QObject::parent());
}
llvm::ErrorOr<unsigned> RefactoringContext::offset(const std::string &sourceFile,
@@ -36,3 +66,47 @@ llvm::ErrorOr<unsigned> RefactoringContext::offset(const \
std::string &sourceFile {
return toOffset(sourceFile, position, cache->refactoringTool(), cache);
}
+
+void RefactoringContext::projectOpened(IProject *project)
+{
+ Q_ASSERT(project);
+ refactorDebug() << project->name() << "opened";
+ auto projectBuilder = project->buildSystemManager()->builder();
+ // IProjectBuilder declares signal configured(), but is unused...
+
+ // FIXME: configure only when necessary (and always when necessary)
+ auto configureJob = projectBuilder->configure(project);
+ connect(configureJob, &KJob::result, this, [this, project]()
+ {
+ projectConfigured(project);
+ });
+ configureJob->start();
+ // wait for above connection to trigger further actions
+}
+
+void RefactoringContext::projectConfigured(IProject *project)
+{
+ Q_ASSERT(project);
+ refactorDebug() << project->name() << "configured";
+ auto buildSystemManager = project->buildSystemManager();
+ Path buildPath = buildSystemManager->buildDirectory(project->projectItem());
+ refactorDebug() << "build path:" << buildPath;
+
+ // FIXME: do it async (in background)
+ // FIXME: handle non-CMake project
+ QString errorMessage;
+ database = makeCompilationDatabaseFromCMake(buildPath.toLocalFile().toStdString(),
+ errorMessage);
+ if (!database) {
+ // TODO: show message for that
+ refactorDebug() << "Cannot create compilation database for" << \
project->name() << ":" << + errorMessage;
+ return;
+ }
+ refactorDebug() << "RefactoringsContext sucessfully (re)generated!";
+}
+
+void RefactoringContext::invokeCallback(std::function<void()> callback)
+{
+ callback();
+}
diff --git a/refactoring/refactoringcontext.h b/refactoring/refactoringcontext.h
index 91001cb..ce370b1 100644
--- a/refactoring/refactoringcontext.h
+++ b/refactoring/refactoringcontext.h
@@ -22,8 +22,9 @@
#ifndef KDEV_CLANG_REFACTORINGCONTEXT_H
#define KDEV_CLANG_REFACTORINGCONTEXT_H
-// base class
+// Qt
#include <QObject>
+#include <QTimer>
// KF5
#include <KTextEditor/ktexteditor/cursor.h>
@@ -33,12 +34,17 @@
// Clang
#include <clang/Tooling/CompilationDatabase.h>
+#include <clang/Tooling/Refactoring.h>
namespace KDevelop
{
class IDocumentController;
+
+class IProject;
};
+class KDevRefactorings;
+
class DocumentCache;
// TODO: join with DocumentCache, handle CompilationDatabase here
@@ -47,15 +53,104 @@ class RefactoringContext : public QObject
Q_OBJECT;
Q_DISABLE_COPY(RefactoringContext);
+ class Worker;
+
public:
- RefactoringContext(std::unique_ptr<clang::tooling::CompilationDatabase> \
database); + RefactoringContext(KDevRefactorings *parent);
+
+ KDevRefactorings *parent();
llvm::ErrorOr<unsigned> offset(const std::string &sourceFile,
const KTextEditor::Cursor &position) const;
+ 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); +
+private: // (slots)
+ // Only one project for now
+ void projectOpened(KDevelop::IProject *project);
+ void projectConfigured(KDevelop::IProject *project);
+
+private slots:
+ // Directly call callback on this thread
+ void invokeCallback(std::function<void()> callback);
+
+private:
+ template<typename Task, typename Callback>
+ static std::function<void(clang::tooling::RefactoringTool &,
+ std::function<void(std::function<void()>)>)> \
composeTask( + Task task, Callback callback);
+
+public:
std::unique_ptr<clang::tooling::CompilationDatabase> database;
DocumentCache *cache;
+
+private:
+ Worker *m_worker;
};
+Q_DECLARE_METATYPE(std::function<void()>);
+
+template<typename Task, typename Callback>
+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,
+ 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);
+ };
+ callbackScheduler(callbackInvoker);
+ };
+};
+
+#include "refactoringcontext_worker.h"
+
+template<typename Task, typename Callback>
+void RefactoringContext::schedule(Task task, Callback callback)
+{
+ auto composedTask = composeTask(task, callback);
+ auto worker = m_worker;
+#if(QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
+ QTimer::singleShot(0, m_worker, [worker, composedTask]
+ {
+ worker->invoke(composedTask);
+ });
+#else
+ QMetaObject::invokeMethod(
+ m_worker, "invoke",
+ Q_ARG(std::function<void(clang::tooling::RefactoringTool & ,
+ std::function<void(std::function<void()>)>)>, composedTask));
+#endif
+};
+
+template<typename Task, typename Callback>
+void RefactoringContext::scheduleOnSingleFile(Task task, const std::string \
&filename, + Callback callback)
+{
+ auto composedTask = composeTask(task, callback);
+ auto worker = m_worker;
+#if(QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
+ QTimer::singleShot(0, m_worker, [worker, composedTask, filename]
+ {
+ worker->invokeOnSingleFile(composedTask, filename);
+ });
+#else
+ QMetaObject::invokeMethod(
+ m_worker, "invokeOnSingleFile",
+ Q_ARG(std::function<void(clang::tooling::RefactoringTool & ,
+ std::function<void(std::function<void()>)>)>, composedTask),
+ Q_ARG(std::string, filename));
+#endif
+}
+
#endif //KDEV_CLANG_REFACTORINGCONTEXT_H
diff --git a/refactoring/refactoringcontext_worker.cpp \
b/refactoring/refactoringcontext_worker.cpp new file mode 100644
index 0000000..751d35b
--- /dev/null
+++ b/refactoring/refactoringcontext_worker.cpp
@@ -0,0 +1,68 @@
+/*
+ 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 "refactoringcontext.h" // NOTE: we have circular dependency here
+// Above must be included before...
+#include "refactoringcontext_worker.h"
+#include "refactoring.h"
+#include "refactoringmanager.h"
+#include "documentcache.h"
+
+RefactoringContext::Worker::Worker(
+ RefactoringContext *refactoringContext)
+ : QThread(nullptr)
+ , m_parent(refactoringContext)
+{
+#if(QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
+ qRegisterMetaType<std::function<void(clang::tooling::RefactoringTool &,
+ \
std::function<void(std::function<void()>)>)>>(); + \
qRegisterMetaType<std::string>(); +#endif
+ moveToThread(this);
+ setObjectName("RefactoringContext - Worker");
+ connect(m_parent, &QObject::destroyed, this, [this]
+ {
+ m_parent = nullptr;
+ exit();
+ });
+}
+
+void RefactoringContext::Worker::invoke(
+ std::function<void(clang::tooling::RefactoringTool &,
+ std::function<void(std::function<void()>)>)> task)
+{
+ task(m_parent->cache->refactoringTool(), [this](std::function<void()> \
resultCallback) + {
+ emit taskFinished(resultCallback);
+ });
+}
+
+void RefactoringContext::Worker::invokeOnSingleFile(
+ std::function<void(clang::tooling::RefactoringTool &,
+ std::function<void(std::function<void()>)>)> task,
+ const std::string &filename)
+{
+ auto tool = m_parent->cache->refactoringToolForFile(filename);
+ task(tool, [this](std::function<void()> resultCallback)
+ {
+ emit taskFinished(resultCallback);
+ });
+}
diff --git a/refactoring/refactoringcontext_worker.h \
b/refactoring/refactoringcontext_worker.h new file mode 100644
index 0000000..93ed446
--- /dev/null
+++ b/refactoring/refactoringcontext_worker.h
@@ -0,0 +1,63 @@
+/*
+ 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.
+*/
+
+#ifndef KDEV_CLANG_REFACTORINGMANAGER_WORKER_H
+#define KDEV_CLANG_REFACTORINGMANAGER_WORKER_H
+
+// Clang
+#include <clang/Tooling/Refactoring.h>
+
+// Qt
+#include <QThread>
+
+#include "refactoringcontext.h"
+
+/**
+ * This is background worker for refactoring actions
+ */
+class RefactoringContext::Worker : public QThread
+{
+ Q_OBJECT;
+ Q_DISABLE_COPY(Worker);
+public:
+ Worker(RefactoringContext *parent);
+
+public slots:
+ void invoke(std::function<void(clang::tooling::RefactoringTool &,
+ std::function<void(std::function<void()>)>)> \
task); + void invokeOnSingleFile(std::function<void(clang::tooling::RefactoringTool \
&, + \
std::function<void(std::function<void()>)>)> task, + const \
std::string &filename); +
+signals:
+ void taskFinished(std::function<void()> resultCallback);
+
+private:
+ RefactoringContext *m_parent;
+};
+
+#if(QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
+Q_DECLARE_METATYPE(std::function<void(clang::tooling::RefactoringTool & ,
+ std::function<void(std::function<void()>)>)>);
+Q_DECLARE_METATYPE(std::string);
+#endif
+
+#endif //KDEV_CLANG_REFACTORINGMANAGER_WORKER_H
diff --git a/refactoring/refactoringmanager.cpp b/refactoring/refactoringmanager.cpp
index e6b074e..6ab8ee2 100644
--- a/refactoring/refactoringmanager.cpp
+++ b/refactoring/refactoringmanager.cpp
@@ -27,6 +27,7 @@
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Tooling/Tooling.h>
+#include "kdevrefactorings.h"
#include "refactoringcontext.h"
#include "documentcache.h"
#include "utils.h"
@@ -158,31 +159,50 @@ private:
}
-RefactoringManager::RefactoringManager(QObject *parent)
+#include "contextmenumutator.h"
+
+RefactoringManager::RefactoringManager(KDevRefactorings *parent)
: QObject(parent)
{
+ qRegisterMetaType<ContextMenuMutator *>();
+ qRegisterMetaType<QVector<Refactoring *>>();
+}
+
+KDevRefactorings *RefactoringManager::parent()
+{
+ return static_cast<KDevRefactorings *>(QObject::parent());
}
-std::vector<Refactoring *> \
RefactoringManager::allApplicableRefactorings(RefactoringContext \
*ctx,
- const QUrl \
&sourceFile,
- const \
KTextEditor::Cursor &location) +void \
RefactoringManager::fillContextMenu(KDevelop::ContextMenuExtension &extension, + \
KDevelop::EditorContext *context) {
- const string filename = sourceFile.toLocalFile().toStdString();
- auto clangTool = ctx->cache->refactoringToolForFile(filename);
+ const string filename = context->url().toLocalFile().toStdString();
unsigned offset;
{
- auto _offset = ctx->offset(filename, location);
+ auto _offset = parent()->refactoringContext()->offset(filename, \
context->position()); if (!_offset) {
// TODO: notify user
refactorDebug() << "Unable to translate cursor position to offset in \
file:" << _offset.getError().message();
- return {};
+ return;
}
offset = _offset.get();
}
- auto faf = cpp::make_unique<ExplorerActionFactory>(filename, offset);
- clangTool.run(faf.get());
- return std::move(faf->m_refactorings);
+ auto mutator = new ContextMenuMutator(extension, this);
+ QThread *mainThread = thread(); // Only for lambda below
+ parent()->refactoringContext()->scheduleOnSingleFile(
+ [filename, offset, mainThread](RefactoringTool &clangTool)
+ {
+ auto faf = cpp::make_unique<ExplorerActionFactory>(filename, offset);
+ clangTool.run(faf.get());
+ for (Refactoring *r : faf->m_refactorings) {
+ r->moveToThread(mainThread);
+ }
+ return QVector<Refactoring *>::fromStdVector(faf->m_refactorings);
+ }, filename, [mutator](const QVector<Refactoring *> &result)
+ {
+ mutator->endFillingContextMenu(result);
+ });
}
diff --git a/refactoring/refactoringmanager.h b/refactoring/refactoringmanager.h
index cf0c919..87c685b 100644
--- a/refactoring/refactoringmanager.h
+++ b/refactoring/refactoringmanager.h
@@ -22,36 +22,38 @@
#ifndef KDEV_CLANG_REFACTORINGMANAGER_H
#define KDEV_CLANG_REFACTORINGMANAGER_H
-// base class
+// Qt
#include <QObject>
+#include <QVector>
+
+// KDevelop
+#include <interfaces/contextmenuextension.h>
+#include <language/interfaces/editorcontext.h>
// C++
-#include <vector>
#include <memory>
#include "refactoring.h"
+class KDevRefactorings;
+
class RefactoringManager : public QObject
{
Q_OBJECT;
Q_DISABLE_COPY(RefactoringManager);
+
public:
- RefactoringManager(QObject *parent);
-
- /**
- * Returns all applicable refactorings "here"
- *
- * @param rc Initialized refactorings context
- * @param sourceFile queried source file name (full path)
- * @param location offset from beginning of the file to location we are querying
- *
- * @return List of all applicable refactorings "here"
- */
- std::vector<Refactoring *> allApplicableRefactorings(RefactoringContext *ctx,
- const QUrl &sourceFile,
- const KTextEditor::Cursor \
&location);
- // or make RefactoringContext* property
+ RefactoringManager(KDevRefactorings *parent);
+
+ void fillContextMenu(KDevelop::ContextMenuExtension &extension,
+ KDevelop::EditorContext *context);
+
+ KDevRefactorings *parent();
+
+private:
+
};
+Q_DECLARE_METATYPE(QVector<Refactoring *>);
#endif //KDEV_CLANG_REFACTORINGMANAGER_H
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic