From 887db6b419b443bfd7f1fd7d95632d6ad18c603c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 6 Dec 2022 15:16:41 +0100 Subject: [PATCH] LSP: implement call hierarchy Fixes: QTCREATORBUG-11660 Change-Id: I006872ba598a807f1f9f16d134fe9ce4fe5dd09d Reviewed-by: Christian Kandeler --- .../languageserverprotocol/CMakeLists.txt | 1 + .../languageserverprotocol/callhierarchy.cpp | 28 ++ .../languageserverprotocol/callhierarchy.h | 108 +++++++ .../clientcapabilities.h | 6 + src/libs/languageserverprotocol/jsonkeys.h | 6 + .../languageserverprotocol.qbs | 2 + .../servercapabilities.cpp | 22 ++ .../servercapabilities.h | 4 + src/plugins/languageclient/CMakeLists.txt | 1 + src/plugins/languageclient/callhierarchy.cpp | 291 ++++++++++++++++++ src/plugins/languageclient/callhierarchy.h | 20 ++ src/plugins/languageclient/client.cpp | 1 + src/plugins/languageclient/languageclient.qbs | 2 + .../languageclient/languageclientplugin.h | 4 +- 14 files changed, 494 insertions(+), 2 deletions(-) create mode 100644 src/libs/languageserverprotocol/callhierarchy.cpp create mode 100644 src/libs/languageserverprotocol/callhierarchy.h create mode 100644 src/plugins/languageclient/callhierarchy.cpp create mode 100644 src/plugins/languageclient/callhierarchy.h diff --git a/src/libs/languageserverprotocol/CMakeLists.txt b/src/libs/languageserverprotocol/CMakeLists.txt index d4c2d635d24..a3031413a46 100644 --- a/src/libs/languageserverprotocol/CMakeLists.txt +++ b/src/libs/languageserverprotocol/CMakeLists.txt @@ -2,6 +2,7 @@ add_qtc_library(LanguageServerProtocol DEPENDS Utils SOURCES basemessage.cpp basemessage.h + callhierarchy.cpp callhierarchy.h client.cpp client.h clientcapabilities.cpp clientcapabilities.h completion.cpp completion.h diff --git a/src/libs/languageserverprotocol/callhierarchy.cpp b/src/libs/languageserverprotocol/callhierarchy.cpp new file mode 100644 index 00000000000..fc61faf6644 --- /dev/null +++ b/src/libs/languageserverprotocol/callhierarchy.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "callhierarchy.h" + +namespace LanguageServerProtocol { + +bool CallHierarchyItem::isValid() const +{ + return contains(nameKey) && contains(symbolKindKey) && contains(rangeKey) && contains(uriKey) + && contains(selectionRangeKey); +} + +PrepareCallHierarchyRequest::PrepareCallHierarchyRequest(const TextDocumentPositionParams ¶ms) + : Request(methodName, params) +{} + +CallHierarchyIncomingCallsRequest::CallHierarchyIncomingCallsRequest( + const CallHierarchyCallsParams ¶ms) + : Request(methodName, params) +{} + +CallHierarchyOutgoingCallsRequest::CallHierarchyOutgoingCallsRequest( + const CallHierarchyCallsParams ¶ms) + : Request(methodName, params) +{} + +} // namespace LanguageServerProtocol diff --git a/src/libs/languageserverprotocol/callhierarchy.h b/src/libs/languageserverprotocol/callhierarchy.h new file mode 100644 index 00000000000..a284611a127 --- /dev/null +++ b/src/libs/languageserverprotocol/callhierarchy.h @@ -0,0 +1,108 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "jsonrpcmessages.h" + +namespace LanguageServerProtocol { + +class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyItem : public JsonObject +{ +public: + using JsonObject::JsonObject; + + QString name() const { return typedValue(nameKey); } + void setName(const QString &name) { insert(nameKey, name); } + + SymbolKind symbolKind() const { return SymbolKind(typedValue(symbolKindKey)); } + void setSymbolKind(const SymbolKind &symbolKind) { insert(symbolKindKey, int(symbolKind)); } + + Range range() const { return typedValue(rangeKey); } + void setRange(const Range &range) { insert(rangeKey, range); } + + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + Range selectionRange() const { return typedValue(selectionRangeKey); } + void setSelectionRange(Range selectionRange) { insert(selectionRangeKey, selectionRange); } + + std::optional detail() const { return optionalValue(detailKey); } + void setDetail(const QString &detail) { insert(detailKey, detail); } + void clearDetail() { remove(detailKey); } + + std::optional> children() const + { return optionalArray(childrenKey); } + void setChildren(const QList &children) { insertArray(childrenKey, children); } + void clearChildren() { remove(childrenKey); } + + bool isValid() const override; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT PrepareCallHierarchyRequest : public Request< + LanguageClientArray, std::nullptr_t, TextDocumentPositionParams> +{ +public: + explicit PrepareCallHierarchyRequest(const TextDocumentPositionParams ¶ms); + using Request::Request; + constexpr static const char methodName[] = "textDocument/prepareCallHierarchy"; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyCallsParams : public JsonObject +{ +public: + using JsonObject::JsonObject; + + CallHierarchyItem item() const { return typedValue(itemKey); } + void setItem(const CallHierarchyItem &item) { insert(itemKey, item); } + + bool isValid() const override { return contains(itemKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyIncomingCall : public JsonObject +{ +public: + using JsonObject::JsonObject; + + CallHierarchyItem from() const { return typedValue(fromKey); } + void setFrom(const CallHierarchyItem &from) { insert(fromKey, from); } + + QList fromRanges() const { return array(fromRangesKey); } + void setFromRanges(const QList &fromRanges) { insertArray(fromRangesKey, fromRanges); } + + bool isValid() const override { return contains(fromRangesKey) && contains(fromRangesKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyIncomingCallsRequest : public Request< + LanguageClientArray, std::nullptr_t, CallHierarchyCallsParams> +{ +public: + explicit CallHierarchyIncomingCallsRequest(const CallHierarchyCallsParams ¶ms); + using Request::Request; + constexpr static const char methodName[] = "callHierarchy/incomingCalls"; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyOutgoingCall : public JsonObject +{ +public: + using JsonObject::JsonObject; + + CallHierarchyItem to() const { return typedValue(toKey); } + void setTo(const CallHierarchyItem &to) { insert(toKey, to); } + + QList fromRanges() const { return array(fromRangesKey); } + void setFromRanges(const QList &fromRanges) { insertArray(fromRangesKey, fromRanges); } + + bool isValid() const override { return contains(fromRangesKey) && contains(fromRangesKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyOutgoingCallsRequest : public Request< + LanguageClientArray, std::nullptr_t, CallHierarchyCallsParams> +{ +public: + explicit CallHierarchyOutgoingCallsRequest(const CallHierarchyCallsParams ¶ms); + using Request::Request; + constexpr static const char methodName[] = "callHierarchy/outgoingCalls"; +}; + +} // namespace LanguageServerProtocol diff --git a/src/libs/languageserverprotocol/clientcapabilities.h b/src/libs/languageserverprotocol/clientcapabilities.h index a9df171b495..92f78ae0562 100644 --- a/src/libs/languageserverprotocol/clientcapabilities.h +++ b/src/libs/languageserverprotocol/clientcapabilities.h @@ -504,6 +504,12 @@ public: std::optional semanticTokens() const; void setSemanticTokens(const SemanticTokensClientCapabilities &semanticTokens); void clearSemanticTokens() { remove(semanticTokensKey); } + + std::optional callHierarchy() const + { return optionalValue(callHierarchyKey); } + void setCallHierarchy(const DynamicRegistrationCapabilities &callHierarchy) + { insert(callHierarchyKey, callHierarchy); } + void clearCallHierarchy() { remove(callHierarchyKey); } }; class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensWorkspaceClientCapabilities : public JsonObject diff --git a/src/libs/languageserverprotocol/jsonkeys.h b/src/libs/languageserverprotocol/jsonkeys.h index 2dbbecb1efe..302c57bc209 100644 --- a/src/libs/languageserverprotocol/jsonkeys.h +++ b/src/libs/languageserverprotocol/jsonkeys.h @@ -16,6 +16,8 @@ constexpr char16_t appliedKey[] = u"applied"; constexpr char16_t applyEditKey[] = u"applyEdit"; constexpr char16_t argumentsKey[] = u"arguments"; constexpr char16_t blueKey[] = u"blue"; +constexpr char16_t callHierarchyKey[] = u"callHierarchy"; +constexpr char16_t callHierarchyProviderKey[] = u"callHierarchyProvider"; constexpr char16_t cancellableKey[] = u"cancellable"; constexpr char16_t capabilitiesKey[] = u"capabilities"; constexpr char16_t chKey[] = u"ch"; @@ -88,6 +90,8 @@ constexpr char16_t filterTextKey[] = u"filterText"; constexpr char16_t firstTriggerCharacterKey[] = u"firstTriggerCharacter"; constexpr char16_t formatsKey[] = u"formats"; constexpr char16_t formattingKey[] = u"formatting"; +constexpr char16_t fromKey[] = u"from"; +constexpr char16_t fromRangesKey[] = u"fromRanges"; constexpr char16_t fullKey[] = u"full"; constexpr char16_t greenKey[] = u"green"; constexpr char16_t hierarchicalDocumentSymbolSupportKey[] = u"hierarchicalDocumentSymbolSupport"; @@ -104,6 +108,7 @@ constexpr char16_t insertSpaceKey[] = u"insertSpace"; constexpr char16_t insertTextFormatKey[] = u"insertTextFormat"; constexpr char16_t insertTextKey[] = u"insertText"; constexpr char16_t isIncompleteKey[] = u"isIncomplete"; +constexpr char16_t itemKey[] = u"item"; constexpr char16_t itemsKey[] = u"items"; constexpr char16_t jsonRpcVersionKey[] = u"jsonrpc"; constexpr char16_t kindKey[] = u"kind"; @@ -190,6 +195,7 @@ constexpr char16_t textEditKey[] = u"textEdit"; constexpr char16_t textKey[] = u"text"; constexpr char16_t titleKey[] = u"title"; constexpr char16_t tokenKey[] = u"token"; +constexpr char16_t toKey[] = u"to"; constexpr char16_t tokenModifiersKey[] = u"tokenModifiers"; constexpr char16_t tokenTypesKey[] = u"tokenTypes"; constexpr char16_t traceKey[] = u"trace"; diff --git a/src/libs/languageserverprotocol/languageserverprotocol.qbs b/src/libs/languageserverprotocol/languageserverprotocol.qbs index cf243929cea..163b2d6d4ea 100644 --- a/src/libs/languageserverprotocol/languageserverprotocol.qbs +++ b/src/libs/languageserverprotocol/languageserverprotocol.qbs @@ -10,6 +10,8 @@ Project { files: [ "basemessage.cpp", "basemessage.h", + "callhierarchy.cpp", + "callhierarchy.h", "client.cpp", "client.h", "clientcapabilities.cpp", diff --git a/src/libs/languageserverprotocol/servercapabilities.cpp b/src/libs/languageserverprotocol/servercapabilities.cpp index d87403781d4..1c0d322e6e7 100644 --- a/src/libs/languageserverprotocol/servercapabilities.cpp +++ b/src/libs/languageserverprotocol/servercapabilities.cpp @@ -156,6 +156,28 @@ void ServerCapabilities::setSemanticTokensProvider( insert(semanticTokensProviderKey, semanticTokensProvider); } +std::optional > +ServerCapabilities::callHierarchyProvider() const +{ + const QJsonValue &provider = value(callHierarchyProviderKey); + if (provider.isBool()) + return provider.toBool(); + else if (provider.isObject()) + return WorkDoneProgressOptions(provider.toObject()); + return std::nullopt; +} + +void ServerCapabilities::setCallHierarchyProvider( + const std::variant &callHierarchyProvider) +{ + QJsonValue val; + if (std::holds_alternative(callHierarchyProvider)) + val = std::get(callHierarchyProvider); + else if (std::holds_alternative(callHierarchyProvider)) + val = QJsonObject(std::get(callHierarchyProvider)); + insert(callHierarchyProviderKey, val); +} + std::optional> ServerCapabilities::workspaceSymbolProvider() const { diff --git a/src/libs/languageserverprotocol/servercapabilities.h b/src/libs/languageserverprotocol/servercapabilities.h index a25c5425789..bacddda19e6 100644 --- a/src/libs/languageserverprotocol/servercapabilities.h +++ b/src/libs/languageserverprotocol/servercapabilities.h @@ -328,6 +328,10 @@ public: void setSemanticTokensProvider(const SemanticTokensOptions &semanticTokensProvider); void clearSemanticTokensProvider() { remove(semanticTokensProviderKey); } + std::optional> callHierarchyProvider() const; + void setCallHierarchyProvider(const std::variant &callHierarchyProvider); + void clearCallHierarchyProvider() { remove(callHierarchyProviderKey); } + // The server provides workspace symbol support. std::optional> workspaceSymbolProvider() const; void setWorkspaceSymbolProvider(std::variant workspaceSymbolProvider); diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index 42dde24dba1..8e1748a04a1 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -2,6 +2,7 @@ add_qtc_plugin(LanguageClient PUBLIC_DEPENDS LanguageServerProtocol Qt::Core app_version PLUGIN_DEPENDS ProjectExplorer Core TextEditor SOURCES + callhierarchy.cpp callhierarchy.h client.cpp client.h diagnosticmanager.cpp diagnosticmanager.h documentsymbolcache.cpp documentsymbolcache.h diff --git a/src/plugins/languageclient/callhierarchy.cpp b/src/plugins/languageclient/callhierarchy.cpp new file mode 100644 index 00000000000..098a1a4b641 --- /dev/null +++ b/src/plugins/languageclient/callhierarchy.cpp @@ -0,0 +1,291 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "callhierarchy.h" + +#include "languageclientmanager.h" +#include "languageclienttr.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Utils; +using namespace TextEditor; +using namespace LanguageServerProtocol; + +namespace LanguageClient { + +const char CALL_HIERARCHY_FACTORY_ID[] = "LanguageClient.CallHierarchy"; + +namespace { +enum Direction { Incoming, Outgoing }; + +enum { + AnnotationRole = Qt::UserRole + 1, + LinkRole +}; +} + +class CallHierarchyItem : public TreeItem +{ +public: + CallHierarchyItem(const LanguageServerProtocol::CallHierarchyItem &item, + const Direction direction, + Client *client) + : m_item(item) + , m_direction(direction) + , m_client(client) + { + } + + QVariant data(int column, int role) const override + { + switch (role) { + case Qt::DecorationRole: + return symbolIcon(int(m_item.symbolKind())); + case Qt::DisplayRole: + return m_item.name(); + case LinkRole: { + if (!m_client) + return QVariant(); + const Position start = m_item.selectionRange().start(); + return QVariant::fromValue( + Link(m_client->serverUriToHostPath(m_item.uri()), start.line(), start.character())); + } + case AnnotationRole: + if (const std::optional detail = m_item.detail()) + return *detail; + return {}; + default: + return TreeItem::data(column, role); + } + } + bool canFetchMore() const override + { + return m_client && !m_fetchedChildren; + } + + void fetchMore() override + { + m_fetchedChildren = true; + if (!m_client) + return; + + CallHierarchyCallsParams params; + params.setItem(m_item); + + if (m_direction == Incoming) { + CallHierarchyIncomingCallsRequest request(params); + request.setResponseCallback( + [this](const CallHierarchyIncomingCallsRequest::Response &response) { + const std::optional> result + = response.result(); + if (result && !result->isNull()) { + for (const CallHierarchyIncomingCall &item : result->toList()) { + if (item.isValid()) + appendChild(new CallHierarchyItem(item.from(), m_direction, m_client)); + } + } + if (!hasChildren()) + update(); + }); + m_client->sendMessage(request); + } else { + CallHierarchyOutgoingCallsRequest request(params); + request.setResponseCallback( + [this](const CallHierarchyOutgoingCallsRequest::Response &response) { + const std::optional> result + = response.result(); + if (result && !result->isNull()) { + for (const CallHierarchyOutgoingCall &item : result->toList()) { + if (item.isValid()) + appendChild(new CallHierarchyItem(item.to(), m_direction, m_client)); + } + } + if (!hasChildren()) + update(); + }); + m_client->sendMessage(request); + } + } + +protected: + const LanguageServerProtocol::CallHierarchyItem m_item; + const Direction m_direction; + bool m_fetchedChildren = false; + QPointer m_client; +}; + +class CallHierarchyDirectionItem : public CallHierarchyItem +{ +public: + CallHierarchyDirectionItem(const LanguageServerProtocol::CallHierarchyItem &item, + const Direction direction, + Client *client) + : CallHierarchyItem(item, direction, client) + {} + + QVariant data(int column, int role) const override + { + if (role == Qt::DisplayRole) + return m_direction == Incoming ? Tr::tr("Incoming") : Tr::tr("Outgoing"); + return CallHierarchyItem::data(column, role); + } +}; + + +class CallHierarchyRootItem : public TreeItem +{ +public: + CallHierarchyRootItem(const LanguageServerProtocol::CallHierarchyItem &item, Client *client) + : m_item(item) + { + appendChild(new CallHierarchyDirectionItem(m_item, Incoming, client)); + appendChild(new CallHierarchyDirectionItem(m_item, Outgoing, client)); + } + + QVariant data(int column, int role) const override + { + switch (role) { + case Qt::DecorationRole: + return symbolIcon(int(m_item.symbolKind())); + case Qt::DisplayRole: + return m_item.name(); + default: + return TreeItem::data(column, role); + } + } + +private: + const LanguageServerProtocol::CallHierarchyItem m_item; +}; + +class CallHierarchy : public QWidget +{ +public: + CallHierarchy() : m_view(new NavigationTreeView(this)) + { + m_delegate.setDelimiter(" "); + m_delegate.setAnnotationRole(AnnotationRole); + + m_view->setModel(&m_model); + m_view->setActivationMode(SingleClickActivation); + m_view->setItemDelegate(&m_delegate); + + setLayout(new QVBoxLayout); + layout()->addWidget(m_view); + layout()->setContentsMargins(0, 0, 0, 0); + layout()->setSpacing(0); + + connect(m_view, &NavigationTreeView::activated, this, &CallHierarchy::onItemActivated); + } + + void onItemActivated(const QModelIndex &index) + { + const auto link = index.data(LinkRole).value(); + if (link.hasValidTarget()) + Core::EditorManager::openEditorAt(link); + } + + void updateHierarchyAtCursorPosition(); + void handlePrepareResponse(Client *client, + const PrepareCallHierarchyRequest::Response &response); + + AnnotatedItemDelegate m_delegate; + NavigationTreeView *m_view; + TreeModel m_model; +}; + +void CallHierarchy::updateHierarchyAtCursorPosition() +{ + m_model.clear(); + + BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); + if (!editor) + return; + Client *client = LanguageClientManager::clientForFilePath(editor->document()->filePath()); + if (!client) + return; + + const QString methodName = PrepareCallHierarchyRequest::methodName; + std::optional registered = client->dynamicCapabilities().isRegistered(methodName); + bool supported = registered.value_or(false); + const Core::IDocument *document = editor->document(); + if (registered) { + if (supported) { + const QJsonValue &options = client->dynamicCapabilities().option(methodName); + const TextDocumentRegistrationOptions docOptions(options); + supported = docOptions.filterApplies(document->filePath(), + Utils::mimeTypeForName(document->mimeType())); + } + } else { + supported = client->capabilities().callHierarchyProvider().has_value(); + } + + if (!supported) + return; + + TextDocumentPositionParams params; + params.setTextDocument(TextDocumentIdentifier(client->hostPathToServerUri(document->filePath()))); + params.setPosition(Position(editor->editorWidget()->textCursor())); + + PrepareCallHierarchyRequest request(params); + request.setResponseCallback([this, client = QPointer(client)]( + const PrepareCallHierarchyRequest::Response &response) { + handlePrepareResponse(client, response); + }); + + client->sendMessage(request); +} + +void CallHierarchy::handlePrepareResponse(Client *client, + const PrepareCallHierarchyRequest::Response &response) +{ + if (!client) + return; + const std::optional error = response.error(); + if (error) + client->log(*error); + + const std::optional> + result = response.result(); + if (result && !result->isNull()) { + for (const LanguageServerProtocol::CallHierarchyItem &item : result->toList()) { + auto newItem = new CallHierarchyRootItem(item, client); + m_model.rootItem()->appendChild(newItem); + m_view->expand(newItem->index()); + newItem->forChildrenAtLevel(1, [&](const TreeItem *child) { + m_view->expand(child->index()); + }); + } + } +} + +CallHierarchyFactory::CallHierarchyFactory() +{ + setDisplayName(tr("Call Hierarchy")); + setPriority(650); + setId(CALL_HIERARCHY_FACTORY_ID); +} + +Core::NavigationView CallHierarchyFactory::createWidget() +{ + auto h = new CallHierarchy; + h->updateHierarchyAtCursorPosition(); + + Icons::RELOAD_TOOLBAR.icon(); + auto button = new QToolButton; + button->setIcon(Icons::RELOAD_TOOLBAR.icon()); + connect(button, &QToolButton::clicked, [h](){ + h->updateHierarchyAtCursorPosition(); + }); + return {h,{button}}; +} + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/callhierarchy.h b/src/plugins/languageclient/callhierarchy.h new file mode 100644 index 00000000000..f707c4fbcbb --- /dev/null +++ b/src/plugins/languageclient/callhierarchy.h @@ -0,0 +1,20 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include + +#pragma once + +namespace LanguageClient { + +class CallHierarchyFactory : public Core::INavigationWidgetFactory +{ + Q_OBJECT + +public: + CallHierarchyFactory(); + + Core::NavigationView createWidget() override; +}; + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 466fbd1d43b..dc391575e8a 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -482,6 +482,7 @@ static ClientCapabilities generateClientCapabilities() tokens.setTokenModifiers({"declaration", "definition"}); tokens.setFormats({"relative"}); documentCapabilities.setSemanticTokens(tokens); + documentCapabilities.setCallHierarchy(allowDynamicRegistration); capabilities.setTextDocument(documentCapabilities); WindowClientClientCapabilities window; diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index 3e28480e6de..9a48caf9e3c 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -20,6 +20,8 @@ QtcPlugin { Depends { name: "app_version_header" } files: [ + "callhierarchy.cpp", + "callhierarchy.h", "client.cpp", "client.h", "diagnosticmanager.cpp", diff --git a/src/plugins/languageclient/languageclientplugin.h b/src/plugins/languageclient/languageclientplugin.h index 59179e88ee6..5bdbfc0a0a2 100644 --- a/src/plugins/languageclient/languageclientplugin.h +++ b/src/plugins/languageclient/languageclientplugin.h @@ -3,9 +3,8 @@ #pragma once -#include "languageclientmanager.h" #include "languageclientoutline.h" -#include "languageclientsettings.h" +#include "callhierarchy.h" #include @@ -29,6 +28,7 @@ private: private: LanguageClientOutlineWidgetFactory m_outlineFactory; + CallHierarchyFactory m_callHierarchyFactory; #ifdef WITH_TESTS private slots: