ClangCodeModel: Use project-specific clangd client, if possible

If we open a file that does not belong to a currently open project, there
is a good chance that the current project's parse context is a better fit
for the file than the fallback client's.

Fixes: QTCREATORBUG-26697
Change-Id: I6c17e275b047602c51364f3203b3f0a3e74a49fc
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2022-02-17 11:46:00 +01:00
parent 3d56b8b54a
commit 8ad7ab2d2a
3 changed files with 33 additions and 19 deletions

View File

@@ -58,6 +58,7 @@
#include <projectexplorer/buildsystem.h> #include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h> #include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
@@ -85,6 +86,13 @@ static CppEditor::CppModelManager *cppModelManager()
return CppEditor::CppModelManager::instance(); return CppEditor::CppModelManager::instance();
} }
static ProjectExplorer::Project *fallbackProject()
{
if (ProjectExplorer::Project * const p = ProjectExplorer::ProjectTree::currentProject())
return p;
return ProjectExplorer::SessionManager::startupProject();
}
static const QList<TextEditor::BaseTextEditor *> allCppEditors() static const QList<TextEditor::BaseTextEditor *> allCppEditors()
{ {
QList<TextEditor::BaseTextEditor *> cppEditors; QList<TextEditor::BaseTextEditor *> cppEditors;
@@ -148,10 +156,7 @@ ClangModelManagerSupport::ClangModelManagerSupport()
connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject, connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject,
this, &ClangModelManagerSupport::onAboutToRemoveProject); this, &ClangModelManagerSupport::onAboutToRemoveProject);
connect(sessionManager, &ProjectExplorer::SessionManager::projectRemoved, connect(sessionManager, &ProjectExplorer::SessionManager::projectRemoved,
this, [this] { this, [this] { claimNonProjectSources(clientForProject(fallbackProject())); });
if (ClangdClient * const fallbackClient = clientForProject(nullptr))
claimNonProjectSources(fallbackClient);
});
CppEditor::ClangdSettings::setDefaultClangdPath(Core::ICore::clangdExecutable(CLANG_BINDIR)); CppEditor::ClangdSettings::setDefaultClangdPath(Core::ICore::clangdExecutable(CLANG_BINDIR));
connect(&CppEditor::ClangdSettings::instance(), &CppEditor::ClangdSettings::changed, connect(&CppEditor::ClangdSettings::instance(), &CppEditor::ClangdSettings::changed,
@@ -369,12 +374,15 @@ void ClangModelManagerSupport::updateLanguageClient(
// Acquaint the client with all open C++ documents for this project. // Acquaint the client with all open C++ documents for this project.
bool hasDocuments = false; bool hasDocuments = false;
for (TextEditor::BaseTextEditor * const editor : allCppEditors()) { for (TextEditor::BaseTextEditor * const editor : allCppEditors()) {
const Utils::FilePath filePath = editor->textDocument()->filePath(); TextEditor::TextDocument * const doc = editor->textDocument();
if (!project->isKnownFile(filePath)) const Client * const currentClient = LanguageClientManager::clientForDocument(doc);
continue; if (!currentClient || !currentClient->project()
LanguageClientManager::openDocumentWithClient(editor->textDocument(), client); || currentClient->state() != Client::Initialized
ClangEditorDocumentProcessor::clearTextMarks(filePath); || project->isKnownFile(doc->filePath())) {
hasDocuments = true; LanguageClientManager::openDocumentWithClient(editor->textDocument(), client);
ClangEditorDocumentProcessor::clearTextMarks(doc->filePath());
hasDocuments = true;
}
} }
if (client->state() == Client::Initialized) if (client->state() == Client::Initialized)
@@ -443,7 +451,7 @@ ClangdClient *ClangModelManagerSupport::clientForProject(
ClangdClient *ClangModelManagerSupport::clientForFile(const Utils::FilePath &file) const ClangdClient *ClangModelManagerSupport::clientForFile(const Utils::FilePath &file) const
{ {
return clientForProject(ProjectExplorer::SessionManager::projectForFile(file)); return qobject_cast<ClangdClient *>(LanguageClientManager::clientForFilePath(file));
} }
ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project, ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project,
@@ -454,15 +462,19 @@ ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *p
return client; return client;
} }
void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *fallbackClient) void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client)
{ {
if (!client)
return;
for (TextEditor::BaseTextEditor * const editor : allCppEditors()) { for (TextEditor::BaseTextEditor * const editor : allCppEditors()) {
if (ProjectExplorer::SessionManager::projectForFile(editor->textDocument()->filePath())) if (Client * const currentClient = LanguageClientManager::clientForDocument(
editor->textDocument());
currentClient && currentClient->state() == Client::Initialized
&& (currentClient == client || currentClient->project())) {
continue; continue;
if (!fallbackClient->documentOpen(editor->textDocument())) {
ClangEditorDocumentProcessor::clearTextMarks(editor->textDocument()->filePath());
fallbackClient->openDocument(editor->textDocument());
} }
ClangEditorDocumentProcessor::clearTextMarks(editor->textDocument()->filePath());
client->openDocument(editor->textDocument());
} }
} }
@@ -562,8 +574,10 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
// TODO: Ensure that not fully loaded documents are updated? // TODO: Ensure that not fully loaded documents are updated?
ProjectExplorer::Project * const project ProjectExplorer::Project * project
= ProjectExplorer::SessionManager::projectForFile(document->filePath()); = ProjectExplorer::SessionManager::projectForFile(document->filePath());
if (!project)
project = fallbackProject();
if (ClangdClient * const client = clientForProject(project)) if (ClangdClient * const client = clientForProject(project))
LanguageClientManager::openDocumentWithClient(textDocument, client); LanguageClientManager::openDocumentWithClient(textDocument, client);
} }

View File

@@ -134,7 +134,7 @@ private:
void updateLanguageClient(ProjectExplorer::Project *project, void updateLanguageClient(ProjectExplorer::Project *project,
const CppEditor::ProjectInfo::ConstPtr &projectInfo); const CppEditor::ProjectInfo::ConstPtr &projectInfo);
ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir); ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
void claimNonProjectSources(ClangdClient *fallbackClient); void claimNonProjectSources(ClangdClient *client);
void watchForExternalChanges(); void watchForExternalChanges();
void watchForInternalChanges(); void watchForInternalChanges();

View File

@@ -2036,7 +2036,7 @@ void ClangdTestExternalChanges::test()
QVERIFY(waitForSignalOrTimeout(ClangModelManagerSupport::instance(), QVERIFY(waitForSignalOrTimeout(ClangModelManagerSupport::instance(),
&ClangModelManagerSupport::createdClient, timeOutInMs())); &ClangModelManagerSupport::createdClient, timeOutInMs()));
ClangdClient * const newClient = ClangModelManagerSupport::instance() ClangdClient * const newClient = ClangModelManagerSupport::instance()
->clientForFile(filePath("main.cpp")); ->clientForProject(project());
QVERIFY(newClient); QVERIFY(newClient);
QVERIFY(newClient != oldClient); QVERIFY(newClient != oldClient);
newClient->enableTesting(); newClient->enableTesting();