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

View File

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

View File

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