diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -1006,6 +1006,38 @@ HI.CallPassType.emplace(PassType); } +const NamedDecl *pickDeclToUse(llvm::ArrayRef Candidates) { + if (Candidates.empty()) + return nullptr; + + // This is e.g the case for + // namespace ns { void foo(); } + // void bar() { using ns::foo; f^oo(); } + // One declaration in Candidates will refer to the using declaration, + // which isn't really useful for Hover. So use the other one, + // which in this example would be the actual declaration of foo. + if (Candidates.size() <= 2) { + if (llvm::isa(Candidates.front())) + return Candidates.back(); + + return Candidates.front(); + } + + // For something like + // namespace ns { void foo(int); void foo(char); } + // using ns::foo; + // template void bar() { fo^o(T{}); } + // we actually want to show the using declaration, + // it's not clear which declaration to pick otherwise. + auto BaseDecls = llvm::make_filter_range(Candidates, [](const NamedDecl *D) { + return llvm::isa(D); + }); + if (std::distance(BaseDecls.begin(), BaseDecls.end()) == 1) + return *BaseDecls.begin(); + + return Candidates.front(); +} + } // namespace llvm::Optional getHover(ParsedAST &AST, Position Pos, @@ -1081,11 +1113,11 @@ // FIXME: Fill in HighlightRange with range coming from N->ASTNode. auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Alias, AST.getHeuristicResolver()); - if (!Decls.empty()) { - HI = getHoverContents(Decls.front(), PP, Index, TB); + if (const auto *DeclToUse = pickDeclToUse(Decls)) { + HI = getHoverContents(DeclToUse, PP, Index, TB); // Layout info only shown when hovering on the field/class itself. - if (Decls.front() == N->ASTNode.get()) - addLayoutInfo(*Decls.front(), *HI); + if (DeclToUse == N->ASTNode.get()) + addLayoutInfo(*DeclToUse, *HI); // Look for a close enclosing expression to show the value of. if (!HI->Value) HI->Value = printExprValue(N, AST.getASTContext()); diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1630,6 +1630,38 @@ HI.Type = "int"; HI.Definition = "int foo"; }}, + { + R"cpp(// Function definition via using declaration + namespace ns { + void foo(); + } + int main() { + using ns::foo; + ^[[foo]](); + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "foo"; + HI.Kind = index::SymbolKind::Function; + HI.NamespaceScope = "ns::"; + HI.Type = "void ()"; + HI.Definition = "void foo()"; + HI.Documentation = ""; + HI.ReturnType = "void"; + HI.Parameters = std::vector{}; + }}, + { + R"cpp( // using declaration and two possible function declarations + namespace ns { void foo(int); void foo(char); } + using ns::foo; + template void bar() { [[f^oo]](T{}); } + )cpp", + [](HoverInfo &HI) { + HI.Name = "foo"; + HI.Kind = index::SymbolKind::Using; + HI.NamespaceScope = ""; + HI.Definition = "using ns::foo"; + }}, { R"cpp(// Macro #define MACRO 0 @@ -1734,6 +1766,25 @@ HI.Definition = "ONE"; HI.Value = "0"; }}, + { + R"cpp(// C++20's using enum + enum class Hello { + ONE, TWO, THREE, + }; + void foo() { + using enum Hello; + Hello hello = [[O^NE]]; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "ONE"; + HI.Kind = index::SymbolKind::EnumConstant; + HI.NamespaceScope = ""; + HI.LocalScope = "Hello::"; + HI.Type = "enum Hello"; + HI.Definition = "ONE"; + HI.Value = "0"; + }}, { R"cpp(// Enumerator in anonymous enum enum {