forked from qt-creator/qt-creator
ClangCodeModel: Start a fallback clangd for files without a project
These were still being served by the old code model even when clangd support was enabled. Change-Id: I5f01b6a7071b90c374750f93435299755cabe3e9 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "clangdiagnosticmanager.h"
|
#include "clangdiagnosticmanager.h"
|
||||||
#include "clangtextmark.h"
|
#include "clangtextmark.h"
|
||||||
|
#include "clangutils.h"
|
||||||
|
|
||||||
#include <clangsupport/sourcelocationscontainer.h>
|
#include <clangsupport/sourcelocationscontainer.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
#include <cplusplus/FindUsages.h>
|
#include <cplusplus/FindUsages.h>
|
||||||
#include <cpptools/cppeditorwidgetinterface.h>
|
#include <cpptools/cppeditorwidgetinterface.h>
|
||||||
#include <cpptools/cppfindreferences.h>
|
#include <cpptools/cppfindreferences.h>
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
#include <cpptools/cpptoolsreuse.h>
|
#include <cpptools/cpptoolsreuse.h>
|
||||||
#include <cpptools/cppvirtualfunctionassistprovider.h>
|
#include <cpptools/cppvirtualfunctionassistprovider.h>
|
||||||
#include <cpptools/cppvirtualfunctionproposalitem.h>
|
#include <cpptools/cppvirtualfunctionproposalitem.h>
|
||||||
@@ -729,6 +731,13 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
|||||||
"text/x-c++hdr", "text/x-c++src", "text/x-objc++src", "text/x-objcsrc"};
|
"text/x-c++hdr", "text/x-c++src", "text/x-objc++src", "text/x-objcsrc"};
|
||||||
setSupportedLanguage(langFilter);
|
setSupportedLanguage(langFilter);
|
||||||
setActivateDocumentAutomatically(true);
|
setActivateDocumentAutomatically(true);
|
||||||
|
if (!project) {
|
||||||
|
QJsonObject initOptions;
|
||||||
|
const auto clangOptions = createClangOptions(
|
||||||
|
*CppTools::CppModelManager::instance()->fallbackProjectPart(), {});
|
||||||
|
initOptions.insert("fallbackFlags", QJsonArray::fromStringList(clangOptions.second));
|
||||||
|
setInitializationOptions(initOptions);
|
||||||
|
}
|
||||||
ClientCapabilities caps = Client::defaultClientCapabilities();
|
ClientCapabilities caps = Client::defaultClientCapabilities();
|
||||||
Utils::optional<TextDocumentClientCapabilities> textCaps = caps.textDocument();
|
Utils::optional<TextDocumentClientCapabilities> textCaps = caps.textDocument();
|
||||||
if (textCaps) {
|
if (textCaps) {
|
||||||
|
|||||||
@@ -81,6 +81,23 @@ static CppTools::CppModelManager *cppModelManager()
|
|||||||
return CppTools::CppModelManager::instance();
|
return CppTools::CppModelManager::instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QList<TextEditor::BaseTextEditor *> allCppEditors()
|
||||||
|
{
|
||||||
|
QList<TextEditor::BaseTextEditor *> cppEditors;
|
||||||
|
for (const Core::DocumentModel::Entry * const entry : Core::DocumentModel::entries()) {
|
||||||
|
const auto textDocument = qobject_cast<TextEditor::TextDocument *>(entry->document);
|
||||||
|
if (!textDocument)
|
||||||
|
continue;
|
||||||
|
if (const auto cppEditor = qobject_cast<TextEditor::BaseTextEditor *>(Utils::findOrDefault(
|
||||||
|
Core::DocumentModel::editorsForDocument(textDocument), [](Core::IEditor *editor) {
|
||||||
|
return CppTools::CppModelManager::isCppEditor(editor);
|
||||||
|
}))) {
|
||||||
|
cppEditors << cppEditor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cppEditors;
|
||||||
|
}
|
||||||
|
|
||||||
ClangModelManagerSupport::ClangModelManagerSupport()
|
ClangModelManagerSupport::ClangModelManagerSupport()
|
||||||
: m_completionAssistProvider(m_communicator, CompletionType::Other)
|
: m_completionAssistProvider(m_communicator, CompletionType::Other)
|
||||||
, m_functionHintAssistProvider(m_communicator, CompletionType::FunctionHint)
|
, m_functionHintAssistProvider(m_communicator, CompletionType::FunctionHint)
|
||||||
@@ -119,6 +136,11 @@ ClangModelManagerSupport::ClangModelManagerSupport()
|
|||||||
this, &ClangModelManagerSupport::onProjectAdded);
|
this, &ClangModelManagerSupport::onProjectAdded);
|
||||||
connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject,
|
connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject,
|
||||||
this, &ClangModelManagerSupport::onAboutToRemoveProject);
|
this, &ClangModelManagerSupport::onAboutToRemoveProject);
|
||||||
|
connect(sessionManager, &ProjectExplorer::SessionManager::projectRemoved,
|
||||||
|
this, [this] {
|
||||||
|
if (ClangdClient * const fallbackClient = clientForProject(nullptr))
|
||||||
|
claimNonProjectSources(fallbackClient);
|
||||||
|
});
|
||||||
|
|
||||||
CppTools::ClangdSettings::setDefaultClangdPath(Utils::FilePath::fromString(
|
CppTools::ClangdSettings::setDefaultClangdPath(Utils::FilePath::fromString(
|
||||||
Core::ICore::clangdExecutable(CLANG_BINDIR)));
|
Core::ICore::clangdExecutable(CLANG_BINDIR)));
|
||||||
@@ -128,8 +150,9 @@ ClangModelManagerSupport::ClangModelManagerSupport()
|
|||||||
connect(settings, &CppTools::CppCodeModelSettings::clangDiagnosticConfigsInvalidated,
|
connect(settings, &CppTools::CppCodeModelSettings::clangDiagnosticConfigsInvalidated,
|
||||||
this, &ClangModelManagerSupport::onDiagnosticConfigsInvalidated);
|
this, &ClangModelManagerSupport::onDiagnosticConfigsInvalidated);
|
||||||
|
|
||||||
// TODO: Enable this once we do document-level stuff with clangd (highlighting etc)
|
if (CppTools::ClangdSettings::instance().useClangd())
|
||||||
// createClient(nullptr, {});
|
createClient(nullptr, {});
|
||||||
|
|
||||||
m_generatorSynchronizer.setCancelOnWait(true);
|
m_generatorSynchronizer.setCancelOnWait(true);
|
||||||
new ClangdQuickFixFactory(); // memory managed by CppEditor::g_cppQuickFixFactories
|
new ClangdQuickFixFactory(); // memory managed by CppEditor::g_cppQuickFixFactories
|
||||||
}
|
}
|
||||||
@@ -291,7 +314,7 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr
|
|||||||
if (Client * const oldClient = clientForProject(project))
|
if (Client * const oldClient = clientForProject(project))
|
||||||
LanguageClientManager::shutdownClient(oldClient);
|
LanguageClientManager::shutdownClient(oldClient);
|
||||||
ClangdClient * const client = createClient(project, jsonDbDir);
|
ClangdClient * const client = createClient(project, jsonDbDir);
|
||||||
connect(client, &Client::initialized, this, [client, project, projectInfo, jsonDbDir] {
|
connect(client, &Client::initialized, this, [this, client, project, projectInfo, jsonDbDir] {
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
if (!SessionManager::hasProject(project))
|
if (!SessionManager::hasProject(project))
|
||||||
return;
|
return;
|
||||||
@@ -301,22 +324,15 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Acquaint the client with all open C++ documents for this project.
|
// Acquaint the client with all open C++ documents for this project.
|
||||||
|
ClangdClient * const fallbackClient = clientForProject(nullptr);
|
||||||
bool hasDocuments = false;
|
bool hasDocuments = false;
|
||||||
for (const Core::DocumentModel::Entry * const entry : Core::DocumentModel::entries()) {
|
for (TextEditor::BaseTextEditor * const editor : allCppEditors()) {
|
||||||
const auto textDocument = qobject_cast<TextEditor::TextDocument *>(entry->document);
|
if (!project->isKnownFile(editor->textDocument()->filePath()))
|
||||||
if (!textDocument)
|
|
||||||
continue;
|
continue;
|
||||||
const bool isCppDocument = Utils::contains(
|
if (fallbackClient && fallbackClient->documentOpen(editor->textDocument()))
|
||||||
Core::DocumentModel::editorsForDocument(textDocument),
|
fallbackClient->closeDocument(editor->textDocument());
|
||||||
[](Core::IEditor *editor) {
|
client->openDocument(editor->textDocument());
|
||||||
return CppTools::CppModelManager::isCppEditor(editor);
|
ClangEditorDocumentProcessor::clearTextMarks(editor->textDocument()->filePath());
|
||||||
});
|
|
||||||
if (!isCppDocument)
|
|
||||||
continue;
|
|
||||||
if (!project->isKnownFile(entry->fileName()))
|
|
||||||
continue;
|
|
||||||
client->openDocument(textDocument);
|
|
||||||
ClangEditorDocumentProcessor::clearTextMarks(textDocument->filePath());
|
|
||||||
hasDocuments = true;
|
hasDocuments = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,6 +392,18 @@ ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *p
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *fallbackClient)
|
||||||
|
{
|
||||||
|
for (TextEditor::BaseTextEditor * const editor : allCppEditors()) {
|
||||||
|
if (ProjectExplorer::SessionManager::projectForFile(editor->textDocument()->filePath()))
|
||||||
|
continue;
|
||||||
|
if (!fallbackClient->documentOpen(editor->textDocument())) {
|
||||||
|
ClangEditorDocumentProcessor::clearTextMarks(editor->textDocument()->filePath());
|
||||||
|
fallbackClient->openDocument(editor->textDocument());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
|
void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(editor, return);
|
QTC_ASSERT(editor, return);
|
||||||
@@ -389,6 +417,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?
|
||||||
|
|
||||||
|
// TODO: If the file does not belong to any project and it is a header file,
|
||||||
|
// it might make sense to check whether the file is included by any file
|
||||||
|
// that does belong to a project, and if so, use the respective client
|
||||||
|
// instead. Is this feasible?
|
||||||
ProjectExplorer::Project * const project
|
ProjectExplorer::Project * const project
|
||||||
= ProjectExplorer::SessionManager::projectForFile(document->filePath());
|
= ProjectExplorer::SessionManager::projectForFile(document->filePath());
|
||||||
if (Client * const client = clientForProject(project))
|
if (Client * const client = clientForProject(project))
|
||||||
@@ -597,7 +629,6 @@ void ClangModelManagerSupport::onProjectPartsRemoved(const QStringList &projectP
|
|||||||
|
|
||||||
void ClangModelManagerSupport::onClangdSettingsChanged()
|
void ClangModelManagerSupport::onClangdSettingsChanged()
|
||||||
{
|
{
|
||||||
// TODO: Handle also project-less client
|
|
||||||
for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) {
|
for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) {
|
||||||
const CppTools::ClangdSettings settings(
|
const CppTools::ClangdSettings settings(
|
||||||
CppTools::ClangdProjectSettings(project).settings());
|
CppTools::ClangdProjectSettings(project).settings());
|
||||||
@@ -614,6 +645,25 @@ void ClangModelManagerSupport::onClangdSettingsChanged()
|
|||||||
if (client->settingsData() != settings.data())
|
if (client->settingsData() != settings.data())
|
||||||
updateLanguageClient(project, cppModelManager()->projectInfo(project));
|
updateLanguageClient(project, cppModelManager()->projectInfo(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClangdClient * const fallbackClient = clientForProject(nullptr);
|
||||||
|
const CppTools::ClangdSettings &settings = CppTools::ClangdSettings::instance();
|
||||||
|
const auto startNewFallbackClient = [this] {
|
||||||
|
claimNonProjectSources(createClient(nullptr, {}));
|
||||||
|
};
|
||||||
|
if (!fallbackClient) {
|
||||||
|
if (settings.useClangd())
|
||||||
|
startNewFallbackClient();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!settings.useClangd()) {
|
||||||
|
LanguageClientManager::shutdownClient(fallbackClient);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fallbackClient->settingsData() != settings.data()) {
|
||||||
|
LanguageClientManager::shutdownClient(fallbackClient);
|
||||||
|
startNewFallbackClient();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClangEditorDocumentProcessors clangProcessorsWithDiagnosticConfig(
|
static ClangEditorDocumentProcessors clangProcessorsWithDiagnosticConfig(
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ private:
|
|||||||
void updateLanguageClient(ProjectExplorer::Project *project,
|
void updateLanguageClient(ProjectExplorer::Project *project,
|
||||||
const CppTools::ProjectInfo &projectInfo);
|
const CppTools::ProjectInfo &projectInfo);
|
||||||
ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
|
ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
|
||||||
|
void claimNonProjectSources(ClangdClient *fallbackClient);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
|
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
|
||||||
|
|||||||
@@ -522,7 +522,9 @@ private:
|
|||||||
void addLanguageOptions()
|
void addLanguageOptions()
|
||||||
{
|
{
|
||||||
// Determine file kind with respect to ambiguous headers.
|
// Determine file kind with respect to ambiguous headers.
|
||||||
CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::classify(m_filePath);
|
CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::Unclassified;
|
||||||
|
if (!m_filePath.isEmpty())
|
||||||
|
fileKind = CppTools::ProjectFile::classify(m_filePath);
|
||||||
if (fileKind == CppTools::ProjectFile::AmbiguousHeader) {
|
if (fileKind == CppTools::ProjectFile::AmbiguousHeader) {
|
||||||
fileKind = m_projectPart.languageVersion <= ::Utils::LanguageVersion::LatestC
|
fileKind = m_projectPart.languageVersion <= ::Utils::LanguageVersion::LatestC
|
||||||
? CppTools::ProjectFile::CHeader
|
? CppTools::ProjectFile::CHeader
|
||||||
|
|||||||
Reference in New Issue
Block a user