Clang: Use completion through backend process

This makes us independent of libclang crashes for completion.
Re-parsing for highlighting still happens in the Qt Creator process.

Run in verbose mode:
    qtc.clangcodemodel.ipc=true

Run tests:
    -test "ClangCodeModel"

Task-number: QTCREATORBUG-14108
Task-number: QTCREATORBUG-12819
Change-Id: Id3e95bd2afdb6508bbd1d35fddc69534a909b905
Reviewed-by: Marco Bubke <marco.bubke@theqtcompany.com>
This commit is contained in:
Nikolai Kosjar
2015-05-08 15:48:17 +02:00
parent 264132da27
commit 23b8a3b2e8
59 changed files with 3820 additions and 634 deletions

View File

@@ -150,8 +150,10 @@ public:
QSet<AbstractEditorSupport *> m_extraEditorSupports;
// Completion & highlighting
QHash<QString, ModelManagerSupport *> m_idTocodeModelSupporter;
QScopedPointer<ModelManagerSupport> m_modelManagerSupportFallback;
ModelManagerSupportProviderInternal m_modelManagerSupportInternalProvider;
ModelManagerSupport::Ptr m_modelManagerSupportInternal;
QHash<QString, ModelManagerSupportProvider *> m_availableModelManagerSupports;
QHash<QString, ModelManagerSupport::Ptr> m_activeModelManagerSupports;
// Indexing
CppIndexingSupport *m_indexingSupporter;
@@ -329,10 +331,17 @@ CppModelManager::CppModelManager(QObject *parent)
qRegisterMetaType<QList<Document::DiagnosticMessage>>(
"QList<CPlusPlus::Document::DiagnosticMessage>");
d->m_modelManagerSupportFallback.reset(new ModelManagerSupportInternal);
CppToolsPlugin::instance()->codeModelSettings()->setDefaultId(
d->m_modelManagerSupportFallback->id());
addModelManagerSupport(d->m_modelManagerSupportFallback.data());
QSharedPointer<CppCodeModelSettings> codeModelSettings
= CppToolsPlugin::instance()->codeModelSettings();
codeModelSettings->setDefaultId(d->m_modelManagerSupportInternalProvider.id());
connect(codeModelSettings.data(), &CppCodeModelSettings::changed,
this, &CppModelManager::onCodeModelSettingsChanged);
d->m_modelManagerSupportInternal
= d->m_modelManagerSupportInternalProvider.createModelManagerSupport();
d->m_activeModelManagerSupports.insert(d->m_modelManagerSupportInternalProvider.id(),
d->m_modelManagerSupportInternal);
addModelManagerSupportProvider(&d->m_modelManagerSupportInternalProvider);
d->m_internalIndexingSupport = new BuiltinIndexingSupport;
}
@@ -466,6 +475,11 @@ void CppModelManager::dumpModelManagerConfiguration(const QString &logFileId)
dumper.dumpMergedEntities(d->m_headerPaths, d->m_definedMacros);
}
QSet<AbstractEditorSupport *> CppModelManager::abstractEditorSupports() const
{
return d->m_extraEditorSupports;
}
void CppModelManager::addExtraEditorSupport(AbstractEditorSupport *editorSupport)
{
d->m_extraEditorSupports.insert(editorSupport);
@@ -648,6 +662,39 @@ void CppModelManager::removeProjectInfoFilesAndIncludesFromSnapshot(const Projec
}
}
void CppModelManager::handleAddedModelManagerSupports(const QSet<QString> &supportIds)
{
foreach (const QString &id, supportIds) {
ModelManagerSupportProvider * const provider = d->m_availableModelManagerSupports.value(id);
if (provider) {
QTC_CHECK(!d->m_activeModelManagerSupports.contains(id));
d->m_activeModelManagerSupports.insert(id, provider->createModelManagerSupport());
}
}
}
QList<ModelManagerSupport::Ptr> CppModelManager::handleRemovedModelManagerSupports(
const QSet<QString> &supportIds)
{
QList<ModelManagerSupport::Ptr> removed;
foreach (const QString &id, supportIds) {
const ModelManagerSupport::Ptr support = d->m_activeModelManagerSupports.value(id);
d->m_activeModelManagerSupports.remove(id);
removed << support;
}
return removed;
}
void CppModelManager::closeCppEditorDocuments()
{
QList<Core::IDocument *> cppDocumentsToClose;
foreach (CppEditorDocumentHandle *cppDocument, cppEditorDocuments())
cppDocumentsToClose << cppDocument->processor()->baseTextDocument();
QTC_CHECK(Core::EditorManager::closeDocuments(cppDocumentsToClose));
}
QList<CppEditorDocumentHandle *> CppModelManager::cppEditorDocuments() const
{
QMutexLocker locker(&d->m_cppEditorDocumentsMutex);
@@ -663,6 +710,15 @@ void CppModelManager::removeFilesFromSnapshot(const QSet<QString> &filesToRemove
d->m_snapshot.remove(i.next());
}
static QStringList projectFilePaths(const QSet<ProjectPart::Ptr> &projectParts)
{
QStringList result;
QSetIterator<ProjectPart::Ptr> it(projectParts);
while (it.hasNext())
result << it.next()->projectFile;
return result;
}
class ProjectInfoComparer
{
public:
@@ -692,6 +748,13 @@ public:
return removedFilesSet;
}
QStringList removedProjectParts()
{
QSet<ProjectPart::Ptr> removed = m_old.projectParts().toSet();
removed.subtract(m_new.projectParts().toSet());
return projectFilePaths(removed);
}
/// Returns a list of common files that have a changed timestamp.
QSet<QString> timeStampModifiedFiles(const Snapshot &snapshot) const
{
@@ -809,6 +872,9 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn
}
}
// Announce removed project parts
emit projectPartsRemoved(comparer.removedProjectParts());
// A new project was opened/created, do a full indexing
} else {
d->m_dirty = true;
@@ -829,6 +895,7 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn
if (filesRemoved)
GC();
// Announce added project parts
emit projectPartsUpdated(newProjectInfo.project().data());
// Ideally, we would update all the editor documents that depend on the 'filesToReindex'.
@@ -903,14 +970,32 @@ void CppModelManager::delayedGC()
d->m_delayedGcTimer.start(500);
}
static QStringList pathsOfAllProjectParts(const ProjectInfo &projectInfo)
{
QStringList projectPaths;
foreach (const ProjectPart::Ptr &part, projectInfo.projectParts())
projectPaths << part->projectFile;
return projectPaths;
}
void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project)
{
do {
QStringList projectFilePaths;
{
QMutexLocker locker(&d->m_projectMutex);
d->m_dirty = true;
// Save paths
const ProjectInfo projectInfo = d->m_projectToProjectsInfo.value(project, ProjectInfo());
QTC_CHECK(projectInfo.isValid());
projectFilePaths = pathsOfAllProjectParts(projectInfo);
d->m_projectToProjectsInfo.remove(project);
recalculateFileToProjectParts();
} while (0);
}
emit projectPartsRemoved(projectFilePaths);
delayedGC();
}
@@ -937,6 +1022,45 @@ void CppModelManager::onCurrentEditorChanged(Core::IEditor *editor)
}
}
static const QSet<QString> activeModelManagerSupportsFromSettings()
{
QSet<QString> result;
QSharedPointer<CppCodeModelSettings> codeModelSettings
= CppToolsPlugin::instance()->codeModelSettings();
const QStringList mimeTypes = codeModelSettings->supportedMimeTypes();
foreach (const QString &mimeType, mimeTypes) {
const QString id = codeModelSettings->modelManagerSupportIdForMimeType(mimeType);
if (!id.isEmpty())
result << id;
}
return result;
}
void CppModelManager::onCodeModelSettingsChanged()
{
const QSet<QString> currentCodeModelSupporters = d->m_activeModelManagerSupports.keys().toSet();
const QSet<QString> newCodeModelSupporters = activeModelManagerSupportsFromSettings();
QSet<QString> added = newCodeModelSupporters;
added.subtract(currentCodeModelSupporters);
added.remove(d->m_modelManagerSupportInternalProvider.id());
handleAddedModelManagerSupports(added);
QSet<QString> removed = currentCodeModelSupporters;
removed.subtract(newCodeModelSupporters);
removed.remove(d->m_modelManagerSupportInternalProvider.id());
const QList<ModelManagerSupport::Ptr> supportsToDelete
= handleRemovedModelManagerSupports(removed);
QTC_CHECK(removed.size() == supportsToDelete.size());
if (!added.isEmpty() || !removed.isEmpty())
closeCppEditorDocuments();
// supportsToDelete goes out of scope and deletes the supports
}
void CppModelManager::onAboutToLoadSession()
{
if (d->m_delayedGcTimer.isActive())
@@ -999,11 +1123,8 @@ void CppModelManager::GC()
foreach (const CppEditorDocumentHandle *editorDocument, cppEditorDocuments())
filesInEditorSupports << editorDocument->filePath();
QSetIterator<AbstractEditorSupport *> jt(d->m_extraEditorSupports);
while (jt.hasNext()) {
AbstractEditorSupport *abstractEditorSupport = jt.next();
foreach (AbstractEditorSupport *abstractEditorSupport, abstractEditorSupports())
filesInEditorSupports << abstractEditorSupport->fileName();
}
Snapshot currentSnapshot = snapshot();
QSet<Utils::FileName> reachableFiles;
@@ -1049,27 +1170,33 @@ void CppModelManager::finishedRefreshingSourceFiles(const QSet<QString> &files)
emit sourceFilesRefreshed(files);
}
void CppModelManager::addModelManagerSupport(ModelManagerSupport *modelManagerSupport)
void CppModelManager::addModelManagerSupportProvider(
ModelManagerSupportProvider *modelManagerSupportProvider)
{
Q_ASSERT(modelManagerSupport);
d->m_idTocodeModelSupporter[modelManagerSupport->id()] = modelManagerSupport;
QTC_ASSERT(modelManagerSupportProvider, return);
d->m_availableModelManagerSupports[modelManagerSupportProvider->id()]
= modelManagerSupportProvider;
QSharedPointer<CppCodeModelSettings> cms = CppToolsPlugin::instance()->codeModelSettings();
cms->setModelManagerSupports(d->m_idTocodeModelSupporter.values());
cms->setModelManagerSupportProviders(d->m_availableModelManagerSupports.values());
onCodeModelSettingsChanged();
}
ModelManagerSupport *CppModelManager::modelManagerSupportForMimeType(const QString &mimeType) const
ModelManagerSupport::Ptr CppModelManager::modelManagerSupportForMimeType(
const QString &mimeType) const
{
QSharedPointer<CppCodeModelSettings> cms = CppToolsPlugin::instance()->codeModelSettings();
const QString &id = cms->modelManagerSupportId(mimeType);
return d->m_idTocodeModelSupporter.value(id, d->m_modelManagerSupportFallback.data());
const QString &id = cms->modelManagerSupportIdForMimeType(mimeType);
return d->m_activeModelManagerSupports.value(id, d->m_modelManagerSupportInternal);
}
CppCompletionAssistProvider *CppModelManager::completionAssistProvider(const QString &mimeType) const
CppCompletionAssistProvider *CppModelManager::completionAssistProvider(
const QString &mimeType) const
{
if (mimeType.isEmpty())
return 0;
ModelManagerSupport *cms = modelManagerSupportForMimeType(mimeType);
ModelManagerSupport::Ptr cms = modelManagerSupportForMimeType(mimeType);
QTC_ASSERT(cms, return 0);
return cms->completionAssistProvider();
}
@@ -1078,7 +1205,7 @@ BaseEditorDocumentProcessor *CppModelManager::editorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) const
{
QTC_ASSERT(baseTextDocument, return 0);
ModelManagerSupport *cms = modelManagerSupportForMimeType(baseTextDocument->mimeType());
ModelManagerSupport::Ptr cms = modelManagerSupportForMimeType(baseTextDocument->mimeType());
QTC_ASSERT(cms, return 0);
return cms->editorDocumentProcessor(baseTextDocument);
}