[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-15 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added a comment.

In D133664#3791694 , @tom-anders 
wrote:

> Hmm, Github noticed that I referenced the issue with this commit, but didn't 
> close it. 
> According to 
> https://github.blog/2013-03-18-closing-issues-across-repositories/ closing 
> issues across repos should work, but only if you have push permissions in the 
> repo that has the issue

thanks for the heads up, closed it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-15 Thread Tom Praschan via Phabricator via cfe-commits
tom-anders added a comment.

Hmm, Github noticed that I referenced the issue with this commit, but didn't 
close it. 
According to https://github.blog/2013-03-18-closing-issues-across-repositories/ 
closing issues across repos should work, but only if you have push permissions 
in the repo that has the issue


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-15 Thread Tom Praschan via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG220d85082349: [clangd] Fix hover on symbol introduced by 
using declaration (authored by tom-anders).

Changed prior to commit:
  https://reviews.llvm.org/D133664?vs=460058=460328#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp

Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ 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.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.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.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 {
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -1006,6 +1006,37 @@
   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 , Position Pos,
@@ -1081,11 +1112,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 = 

[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

In D133664#3790144 , @tom-anders 
wrote:

> Yeah I do have commit access now, so I'll land this by myself.
>
> I don't think I have the permissions to close the corresponding issue on 
> Github though, so someone else would need to do that.

It happens automatically if the commit message includes "fixes ", which it looks like this one does.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Tom Praschan via Phabricator via cfe-commits
tom-anders added a comment.

Yeah I do have commit access now, so I'll land this by myself.

I don't think I have the permissions to close the corresponding issue on Github 
though, so someone else would need to do that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet accepted this revision.
kadircet added a comment.
This revision is now accepted and ready to land.

thanks, lgtm! i think you have commit access now, but let me know if I should 
land this for you (preferably with an email address for commit attribution)




Comment at: clang-tools-extra/clangd/Hover.cpp:1022
+  return Candidates.back();
+
+return Candidates.front();

nit: drop the empty line


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Tom Praschan via Phabricator via cfe-commits
tom-anders added inline comments.



Comment at: clang-tools-extra/clangd/Hover.cpp:1011
+const NamedDecl *
+pickDeclToUse(const llvm::SmallVector ) {
+  if (Candidates.empty())

kadircet wrote:
> you can just pass in ArrayRef instead.
Ah of course, forgot about that nice class


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Tom Praschan via Phabricator via cfe-commits
tom-anders updated this revision to Diff 460058.
tom-anders marked 5 inline comments as done.
tom-anders added a comment.

Add additional test, tidy up logic in pickDeclToUse()


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp

Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ 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.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.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.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 {
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ 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 , 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());
___
cfe-commits 

[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added inline comments.



Comment at: clang-tools-extra/clangd/Hover.cpp:1011
+const NamedDecl *
+pickDeclToUse(const llvm::SmallVector ) {
+  if (Candidates.empty())

you can just pass in ArrayRef instead.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-14 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added inline comments.



Comment at: clang-tools-extra/clangd/Hover.cpp:1023
+  // which in this example would be the actual declaration of foo.
+  if (Candidates.size() == 2) {
+if (llvm::isa(Candidates.front()))

nit: you can change this to `Candidates.size() <= 2` and get rid of the extra 
single candidate case above (after changing it to always return 
Candidate.front() when Candidate.back() is a using decl.)



Comment at: clang-tools-extra/clangd/Hover.cpp:1026
+  return Candidates.back();
+if (llvm::isa(Candidates.back()))
+  return Candidates.front();

just drop this if check and always return front, when it isn't a using decl.



Comment at: clang-tools-extra/clangd/Hover.cpp:1031
+  // For something like
+  // namespace ns { void foo(int); void foo(char) }
+  // using ns::fo

can we have a test case for this?



Comment at: clang-tools-extra/clangd/Hover.cpp:1032
+  // namespace ns { void foo(int); void foo(char) }
+  // using ns::fo
+  // template  void bar() { fo^o(T{}); }

nit: `ns::foo` not `fo`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-13 Thread Tom Praschan via Phabricator via cfe-commits
tom-anders updated this revision to Diff 459864.
tom-anders added a comment.

Move logic to pickDeclToUse


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp

Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -1630,6 +1630,26 @@
 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.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(// Macro
 #define MACRO 0
@@ -1734,6 +1754,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.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 {
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -1006,6 +1006,42 @@
   HI.CallPassType.emplace(PassType);
 }
 
+template 
+const NamedDecl *
+pickDeclToUse(const llvm::SmallVector ) {
+  if (Candidates.empty())
+return nullptr;
+  if (Candidates.size() == 1)
+return Candidates.front();
+
+  // 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();
+if (llvm::isa(Candidates.back()))
+  return Candidates.front();
+  }
+
+  // For something like
+  // namespace ns { void foo(int); void foo(char) }
+  // using ns::fo
+  // 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 , Position Pos,
@@ -1081,11 +1117,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());
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-13 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added inline comments.



Comment at: clang-tools-extra/clangd/Hover.cpp:1091
+// better, which in this example would be the actual declaration of 
foo.
+auto *DeclToUse = Decls.begin();
+while (llvm::isa(*DeclToUse) &&

we actually want to show the using decl in certain cases, e.g:
```
namespace ns {
void foo(int); void foo(char);
}
using ns::foo;
template  void bar() { fo^o(T{}); }
```

so rather than this, can we have some logic that looks like:
```
- If we have more than two candidates, and there's exactly one `BaseUsingDecl`, 
prefer that.
- If we have two candidates, prefer the non-`BaseUsingDecl` one.
- Prefer the first. (we hit this case when there's a single candidate or there 
are `multiple or no` using decls. i think multiple using decls is not possible, 
but at least we preserve the existing behaviour in such cases).  
```

can you also export this logic to a helper function, probably called 
`pickDeclToUse`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133664/new/

https://reviews.llvm.org/D133664

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133664: [clangd] Fix hover on symbol introduced by using declaration

2022-09-11 Thread Tom Praschan via Phabricator via cfe-commits
tom-anders created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
tom-anders requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

This fixes https://github.com/clangd/clangd/issues/1284. The example
there was C++20's "using enum", but I noticed that we had the same issue
for other using-declarations.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133664

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -1630,6 +1630,26 @@
 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.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(// Macro
 #define MACRO 0
@@ -1734,6 +1754,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.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 {
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -1082,10 +1082,22 @@
   auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Alias,
 AST.getHeuristicResolver());
   if (!Decls.empty()) {
-HI = getHoverContents(Decls.front(), PP, Index, TB);
+// For using-declarations, e.g.
+// namespace ns { void foo(); }
+// void bar() { using ns::foo; f^oo(); }
+// The first declaration in Decls will refer to the using declaration,
+// which isn't really useful for Hover. So check if we have something
+// better, which in this example would be the actual declaration of 
foo.
+auto *DeclToUse = Decls.begin();
+while (llvm::isa(*DeclToUse) &&
+   std::next(DeclToUse) != Decls.end()) {
+  ++DeclToUse;
+}
+
+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());


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -1630,6 +1630,26 @@
 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.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(// Macro
 #define MACRO 0
@@ -1734,6 +1754,25 @@
 HI.Definition = "ONE";
 HI.Value = "0";
   }},