VcsBase: Make dependency on CppTools optional

The VcsBaseSubmitEditor uses CppModelManager to collect the symbol names
from the affected files for completion in the commit message.

Move the C++ code model code into CppModelManager, register it in the
plugin manager, and call it via QObject means from the submit editor.

This avoids a hard dependency from VcsBase to CppTools.

Change-Id: I2fb34dbef153c1414820d711e7fc5596bcac1691
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Eike Ziller
2019-08-13 15:42:03 +02:00
parent 6b5bf41d9f
commit 857b299356
6 changed files with 101 additions and 73 deletions

View File

@@ -52,15 +52,16 @@
#include "followsymbolinterface.h" #include "followsymbolinterface.h"
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <texteditor/textdocument.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/vcsmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectmacro.h> #include <projectexplorer/projectmacro.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <texteditor/textdocument.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -511,6 +512,10 @@ CppModelManager::CppModelManager()
: CppModelManagerBase(nullptr) : CppModelManagerBase(nullptr)
, d(new CppModelManagerPrivate) , d(new CppModelManagerPrivate)
{ {
// Used for weak dependency in VcsBaseSubmitEditor
setObjectName("CppModelManager");
ExtensionSystem::PluginManager::addObject(this);
d->m_indexingSupporter = nullptr; d->m_indexingSupporter = nullptr;
d->m_enableGC = true; d->m_enableGC = true;
@@ -561,6 +566,8 @@ CppModelManager::CppModelManager()
CppModelManager::~CppModelManager() CppModelManager::~CppModelManager()
{ {
ExtensionSystem::PluginManager::removeObject(this);
delete d->m_internalIndexingSupport; delete d->m_internalIndexingSupport;
delete d; delete d;
} }
@@ -1305,6 +1312,60 @@ void CppModelManager::renameIncludes(const QString &oldFileName, const QString &
} }
} }
// Return the class name which function belongs to
static const char *belongingClassName(const Function *function)
{
if (!function)
return nullptr;
if (auto funcName = function->name()) {
if (auto qualifiedNameId = funcName->asQualifiedNameId()) {
if (const Name *funcBaseName = qualifiedNameId->base()) {
if (auto identifier = funcBaseName->identifier())
return identifier->chars();
}
}
}
return nullptr;
}
QSet<QString> CppModelManager::symbolsInFiles(const QSet<Utils::FilePath> &files) const
{
QSet<QString> uniqueSymbols;
const Snapshot cppSnapShot = snapshot();
// Iterate over the files and get interesting symbols
for (const Utils::FilePath &file : files) {
// Add symbols from the C++ code model
const CPlusPlus::Document::Ptr doc = cppSnapShot.document(file);
if (!doc.isNull() && doc->control()) {
const CPlusPlus::Control *ctrl = doc->control();
CPlusPlus::Symbol **symPtr = ctrl->firstSymbol(); // Read-only
while (symPtr != ctrl->lastSymbol()) {
const CPlusPlus::Symbol *sym = *symPtr;
const CPlusPlus::Identifier *symId = sym->identifier();
// Add any class, function or namespace identifiers
if ((sym->isClass() || sym->isFunction() || sym->isNamespace()) && symId
&& symId->chars()) {
uniqueSymbols.insert(QString::fromUtf8(symId->chars()));
}
// Handle specific case : get "Foo" in "void Foo::function() {}"
if (sym->isFunction() && !sym->asFunction()->isDeclaration()) {
const char *className = belongingClassName(sym->asFunction());
if (className)
uniqueSymbols.insert(QString::fromUtf8(className));
}
++symPtr;
}
}
}
return uniqueSymbols;
}
void CppModelManager::onCoreAboutToClose() void CppModelManager::onCoreAboutToClose()
{ {
Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX); Core::ProgressManager::cancelTasks(CppTools::Constants::TASK_INDEX);

View File

@@ -230,6 +230,9 @@ public:
void renameIncludes(const QString &oldFileName, const QString &newFileName); void renameIncludes(const QString &oldFileName, const QString &newFileName);
// for VcsBaseSubmitEditor
Q_INVOKABLE QSet<QString> symbolsInFiles(const QSet<Utils::FilePath> &files) const;
signals: signals:
/// Project data might be locked while this is emitted. /// Project data might be locked while this is emitted.
void aboutToRemoveFiles(const QStringList &files); void aboutToRemoveFiles(const QStringList &files);

View File

@@ -1,6 +1,6 @@
add_qtc_plugin(VcsBase add_qtc_plugin(VcsBase
PLUGIN_DEPENDS Core CppTools DiffEditor ProjectExplorer TextEditor PLUGIN_DEPENDS Core DiffEditor ProjectExplorer TextEditor
PLUGIN_RECOMMENDS CodePaster PLUGIN_RECOMMENDS CodePaster CppTools
SOURCES SOURCES
baseannotationhighlighter.cpp baseannotationhighlighter.h baseannotationhighlighter.cpp baseannotationhighlighter.h
basevcseditorfactory.cpp basevcseditorfactory.h basevcseditorfactory.cpp basevcseditorfactory.h

View File

@@ -11,11 +11,11 @@ QtcPlugin {
Depends { name: "Core" } Depends { name: "Core" }
Depends { name: "TextEditor" } Depends { name: "TextEditor" }
Depends { name: "ProjectExplorer" } Depends { name: "ProjectExplorer" }
Depends { name: "CppTools" }
Depends { name: "DiffEditor" } Depends { name: "DiffEditor" }
pluginRecommends: [ pluginRecommends: [
"CodePaster" "CodePaster",
"CppTools"
] ]
files: [ files: [

View File

@@ -8,7 +8,7 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \ coreplugin \
texteditor \ texteditor \
projectexplorer \ projectexplorer \
cpptools \
diffeditor diffeditor
QTC_PLUGIN_RECOMMENDS += \ QTC_PLUGIN_RECOMMENDS += \
cpaster cpaster \
cpptools

View File

@@ -36,12 +36,14 @@
#include "vcsplugin.h" #include "vcsplugin.h"
#include <aggregation/aggregate.h> #include <aggregation/aggregate.h>
#include <cpptools/cppmodelmanager.h>
#include <coreplugin/find/basetextfind.h> #include <coreplugin/find/basetextfind.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <extensionsystem/invoker.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/checkablemessagebox.h> #include <utils/checkablemessagebox.h>
#include <utils/completingtextedit.h> #include <utils/completingtextedit.h>
@@ -78,30 +80,9 @@ enum { debug = 0 };
enum { wantToolBar = 0 }; enum { wantToolBar = 0 };
// Return true if word is meaningful and can be added to a completion model // Return true if word is meaningful and can be added to a completion model
static bool acceptsWordForCompletion(const char *word) static bool acceptsWordForCompletion(const QString &word)
{ {
if (!word) return word.size() >= 7;
return false;
static const std::size_t minWordLength = 7;
return std::strlen(word) >= minWordLength;
}
// Return the class name which function belongs to
static const char *belongingClassName(const CPlusPlus::Function *function)
{
if (!function)
return nullptr;
if (auto funcName = function->name()) {
if (auto qualifiedNameId = funcName->asQualifiedNameId()) {
if (const CPlusPlus::Name *funcBaseName = qualifiedNameId->base()) {
if (auto identifier = funcBaseName->identifier())
return identifier->chars();
}
}
}
return nullptr;
} }
/*! /*!
@@ -407,6 +388,17 @@ QStringList VcsBaseSubmitEditor::checkedFiles() const
return d->m_widget->checkedFiles(); return d->m_widget->checkedFiles();
} }
static QSet<FilePath> filesFromModel(SubmitFileModel *model)
{
QSet<FilePath> result;
result.reserve(model->rowCount());
for (int row = 0; row < model->rowCount(); ++row) {
result.insert(FilePath::fromString(
QFileInfo(model->repositoryRoot(), model->file(row)).absoluteFilePath()));
}
return result;
}
void VcsBaseSubmitEditor::setFileModel(SubmitFileModel *model) void VcsBaseSubmitEditor::setFileModel(SubmitFileModel *model)
{ {
QTC_ASSERT(model, return); QTC_ASSERT(model, return);
@@ -421,49 +413,21 @@ void VcsBaseSubmitEditor::setFileModel(SubmitFileModel *model)
if (!selected.isEmpty()) if (!selected.isEmpty())
d->m_widget->setSelectedRows(selected); d->m_widget->setSelectedRows(selected);
QSet<QString> uniqueSymbols; const QSet<FilePath> files = filesFromModel(model);
const CPlusPlus::Snapshot cppSnapShot = CppTools::CppModelManager::instance()->snapshot(); // add file names to completion
QSet<QString> completionItems = Utils::transform(files, &FilePath::fileName);
// Iterate over the files and get interesting symbols QObject *cppModelManager = ExtensionSystem::PluginManager::getObjectByName("CppModelManager");
for (int row = 0; row < model->rowCount(); ++row) { if (cppModelManager) {
const QFileInfo fileInfo(model->repositoryRoot(), model->file(row)); const auto symbols = ExtensionSystem::invoke<QSet<QString>>(cppModelManager,
"symbolsInFiles",
// Add file name files);
uniqueSymbols.insert(fileInfo.fileName()); completionItems += Utils::filtered(symbols, acceptsWordForCompletion);
const QString filePath = fileInfo.absoluteFilePath();
// Add symbols from the C++ code model
const CPlusPlus::Document::Ptr doc = cppSnapShot.document(filePath);
if (!doc.isNull() && doc->control()) {
const CPlusPlus::Control *ctrl = doc->control();
CPlusPlus::Symbol **symPtr = ctrl->firstSymbol(); // Read-only
while (symPtr != ctrl->lastSymbol()) {
const CPlusPlus::Symbol *sym = *symPtr;
const CPlusPlus::Identifier *symId = sym->identifier();
// Add any class, function or namespace identifiers
if ((sym->isClass() || sym->isFunction() || sym->isNamespace())
&& (symId && acceptsWordForCompletion(symId->chars())))
{
uniqueSymbols.insert(QString::fromUtf8(symId->chars()));
}
// Handle specific case : get "Foo" in "void Foo::function() {}"
if (sym->isFunction() && !sym->asFunction()->isDeclaration()) {
const char *className = belongingClassName(sym->asFunction());
if (acceptsWordForCompletion(className))
uniqueSymbols.insert(QString::fromUtf8(className));
}
++symPtr;
}
}
} }
// Populate completer with symbols // Populate completer with symbols
if (!uniqueSymbols.isEmpty()) { if (!completionItems.isEmpty()) {
QCompleter *completer = d->m_widget->descriptionEdit()->completer(); QCompleter *completer = d->m_widget->descriptionEdit()->completer();
QStringList symbolsList = Utils::toList(uniqueSymbols); QStringList symbolsList = Utils::toList(completionItems);
symbolsList.sort(); symbolsList.sort();
completer->setModel(new QStringListModel(symbolsList, completer)); completer->setModel(new QStringListModel(symbolsList, completer));
} }