[clang-tools-extra] e33ec9d - [clangd] Target member of dependent base made visible via a using-decl

Nathan Ridge via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 18 00:04:01 PDT 2020


Author: Nathan Ridge
Date: 2020-08-18T03:03:49-04:00
New Revision: e33ec9d90400a906314ccbd5821dbe05d070108a

URL: https://github.com/llvm/llvm-project/commit/e33ec9d90400a906314ccbd5821dbe05d070108a
DIFF: https://github.com/llvm/llvm-project/commit/e33ec9d90400a906314ccbd5821dbe05d070108a.diff

LOG: [clangd] Target member of dependent base made visible via a using-decl

Fixes https://github.com/clangd/clangd/issues/307

Differential Revision: https://reviews.llvm.org/D86047

Added: 
    

Modified: 
    clang-tools-extra/clangd/FindTarget.cpp
    clang-tools-extra/clangd/XRefs.cpp
    clang-tools-extra/clangd/unittests/FindTargetTests.cpp
    clang-tools-extra/clangd/unittests/XRefsTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index f73a6e584972..9db814368a02 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -100,7 +100,7 @@ CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) {
 std::vector<const NamedDecl *> getMembersReferencedViaDependentName(
     const Type *T,
     llvm::function_ref<DeclarationName(ASTContext &)> NameFactory,
-    bool IsNonstaticMember) {
+    llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
   if (!T)
     return {};
   if (auto *ET = T->getAs<EnumType>()) {
@@ -113,17 +113,22 @@ std::vector<const NamedDecl *> getMembersReferencedViaDependentName(
       return {};
     RD = RD->getDefinition();
     DeclarationName Name = NameFactory(RD->getASTContext());
-    return RD->lookupDependentName(Name, [=](const NamedDecl *D) {
-      return IsNonstaticMember ? D->isCXXInstanceMember()
-                               : !D->isCXXInstanceMember();
-    });
+    return RD->lookupDependentName(Name, Filter);
   }
   return {};
 }
 
-// Given the type T of a dependent expression that appears of the LHS of a "->",
-// heuristically find a corresponding pointee type in whose scope we could look
-// up the name appearing on the RHS.
+const auto NonStaticFilter = [](const NamedDecl *D) {
+  return D->isCXXInstanceMember();
+};
+const auto StaticFilter = [](const NamedDecl *D) {
+  return !D->isCXXInstanceMember();
+};
+const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
+
+// Given the type T of a dependent expression that appears of the LHS of a
+// "->", heuristically find a corresponding pointee type in whose scope we
+// could look up the name appearing on the RHS.
 const Type *getPointeeType(const Type *T) {
   if (!T)
     return nullptr;
@@ -141,7 +146,7 @@ const Type *getPointeeType(const Type *T) {
       [](ASTContext &Ctx) {
         return Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow);
       },
-      /*IsNonStaticMember=*/true);
+      NonStaticFilter);
   if (ArrowOps.empty())
     return nullptr;
 
@@ -187,13 +192,12 @@ std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) {
     }
     return getMembersReferencedViaDependentName(
         BaseType, [ME](ASTContext &) { return ME->getMember(); },
-        /*IsNonstaticMember=*/true);
+        NonStaticFilter);
   }
   if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
     return getMembersReferencedViaDependentName(
         RE->getQualifier()->getAsType(),
-        [RE](ASTContext &) { return RE->getDeclName(); },
-        /*IsNonstaticMember=*/false);
+        [RE](ASTContext &) { return RE->getDeclName(); }, StaticFilter);
   }
   if (const auto *CE = dyn_cast<CallExpr>(E)) {
     const auto *CalleeType = resolveExprToType(CE->getCallee());
@@ -291,7 +295,6 @@ const NamedDecl *getTemplatePattern(const NamedDecl *D) {
 // CXXDependentScopeMemberExpr, but some other constructs remain to be handled:
 //  - DependentTemplateSpecializationType,
 //  - DependentNameType
-//  - UnresolvedUsingValueDecl
 //  - UnresolvedUsingTypenameDecl
 struct TargetFinder {
   using RelSet = DeclRelationSet;
@@ -345,6 +348,15 @@ struct TargetFinder {
     } else if (const auto *NAD = dyn_cast<NamespaceAliasDecl>(D)) {
       add(NAD->getUnderlyingDecl(), Flags | Rel::Underlying);
       Flags |= Rel::Alias; // continue with the alias
+    } else if (const UnresolvedUsingValueDecl *UUVD =
+                   dyn_cast<UnresolvedUsingValueDecl>(D)) {
+      for (const NamedDecl *Target : getMembersReferencedViaDependentName(
+               UUVD->getQualifier()->getAsType(),
+               [UUVD](ASTContext &) { return UUVD->getNameInfo().getName(); },
+               ValueFilter)) {
+        add(Target, Flags | Rel::Underlying);
+      }
+      Flags |= Rel::Alias; // continue with the alias
     } else if (const UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) {
       // Include the using decl, but don't traverse it. This may end up
       // including *all* shadows, which we don't want.

diff  --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 9936c67cb6e5..031a9c7bf5da 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -345,7 +345,7 @@ locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
 
     // Give the underlying decl if navigation is triggered on a non-renaming
     // alias.
-    if (llvm::isa<UsingDecl>(D)) {
+    if (llvm::isa<UsingDecl>(D) || llvm::isa<UnresolvedUsingValueDecl>(D)) {
       // FIXME: address more complicated cases. TargetDecl(... Underlying) gives
       // all overload candidates, we only want the targeted one if the cursor is
       // on an using-alias usage, workround it with getDeclAtPosition.

diff  --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 2507932c5cda..5bfdaaf6c343 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -207,6 +207,19 @@ TEST_F(TargetDeclTest, UsingDecl) {
   )cpp";
   EXPECT_DECLS("MemberExpr", {"using X::foo", Rel::Alias},
                {"int foo()", Rel::Underlying});
+
+  Code = R"cpp(
+      template <typename T>
+      struct Base {
+        void waldo() {}
+      };
+      template <typename T>
+      struct Derived : Base<T> {
+        using Base<T>::[[waldo]];
+      };
+    )cpp";
+  EXPECT_DECLS("UnresolvedUsingValueDecl", {"using Base<T>::waldo", Rel::Alias},
+               {"void waldo()", Rel::Underlying});
 }
 
 TEST_F(TargetDeclTest, ConstructorInitList) {

diff  --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index 63e8c96daab8..d2337dcbd7b3 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -1087,66 +1087,78 @@ TEST(LocateSymbol, TextualDependent) {
 
 TEST(LocateSymbol, Alias) {
   const char *Tests[] = {
-    R"cpp(
+      R"cpp(
       template <class T> struct function {};
       template <class T> using [[callback]] = function<T()>;
 
       c^allback<int> foo;
     )cpp",
 
-    // triggered on non-definition of a renaming alias: should not give any
-    // underlying decls.
-    R"cpp(
+      // triggered on non-definition of a renaming alias: should not give any
+      // underlying decls.
+      R"cpp(
       class Foo {};
       typedef Foo [[Bar]];
 
       B^ar b;
     )cpp",
-    R"cpp(
+      R"cpp(
       class Foo {};
       using [[Bar]] = Foo; // definition
       Ba^r b;
     )cpp",
 
-    // triggered on the underlying decl of a renaming alias.
-    R"cpp(
+      // triggered on the underlying decl of a renaming alias.
+      R"cpp(
       class [[Foo]];
       using Bar = Fo^o;
     )cpp",
 
-    // triggered on definition of a non-renaming alias: should give underlying
-    // decls.
-    R"cpp(
+      // triggered on definition of a non-renaming alias: should give underlying
+      // decls.
+      R"cpp(
       namespace ns { class [[Foo]] {}; }
       using ns::F^oo;
     )cpp",
 
-    R"cpp(
+      R"cpp(
       namespace ns { int [[x]](char); int [[x]](double); }
       using ns::^x;
     )cpp",
 
-    R"cpp(
+      R"cpp(
       namespace ns { int [[x]](char); int x(double); }
       using ns::x;
       int y = ^x('a');
     )cpp",
 
-    R"cpp(
+      R"cpp(
       namespace ns { class [[Foo]] {}; }
       using ns::Foo;
       F^oo f;
     )cpp",
 
-    // other cases that don't matter much.
-    R"cpp(
+      // other cases that don't matter much.
+      R"cpp(
       class Foo {};
       typedef Foo [[Ba^r]];
     )cpp",
-    R"cpp(
+      R"cpp(
       class Foo {};
       using [[B^ar]] = Foo;
     )cpp",
+
+      // Member of dependent base
+      R"cpp(
+      template <typename T>
+      struct Base {
+        void [[waldo]]() {}
+      };
+      template <typename T>
+      struct Derived : Base<T> {
+        using Base<T>::w^aldo;
+      };
+    )cpp",
   };
 
   for (const auto* Case : Tests) {


        


More information about the cfe-commits mailing list