From 2fc5dba1c312067ed040bee0bacced400d0179e1 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 24 Aug 2022 11:16:20 +0200 Subject: [PATCH] ClangCodeModel: Implement per-session mode for clangd Fixes: QTCREATORBUG-26526 Change-Id: If9e018475b4e2f0557d9bf64ad9a7921c9dd6046 Reviewed-by: Reviewed-by: David Schulz --- .../clangcodemodel/clangcodemodelplugin.cpp | 2 +- src/plugins/clangcodemodel/clangdclient.cpp | 17 +- src/plugins/clangcodemodel/clangdclient.h | 1 + .../clangmodelmanagersupport.cpp | 233 ++++++++++++------ .../clangcodemodel/clangmodelmanagersupport.h | 4 +- src/plugins/clangcodemodel/clangutils.cpp | 52 ++-- src/plugins/clangcodemodel/clangutils.h | 8 +- .../cppeditor/cppcodemodelsettingspage.cpp | 7 +- src/plugins/cppeditor/cppmodelmanager.cpp | 2 +- src/plugins/cppeditor/cppmodelmanager.h | 2 +- src/plugins/cppeditor/projectinfo.h | 3 + src/plugins/languageclient/client.cpp | 5 + src/plugins/languageclient/client.h | 1 + .../languageclient/diagnosticmanager.cpp | 3 +- 14 files changed, 226 insertions(+), 114 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 2d656b8d417..65bc4df731c 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -59,7 +59,7 @@ void ClangCodeModelPlugin::generateCompilationDB() baseDir = TemporaryDirectory::masterDirectoryFilePath(); QFuture task - = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, + = Utils::runAsync(&Internal::generateCompilationDB, ProjectInfoList{projectInfo}, baseDir, CompilationDbPurpose::Project, warningsConfigForProject(target->project()), globalClangOptions(), diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index e7e34251f5f..4d5826b2a9f 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -372,10 +373,9 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir) setClientCapabilities(caps); setLocatorsEnabled(false); setAutoRequestCodeActions(false); // clangd sends code actions inside diagnostics - if (project) { - setProgressTitleForToken(indexingToken(), - tr("Indexing %1 with clangd").arg(project->displayName())); - } + setProgressTitleForToken(indexingToken(), + project ? tr("Indexing %1 with clangd").arg(project->displayName()) + : tr("Indexing session with clangd")); setCurrentProject(project); setDocumentChangeUpdateThreshold(d->settings.documentUpdateThreshold); setSymbolStringifier(displayNameFromDocumentSymbol); @@ -587,6 +587,15 @@ bool ClangdClient::referencesShadowFile(const TextEditor::TextDocument *doc, return !includePos.isNull(); } +bool ClangdClient::fileBelongsToProject(const Utils::FilePath &filePath) const +{ + if (CppEditor::ClangdSettings::instance().granularity() + == CppEditor::ClangdSettings::Granularity::Session) { + return SessionManager::projectForFile(filePath); + } + return Client::fileBelongsToProject(filePath); +} + RefactoringChangesData *ClangdClient::createRefactoringChangesBackend() const { return new CppEditor::CppRefactoringChangesData( diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index fe18af40872..c852d3f5929 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -126,6 +126,7 @@ private: LanguageClient::DiagnosticManager *createDiagnosticManager() override; bool referencesShadowFile(const TextEditor::TextDocument *doc, const Utils::FilePath &candidate) override; + bool fileBelongsToProject(const Utils::FilePath &filePath) const override; class Private; class VirtualFunctionAssistProcessor; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index be63b2ab53b..e3b7b48e79f 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -68,6 +68,11 @@ static ProjectExplorer::Project *fallbackProject() return ProjectExplorer::SessionManager::startupProject(); } +static bool sessionModeEnabled() +{ + return ClangdSettings::instance().granularity() == ClangdSettings::Granularity::Session; +} + static const QList allCppDocuments() { const auto isCppDocument = Utils::equal(&Core::IDocument::id, @@ -77,9 +82,23 @@ static const QList allCppDocuments() return Utils::qobject_container_cast(documents); } +static const QList projectsForClient(const Client *client) +{ + QList projects; + if (sessionModeEnabled()) { + for (ProjectExplorer::Project * const p : ProjectExplorer::SessionManager::projects()) { + if (ClangdProjectSettings(p).settings().useClangd) + projects << p; + } + } else if (client->project()) { + projects << client->project(); + } + return projects; +} + static bool fileIsProjectBuildArtifact(const Client *client, const Utils::FilePath &filePath) { - if (const auto p = client->project()) { + for (const ProjectExplorer::Project * const p : projectsForClient(client)) { if (const auto t = p->activeTarget()) { if (const auto bc = t->activeBuildConfiguration()) { if (filePath.isChildOf(bc->buildDirectory())) @@ -176,6 +195,8 @@ ClangModelManagerSupport::ClangModelManagerSupport() connect(modelManager, &CppEditor::CppModelManager::projectPartsRemoved, this, &ClangModelManagerSupport::onProjectPartsRemoved); connect(modelManager, &CppModelManager::fallbackProjectPartUpdated, this, [this] { + if (sessionModeEnabled()) + return; if (ClangdClient * const fallbackClient = clientForProject(nullptr)) { LanguageClientManager::shutdownClient(fallbackClient); claimNonProjectSources(new ClangdClient(nullptr, {})); @@ -184,7 +205,15 @@ ClangModelManagerSupport::ClangModelManagerSupport() auto *sessionManager = ProjectExplorer::SessionManager::instance(); connect(sessionManager, &ProjectExplorer::SessionManager::projectRemoved, - this, [this] { claimNonProjectSources(clientForProject(fallbackProject())); }); + this, [this] { + if (!sessionModeEnabled()) + claimNonProjectSources(clientForProject(fallbackProject())); + }); + connect(sessionManager, &ProjectExplorer::SessionManager::sessionLoaded, + this, [this] { + if (sessionModeEnabled()) + onClangdSettingsChanged(); + }); CppEditor::ClangdSettings::setDefaultClangdPath(Core::ICore::clangdExecutable(CLANG_BINDIR)); connect(&CppEditor::ClangdSettings::instance(), &CppEditor::ClangdSettings::changed, @@ -331,38 +360,71 @@ void ClangModelManagerSupport::connectToWidgetsMarkContextMenuRequested(QWidget } } -void ClangModelManagerSupport::updateLanguageClient( - ProjectExplorer::Project *project, const CppEditor::ProjectInfo::ConstPtr &projectInfo) +static Utils::FilePath getJsonDbDir(const ProjectExplorer::Project *project) +{ + static const QString dirName(".qtc_clangd"); + if (!project) { + const QString sessionDirName = Utils::FileUtils::fileSystemFriendlyName( + ProjectExplorer::SessionManager::activeSession()); + return Core::ICore::userResourcePath() / dirName / sessionDirName; // TODO: Make configurable? + } + if (const ProjectExplorer::Target * const target = project->activeTarget()) { + if (const ProjectExplorer::BuildConfiguration * const bc + = target->activeBuildConfiguration()) { + return bc->buildDirectory() / dirName; + } + } + return Utils::FilePath(); +} + +static bool isProjectDataUpToDate( + ProjectExplorer::Project *project, ProjectInfoList projectInfo, + const Utils::FilePath &jsonDbDir) +{ + if (project && !ProjectExplorer::SessionManager::hasProject(project)) + return false; + const ClangdSettings settings(ClangdProjectSettings(project).settings()); + if (!settings.useClangd()) + return false; + if (!sessionModeEnabled() && !project) + return false; + if (sessionModeEnabled() && project) + return false; + const ProjectInfoList newProjectInfo = project + ? ProjectInfoList{CppModelManager::instance()->projectInfo(project)} + : CppModelManager::instance()->projectInfos(); + if (newProjectInfo.size() != projectInfo.size()) + return false; + for (int i = 0; i < projectInfo.size(); ++i) { + if (*projectInfo[i] != *newProjectInfo[i]) + return false; + } + if (getJsonDbDir(project) != jsonDbDir) + return false; + return true; +} + +void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *project) { const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.useClangd()) return; - const auto getJsonDbDir = [project] { - if (const ProjectExplorer::Target * const target = project->activeTarget()) { - if (const ProjectExplorer::BuildConfiguration * const bc - = target->activeBuildConfiguration()) { - return bc->buildDirectory() / ".qtc_clangd"; - } - } - return Utils::FilePath(); - }; + ProjectInfoList projectInfo; + if (sessionModeEnabled()) { + project = nullptr; + projectInfo = CppModelManager::instance()->projectInfos(); + } else { + projectInfo.append(CppModelManager::instance()->projectInfo(project)); + } - const Utils::FilePath jsonDbDir = getJsonDbDir(); + const Utils::FilePath jsonDbDir = getJsonDbDir(project); if (jsonDbDir.isEmpty()) return; const auto generatorWatcher = new QFutureWatcher; connect(generatorWatcher, &QFutureWatcher::finished, - [this, project, projectInfo, getJsonDbDir, jsonDbDir, generatorWatcher] { + [this, project, projectInfo, jsonDbDir, generatorWatcher] { generatorWatcher->deleteLater(); - if (!ProjectExplorer::SessionManager::hasProject(project)) - return; - if (!ClangdSettings(ClangdProjectSettings(project).settings()).useClangd()) - return; - const CppEditor::ProjectInfo::ConstPtr newProjectInfo - = cppModelManager()->projectInfo(project); - if (!newProjectInfo || *newProjectInfo != *projectInfo) - return; - if (getJsonDbDir() != jsonDbDir) + if (!isProjectDataUpToDate(project, projectInfo, jsonDbDir)) return; const GenerateCompilationDbResult result = generatorWatcher->result(); if (!result.error.isEmpty()) { @@ -382,19 +444,13 @@ void ClangModelManagerSupport::updateLanguageClient( client, [client] { updateParserConfig(client); }); connect(client, &Client::initialized, this, [this, client, project, projectInfo, jsonDbDir] { + if (!isProjectDataUpToDate(project, projectInfo, jsonDbDir)) + return; using namespace ProjectExplorer; - if (!SessionManager::hasProject(project)) - return; - if (!CppEditor::ClangdProjectSettings(project).settings().useClangd) - return; - const CppEditor::ProjectInfo::ConstPtr newProjectInfo - = cppModelManager()->projectInfo(project); - if (!newProjectInfo || *newProjectInfo != *projectInfo) - return; - // Acquaint the client with all open C++ documents for this project. - bool hasDocuments = false; + // Acquaint the client with all open C++ documents for this project or session. const ClangdSettings settings(ClangdProjectSettings(project).settings()); + bool hasDocuments = false; for (TextEditor::TextDocument * const doc : allCppDocuments()) { Client * const currentClient = LanguageClientManager::clientForDocument(doc); if (currentClient == client) { @@ -403,6 +459,13 @@ void ClangModelManagerSupport::updateLanguageClient( } if (!settings.sizeIsOkay(doc->filePath())) continue; + if (!project) { + if (currentClient) + currentClient->closeDocument(doc); + LanguageClientManager::openDocumentWithClient(doc, client); + hasDocuments = true; + continue; + } const Project * const docProject = SessionManager::projectForFile(doc->filePath()); if (currentClient && currentClient->project() && currentClient->project() != project @@ -438,7 +501,11 @@ void ClangModelManagerSupport::updateLanguageClient( // clangd oddity: Background indexing only starts after opening a random file. // TODO: changes to the compilation db do not seem to trigger re-indexing. // How to force it? - ProjectNode * const rootNode = project->rootProjectNode(); + ProjectNode *rootNode = nullptr; + if (project) + rootNode = project->rootProjectNode(); + else if (SessionManager::startupProject()) + rootNode = SessionManager::startupProject()->rootProjectNode(); if (!rootNode) return; const Node * const cxxNode = rootNode->findNode([](Node *n) { @@ -456,8 +523,8 @@ void ClangModelManagerSupport::updateLanguageClient( }); const Utils::FilePath includeDir = settings.clangdIncludePath(); - auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, jsonDbDir, - CompilationDbPurpose::CodeModel, + auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, + jsonDbDir, CompilationDbPurpose::CodeModel, warningsConfigForProject(project), globalClangOptions(), includeDir); generatorWatcher->setFuture(future); @@ -465,6 +532,13 @@ void ClangModelManagerSupport::updateLanguageClient( } ClangdClient *ClangModelManagerSupport::clientForProject(const ProjectExplorer::Project *project) +{ + if (sessionModeEnabled()) + project = nullptr; + return clientWithProject(project); +} + +ClangdClient *ClangModelManagerSupport::clientWithProject(const ProjectExplorer::Project *project) { const QList clients = Utils::filtered( LanguageClientManager::clientsForProject(project), @@ -520,48 +594,52 @@ void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client) // workflow, e.g. a git branch switch will hit at least one open file. void ClangModelManagerSupport::watchForExternalChanges() { - const auto projectIsParsing = [](const ProjectExplorer::Project *project) { - const ProjectExplorer::BuildSystem * const bs = project && project->activeTarget() - ? project->activeTarget()->buildSystem() : nullptr; - return bs && (bs->isParsing() || bs->isWaitingForParse()); + static const auto projectIsParsing = [](const ClangdClient *client) { + for (const ProjectExplorer::Project * const p : projectsForClient(client)) { + const ProjectExplorer::BuildSystem * const bs = p && p->activeTarget() + ? p->activeTarget()->buildSystem() : nullptr; + if (bs && (bs->isParsing() || bs->isWaitingForParse())) + return true; + } + return false; }; const auto timer = new QTimer(this); timer->setInterval(3000); - connect(timer, &QTimer::timeout, this, [this, projectIsParsing] { + connect(timer, &QTimer::timeout, this, [this] { const auto clients = m_clientsToRestart; m_clientsToRestart.clear(); for (ClangdClient * const client : clients) { if (client && client->state() != Client::Shutdown && client->state() != Client::ShutdownRequested - && !projectIsParsing(client->project())) { - ProjectExplorer::Project * const project = client->project(); - updateLanguageClient(project, CppModelManager::instance()->projectInfo(project)); + && !projectIsParsing(client)) { + updateLanguageClient(client->project()); } } }); connect(Core::DocumentManager::instance(), &Core::DocumentManager::filesChangedExternally, - this, [this, timer, projectIsParsing](const QSet &files) { + this, [this, timer](const QSet &files) { if (!LanguageClientManager::hasClients()) return; for (const Utils::FilePath &file : files) { const ProjectFile::Kind kind = ProjectFile::classify(file.toString()); if (!ProjectFile::isSource(kind) && !ProjectFile::isHeader(kind)) continue; - const ProjectExplorer::Project * const project + ProjectExplorer::Project * const project = ProjectExplorer::SessionManager::projectForFile(file); if (!project) continue; - // If a project file was changed, it is very likely that we will have to generate - // a new compilation database, in which case the client will be restarted via - // a different code path. - if (projectIsParsing(project)) - return; - ClangdClient * const client = clientForProject(project); if (client && !m_clientsToRestart.contains(client)) { + + // If a project file was changed, it is very likely that we will have to generate + // a new compilation database, in which case the client will be restarted via + // a different code path. + if (projectIsParsing(client)) + return; + m_clientsToRestart.append(client); timer->start(); } @@ -607,14 +685,14 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor) if (textDocument && cppModelManager()->isCppEditor(editor)) { connectToWidgetsMarkContextMenuRequested(editor->widget()); - // TODO: Ensure that not fully loaded documents are updated? - ProjectExplorer::Project * project = ProjectExplorer::SessionManager::projectForFile(document->filePath()); const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.sizeIsOkay(textDocument->filePath())) return; - if (!project) + if (sessionModeEnabled()) + project = nullptr; + else if (!project) project = fallbackProject(); if (ClangdClient * const client = clientForProject(project)) LanguageClientManager::openDocumentWithClient(textDocument, client); @@ -706,12 +784,13 @@ static ClangEditorDocumentProcessors clangProcessors() void ClangModelManagerSupport::onProjectPartsUpdated(ProjectExplorer::Project *project) { QTC_ASSERT(project, return); + + updateLanguageClient(project); + + QStringList projectPartIds; const CppEditor::ProjectInfo::ConstPtr projectInfo = cppModelManager()->projectInfo(project); QTC_ASSERT(projectInfo, return); - updateLanguageClient(project, projectInfo); - - QStringList projectPartIds; for (const CppEditor::ProjectPart::ConstPtr &projectPart : projectInfo->projectParts()) projectPartIds.append(projectPart->id()); onProjectPartsRemoved(projectPartIds); @@ -725,13 +804,20 @@ void ClangModelManagerSupport::onProjectPartsRemoved(const QStringList &projectP void ClangModelManagerSupport::onClangdSettingsChanged() { + const bool sessionMode = sessionModeEnabled(); + for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) { const CppEditor::ClangdSettings settings( CppEditor::ClangdProjectSettings(project).settings()); - ClangdClient * const client = clientForProject(project); + ClangdClient * const client = clientWithProject(project); + if (sessionMode) { + if (client && client->project()) + LanguageClientManager::shutdownClient(client); + continue; + } if (!client) { if (settings.useClangd()) - updateLanguageClient(project, cppModelManager()->projectInfo(project)); + updateLanguageClient(project); continue; } if (!settings.useClangd()) { @@ -739,26 +825,29 @@ void ClangModelManagerSupport::onClangdSettingsChanged() continue; } if (client->settingsData() != settings.data()) - updateLanguageClient(project, cppModelManager()->projectInfo(project)); + updateLanguageClient(project); } - ClangdClient * const fallbackClient = clientForProject(nullptr); - const ClangdSettings &settings = ClangdSettings::instance(); - const auto startNewFallbackClient = [this] { - claimNonProjectSources(new ClangdClient(nullptr, {})); + ClangdClient * const fallbackOrSessionClient = clientForProject(nullptr); + const auto startNewFallbackOrSessionClient = [this, sessionMode] { + if (sessionMode) + updateLanguageClient(nullptr); + else + claimNonProjectSources(new ClangdClient(nullptr, {})); }; - if (!fallbackClient) { + const ClangdSettings &settings = ClangdSettings::instance(); + if (!fallbackOrSessionClient) { if (settings.useClangd()) - startNewFallbackClient(); + startNewFallbackOrSessionClient(); return; } if (!settings.useClangd()) { - LanguageClientManager::shutdownClient(fallbackClient); + LanguageClientManager::shutdownClient(fallbackOrSessionClient); return; } - if (fallbackClient->settingsData() != settings.data()) { - LanguageClientManager::shutdownClient(fallbackClient); - startNewFallbackClient(); + if (fallbackOrSessionClient->settingsData() != settings.data()) { + LanguageClientManager::shutdownClient(fallbackOrSessionClient); + startNewFallbackOrSessionClient(); } } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index f3100283342..d83c7f353ca 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -81,11 +81,11 @@ private: void connectTextDocumentToTranslationUnit(TextEditor::TextDocument *textDocument); void connectToWidgetsMarkContextMenuRequested(QWidget *editorWidget); - void updateLanguageClient(ProjectExplorer::Project *project, - const CppEditor::ProjectInfo::ConstPtr &projectInfo); + void updateLanguageClient(ProjectExplorer::Project *project); void claimNonProjectSources(ClangdClient *client); void watchForExternalChanges(); void watchForInternalChanges(); + static ClangdClient *clientWithProject(const ProjectExplorer::Project *project); Utils::FutureSynchronizer m_generatorSynchronizer; QList> m_clientsToRestart; diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index eb5a8257441..ba8d6ad7763 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -143,17 +143,17 @@ static QJsonObject createFileObject(const FilePath &buildDir, return fileObject; } -GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::ConstPtr projectInfo, - const Utils::FilePath &baseDir, +GenerateCompilationDbResult generateCompilationDB(QList projectInfoList, + FilePath baseDir, CompilationDbPurpose purpose, - const ClangDiagnosticConfig &warningsConfig, - const QStringList &projectOptions, - const FilePath &clangIncludeDir) + ClangDiagnosticConfig warningsConfig, + QStringList projectOptions, + FilePath clangIncludeDir) { QTC_ASSERT(!baseDir.isEmpty(), return GenerateCompilationDbResult(QString(), QCoreApplication::translate("ClangUtils", "Could not retrieve build directory."))); - QTC_ASSERT(projectInfo, return GenerateCompilationDbResult(QString(), - "Could not retrieve project info.")); + QTC_ASSERT(!projectInfoList.isEmpty(), + return GenerateCompilationDbResult(QString(), "Could not retrieve project info.")); QTC_CHECK(baseDir.ensureWritableDir()); QFile compileCommandsFile(baseDir.toString() + "/compile_commands.json"); const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); @@ -166,23 +166,27 @@ GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo:: const UsePrecompiledHeaders usePch = getPchUsage(); const QJsonArray jsonProjectOptions = QJsonArray::fromStringList(projectOptions); - for (ProjectPart::ConstPtr projectPart : projectInfo->projectParts()) { - QStringList args; - const CompilerOptionsBuilder optionsBuilder = clangOptionsBuilder( - *projectPart, warningsConfig, clangIncludeDir); - QJsonArray ppOptions; - if (purpose == CompilationDbPurpose::Project) { - args = projectPartArguments(*projectPart); - } else { - ppOptions = fullProjectPartOptions(projectPartOptions(optionsBuilder), jsonProjectOptions); - } - for (const ProjectFile &projFile : projectPart->files) { - const QJsonObject json = createFileObject(baseDir, args, *projectPart, projFile, - purpose, ppOptions, usePch, - optionsBuilder.isClStyle()); - if (compileCommandsFile.size() > 1) - compileCommandsFile.write(","); - compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed()); + for (const ProjectInfo::ConstPtr &projectInfo : qAsConst(projectInfoList)) { + for (ProjectPart::ConstPtr projectPart : projectInfo->projectParts()) { + QTC_ASSERT(projectInfo, continue); + QStringList args; + const CompilerOptionsBuilder optionsBuilder = clangOptionsBuilder( + *projectPart, warningsConfig, clangIncludeDir); + QJsonArray ppOptions; + if (purpose == CompilationDbPurpose::Project) { + args = projectPartArguments(*projectPart); + } else { + ppOptions = fullProjectPartOptions(projectPartOptions(optionsBuilder), + jsonProjectOptions); + } + for (const ProjectFile &projFile : projectPart->files) { + const QJsonObject json = createFileObject(baseDir, args, *projectPart, projFile, + purpose, ppOptions, usePch, + optionsBuilder.isClStyle()); + if (compileCommandsFile.size() > 1) + compileCommandsFile.write(","); + compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed()); + } } } diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 10b3292e7c1..c2756274ab7 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -65,10 +65,10 @@ public: }; enum class CompilationDbPurpose { Project, CodeModel }; -GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::ConstPtr projectInfo, - const Utils::FilePath &baseDir, CompilationDbPurpose purpose, - const CppEditor::ClangDiagnosticConfig &warningsConfig, const QStringList &projectOptions, - const Utils::FilePath &clangIncludeDir); +GenerateCompilationDbResult generateCompilationDB(QList projectInfo, + Utils::FilePath baseDir, CompilationDbPurpose purpose, + CppEditor::ClangDiagnosticConfig warningsConfig, QStringList projectOptions, + Utils::FilePath clangIncludeDir); class DiagnosticTextInfo { diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 9d5e8543ac6..2e3927af5d1 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -272,6 +272,10 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD innerSessionsLayout->addLayout(buttonsLayout); outerSessionsLayout->addWidget(d->sessionsGroupBox); outerSessionsLayout->addStretch(1); + + const auto separator = new QFrame; + separator->setFrameShape(QFrame::HLine); + layout->addWidget(separator); layout->addLayout(outerSessionsLayout); const auto updateRemoveButtonState = [removeButton, sessionsView] { @@ -303,9 +307,6 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD d->sessionsModel.sort(0); } }); - - // TODO: Remove once the concept is functional. - d->sessionsGroupBox->hide(); } const auto configFilesHelpLabel = new QLabel; diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 5b4e3056973..eb7d618fd21 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -946,7 +946,7 @@ QFuture CppModelManager::updateSourceFiles(const QSet &sourceFile return d->m_internalIndexingSupport->refreshSourceFiles(filteredFiles, mode); } -QList CppModelManager::projectInfos() const +ProjectInfoList CppModelManager::projectInfos() const { QReadLocker locker(&d->m_projectLock); return Utils::transform>(d->m_projectData, diff --git a/src/plugins/cppeditor/cppmodelmanager.h b/src/plugins/cppeditor/cppmodelmanager.h index 8ad9b908e60..73aab2eaec1 100644 --- a/src/plugins/cppeditor/cppmodelmanager.h +++ b/src/plugins/cppeditor/cppmodelmanager.h @@ -99,7 +99,7 @@ public: const QList diagnosticMessages(); - QList projectInfos() const; + ProjectInfoList projectInfos() const; ProjectInfo::ConstPtr projectInfo(ProjectExplorer::Project *project) const; QFuture updateProjectInfo(const ProjectInfo::ConstPtr &newProjectInfo, const QSet &additionalFiles = {}); diff --git a/src/plugins/cppeditor/projectinfo.h b/src/plugins/cppeditor/projectinfo.h index ee28b46881e..d918600c2db 100644 --- a/src/plugins/cppeditor/projectinfo.h +++ b/src/plugins/cppeditor/projectinfo.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -54,4 +55,6 @@ private: const ProjectExplorer::Macros m_defines; }; +using ProjectInfoList = QList; + } // namespace CppEditor diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 49778d8f79d..732d1d66184 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -2051,6 +2051,11 @@ bool Client::referencesShadowFile(const TextEditor::TextDocument *doc, return false; } +bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const +{ + return project() && project()->isKnownFile(filePath); +} + } // namespace LanguageClient #include diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 4f358db10ea..fe07c7ff27e 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -163,6 +163,7 @@ public: void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); void setQuickFixAssistProvider(LanguageClientQuickFixProvider *provider); virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; + virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const; // logging enum class LogTarget { Console, Ui }; diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index 8ec4cd117d0..5b829263af2 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -98,8 +98,7 @@ void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version) if (versionedDiagnostics.version.value_or(version) == version && !versionedDiagnostics.diagnostics.isEmpty()) { Marks &marks = m_marks[filePath]; - const bool isProjectFile = m_client->project() - && m_client->project()->isKnownFile(filePath); + const bool isProjectFile = m_client->fileBelongsToProject(filePath); for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) { const QTextEdit::ExtraSelection selection = createDiagnosticSelection(diagnostic, doc->document());