forked from qt-creator/qt-creator
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:
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
@@ -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: [
|
||||||
|
@@ -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
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user