diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index c14f8dd5e29..c9c99c81869 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -985,6 +985,9 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR type = type.left(angleBracketIndex); }; + if (gatherMemberFunctionOverrideHelpItemForTooltip(id, path)) + return; + const bool isMemberFunction = node.role() == "expression" && node.kind() == "Member" && (node.arcanaContains("member function") || type.contains('(')); const bool isFunction = node.role() == "expression" && node.kind() == "DeclRef" @@ -1070,6 +1073,50 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR d->getAndHandleAst(doc, astHandler, AstCallbackMode::SyncIfPossible); } +bool ClangdClient::gatherMemberFunctionOverrideHelpItemForTooltip( + const LanguageServerProtocol::MessageId &token, + const QList &path) +{ + // Heuristic: If we encounter a member function re-declaration, continue under the + // assumption that the base class holds the documentation. + if (path.length() < 3 || path.last().kind() != "FunctionProto") + return false; + const ClangdAstNode &methodNode = path.at(path.length() - 2); + if (methodNode.kind() != "CXXMethod" || !methodNode.detail()) + return false; + bool hasOverride = false; + for (const ClangdAstNode &methodNodeChild + : methodNode.children().value_or(QList())) { + if (methodNodeChild.kind() == "Override") { + hasOverride = true; + break; + } + } + if (!hasOverride) + return false; + const ClangdAstNode &classNode = path.at(path.length() - 3); + if (classNode.kind() != "CXXRecord") + return false; + const ClangdAstNode baseNode = classNode.children()->first(); + if (baseNode.role() != "base") + return false; + const auto baseNodeChildren = baseNode.children(); + if (!baseNodeChildren || baseNodeChildren->isEmpty()) + return false; + const ClangdAstNode baseTypeNode = baseNodeChildren->first(); + if (baseTypeNode.role() != "type") + return false; + const auto baseTypeNodeChildren = baseTypeNode.children(); + if (!baseTypeNodeChildren || baseTypeNodeChildren->isEmpty()) + return false; + const ClangdAstNode baseClassNode = baseTypeNodeChildren->first(); + if (!baseClassNode.detail()) + return false; + d->setHelpItemForTooltip(token, *baseClassNode.detail() + "::" + *methodNode.detail(), + HelpItem::Function, "()"); + return true; +} + void ClangdClient::setVirtualRanges(const Utils::FilePath &filePath, const QList &ranges, int revision) { diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 70eb3e0d989..ff0c5b1b1dc 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -69,6 +69,9 @@ public: void gatherHelpItemForTooltip( const LanguageServerProtocol::HoverRequest::Response &hoverResponse, const LanguageServerProtocol::DocumentUri &uri); + bool gatherMemberFunctionOverrideHelpItemForTooltip( + const LanguageServerProtocol::MessageId &token, + const QList &path); void setVirtualRanges(const Utils::FilePath &filePath, const QList &ranges, int revision);