ClangCodeModel: Add experimental clangd support

If the user has enabled clangd (default is off), we start up one instance
per project when it is opened/changed (including build config switches),
and trigger background indexing.
So far, the index is used to provide results for locators and "Find
Usages".
Per-document functionality such as semantic highlighting and completion
is still provided by libclang.

Change-Id: I12532fca1b9c6278baab560e7238cba6189cde9f
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2021-02-23 13:51:41 +01:00
parent 8bacd9bdc4
commit ecafdb7543
40 changed files with 881 additions and 190 deletions

View File

@@ -292,7 +292,7 @@ void Client::initialize()
QTC_ASSERT(m_state == Uninitialized, return);
qCDebug(LOGLSPCLIENT) << "initializing language server " << m_displayName;
InitializeParams params;
params.setCapabilities(generateClientCapabilities());
params.setCapabilities(m_clientCapabilities);
params.setInitializationOptions(m_initializationOptions);
if (m_project) {
params.setRootUri(DocumentUri::fromFilePath(m_project->projectDirectory()));
@@ -333,6 +333,16 @@ Client::State Client::state() const
return m_state;
}
ClientCapabilities Client::defaultClientCapabilities()
{
return generateClientCapabilities();
}
void Client::setClientCapabilities(const LanguageServerProtocol::ClientCapabilities &caps)
{
m_clientCapabilities = caps;
}
void Client::openDocument(TextEditor::TextDocument *document)
{
using namespace TextEditor;
@@ -532,6 +542,9 @@ void Client::requestDocumentHighlights(TextEditor::TextEditorWidget *widget)
void Client::activateDocument(TextEditor::TextDocument *document)
{
if (!m_documentActionsEnabled)
return;
auto uri = DocumentUri::fromFilePath(document->filePath());
m_diagnosticManager.showDiagnostics(uri);
SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities());
@@ -558,6 +571,9 @@ void Client::activateDocument(TextEditor::TextDocument *document)
void Client::deactivateDocument(TextEditor::TextDocument *document)
{
if (!m_documentActionsEnabled)
return;
m_diagnosticManager.hideDiagnostics(document);
resetAssistProviders(document);
document->setFormatter(nullptr);
@@ -1241,6 +1257,9 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
void Client::handleDiagnostics(const PublishDiagnosticsParams &params)
{
if (!m_documentActionsEnabled)
return;
const DocumentUri &uri = params.uri();
const QList<Diagnostic> &diagnostics = params.diagnostics();
@@ -1253,6 +1272,9 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams &params)
void Client::handleSemanticHighlight(const SemanticHighlightingParams &params)
{
if (!m_documentActionsEnabled)
return;
DocumentUri uri;
LanguageClientValue<int> version;
auto textDocument = params.textDocument();
@@ -1283,6 +1305,9 @@ void Client::handleSemanticHighlight(const SemanticHighlightingParams &params)
void Client::rehighlight()
{
if (!m_documentActionsEnabled)
return;
using namespace TextEditor;
for (auto it = m_highlights.begin(), end = m_highlights.end(); it != end; ++it) {
if (TextDocument *doc = TextDocument::textDocumentForFilePath(it.key().toFilePath())) {

View File

@@ -113,11 +113,17 @@ public:
bool reachable() const { return m_state == Initialized; }
// capabilities
static LanguageServerProtocol::ClientCapabilities defaultClientCapabilities();
void setClientCapabilities(const LanguageServerProtocol::ClientCapabilities &caps);
const LanguageServerProtocol::ServerCapabilities &capabilities() const;
const DynamicCapabilities &dynamicCapabilities() const;
void registerCapabilities(const QList<LanguageServerProtocol::Registration> &registrations);
void unregisterCapabilities(const QList<LanguageServerProtocol::Unregistration> &unregistrations);
void setLocatorsEnabled(bool enabled) { m_locatorsEnabled = enabled; }
bool locatorsEnabled() const { return m_locatorsEnabled; }
void setDocumentActionsEnabled(bool enabled) { m_documentActionsEnabled = enabled; }
// document synchronization
void setSupportedLanguage(const LanguageFilter &filter);
void setActivateDocumentAutomatically(bool enabled);
@@ -226,6 +232,7 @@ private:
QMap<TextEditor::TextEditorWidget *, QTimer *> m_documentHighlightsTimer;
QTimer m_documentUpdateTimer;
Utils::Id m_id;
LanguageServerProtocol::ClientCapabilities m_clientCapabilities = defaultClientCapabilities();
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
DynamicCapabilities m_dynamicCapabilities;
struct AssistProviders
@@ -250,6 +257,8 @@ private:
ProgressManager m_progressManager;
bool m_activateDocAutomatically = false;
SemanticTokenSupport m_tokentSupport;
bool m_locatorsEnabled = true;
bool m_documentActionsEnabled = true;
};
} // namespace LanguageClient

View File

@@ -57,4 +57,6 @@ QtcPlugin {
"semantichighlightsupport.cpp",
"semantichighlightsupport.h",
]
Export { Depends { name: "LanguageServerProtocol" } }
}

View File

@@ -40,6 +40,7 @@
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <texteditor/textmark.h>
#include <utils/algorithm.h>
#include <utils/executeondestruction.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/theme/theme.h>
@@ -375,6 +376,14 @@ Client *LanguageClientManager::clientForUri(const DocumentUri &uri)
return clientForFilePath(uri.toFilePath());
}
const QList<Client *> LanguageClientManager::clientsForProject(
const ProjectExplorer::Project *project)
{
return Utils::filtered(managerInstance->m_clients, [project](const Client *c) {
return c->project() == project;
}).toList();
}
void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *document, Client *client)
{
Client *currentClient = clientForDocument(document);

View File

@@ -84,6 +84,7 @@ public:
static Client *clientForDocument(TextEditor::TextDocument *document);
static Client *clientForFilePath(const Utils::FilePath &filePath);
static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri);
static const QList<Client *> clientsForProject(const ProjectExplorer::Project *project);
///
/// \brief openDocumentWithClient

View File

@@ -25,6 +25,8 @@
#pragma once
#include "languageclient_global.h"
#include <texteditor/textdocument.h>
#include <languageserverprotocol/languagefeatures.h>
@@ -38,7 +40,7 @@ namespace LanguageClient {
class Client;
class SymbolSupport
class LANGUAGECLIENT_EXPORT SymbolSupport
{
Q_DECLARE_TR_FUNCTIONS(SymbolSupport)
public:

View File

@@ -214,6 +214,18 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector<SymbolKind> &filter
}
void WorkspaceLocatorFilter::prepareSearch(const QString &entry)
{
prepareSearch(entry, LanguageClientManager::clients(), false);
}
void WorkspaceLocatorFilter::prepareSearch(const QString &entry, const QVector<Client *> &clients)
{
prepareSearch(entry, clients, true);
}
void WorkspaceLocatorFilter::prepareSearch(const QString &entry,
const QVector<Client *> &clients,
bool force)
{
m_pendingRequests.clear();
m_results.clear();
@@ -222,7 +234,11 @@ void WorkspaceLocatorFilter::prepareSearch(const QString &entry)
params.setQuery(entry);
QMutexLocker locker(&m_mutex);
for (auto client : Utils::filtered(LanguageClientManager::clients(), &Client::reachable)) {
for (auto client : qAsConst(clients)) {
if (!client->reachable())
continue;
if (!(force || client->locatorsEnabled()))
continue;
Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>> capability
= client->capabilities().workspaceSymbolProvider();
if (!capability.has_value())

View File

@@ -74,13 +74,16 @@ private:
Utils::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols;
};
class WorkspaceLocatorFilter : public Core::ILocatorFilter
class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter
{
Q_OBJECT
public:
WorkspaceLocatorFilter();
/// request workspace symbols for all clients with enabled locator
void prepareSearch(const QString &entry) override;
/// force request workspace symbols for all given clients
void prepareSearch(const QString &entry, const QVector<Client *> &clients);
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry) override;
void accept(Core::LocatorFilterEntry selection,
@@ -95,6 +98,7 @@ protected:
explicit WorkspaceLocatorFilter(const QVector<LanguageServerProtocol::SymbolKind> &filter);
private:
void prepareSearch(const QString &entry, const QVector<Client *> &clients, bool force);
void handleResponse(Client *client,
const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response);
@@ -104,13 +108,13 @@ private:
QVector<LanguageServerProtocol::SymbolKind> m_filterKinds;
};
class WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter
class LANGUAGECLIENT_EXPORT WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter
{
public:
WorkspaceClassLocatorFilter();
};
class WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter
class LANGUAGECLIENT_EXPORT WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter
{
public:
WorkspaceMethodLocatorFilter();