nridge created this revision.
nridge added a reviewer: sammccall.
Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman, jkorous, 
MaskRay, ilya-biryukov.
Herald added a project: clang.
nridge updated this revision to Diff 232996.
nridge added a comment.
nridge edited the summary of this revision.

Add github issue number


The heuristic is to look in the definition of the primary template,
which is what you want in the vast majority of cases.

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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D71240

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

Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -465,6 +465,39 @@
 
         template <typename T>
         struct Fo^o<T*> {};
+      )cpp",
+
+      R"cpp(// Heuristic resolution of method
+        template <typename T>
+        struct S {
+          void [[bar]]() {}
+        };
+
+        template <typename T>
+        void foo(S<T> arg) {
+          arg.ba^r();
+        }
+      )cpp",
+
+      R"cpp(// Heuristic resolution of method via this->
+        template <typename T>
+        struct S {
+          void [[foo]]() {
+            this->fo^o();
+          }
+        };
+      )cpp",
+
+      R"cpp(// Heuristic resolution of static method
+        template <typename T>
+        struct S {
+          static void [[bar]]() {}
+        };
+
+        template <typename T>
+        void foo() {
+          S<T>::ba^r();
+        }
       )cpp"};
   for (const char *Test : Tests) {
     Annotations T(Test);
@@ -525,6 +558,21 @@
       Foo abcde$10^("asdf");
       Foo foox2 = Foo$11^("asdf");
     }
+
+    template <typename T>
+    struct S {
+      void $NonstaticOverload1[[bar]](int);
+      void $NonstaticOverload2[[bar]](float);
+
+      static void $StaticOverload1[[baz]](int);
+      static void $StaticOverload2[[baz]](int);
+    };
+
+    template <typename T, typename U>
+    void dependent_call(S<T> s, U u) {
+      s.ba$12^r(u);
+      S<T>::ba$13^z(u);
+    }
   )cpp");
   auto AST = TestTU::withCode(T.code()).build();
   // Ordered assertions are deliberate: we expect a predictable order.
@@ -544,6 +592,15 @@
               ElementsAre(Sym("Foo", T.range("ConstructorLoc"))));
   EXPECT_THAT(locateSymbolAt(AST, T.point("11")),
               ElementsAre(Sym("Foo", T.range("ConstructorLoc"))));
+  // These assertions are unordered because the order comes from
+  // CXXRecordDecl::lookupDependentName() which doesn't appear to provide
+  // an order guarantee.
+  EXPECT_THAT(locateSymbolAt(AST, T.point("12")),
+              UnorderedElementsAre(Sym("bar", T.range("NonstaticOverload1")),
+                                   Sym("bar", T.range("NonstaticOverload2"))));
+  EXPECT_THAT(locateSymbolAt(AST, T.point("13")),
+              UnorderedElementsAre(Sym("baz", T.range("StaticOverload1")),
+                                   Sym("baz", T.range("StaticOverload2"))));
 }
 
 TEST(LocateSymbol, TemplateTypedefs) {
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -384,8 +384,8 @@
   // different kinds, deduplicate them.
   std::vector<DocumentHighlight> Result;
   for (const auto &Ref : References) {
-    if (auto Range = getTokenRange(AST.getSourceManager(),
-                                   AST.getLangOpts(), Ref.Loc)) {
+    if (auto Range =
+            getTokenRange(AST.getSourceManager(), AST.getLangOpts(), Ref.Loc)) {
       DocumentHighlight DH;
       DH.range = *Range;
       if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -79,8 +79,6 @@
 // formally size() is unresolved, but the primary template is a good guess.
 // This affects:
 //  - DependentTemplateSpecializationType,
-//  - DependentScopeMemberExpr
-//  - DependentScopeDeclRefExpr
 //  - DependentNameType
 struct TargetFinder {
   using RelSet = DeclRelationSet;
@@ -212,6 +210,25 @@
             break;
           }
       }
+      void
+      VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) {
+        const Type *BaseType = E->getBaseType().getTypePtrOrNull();
+        if (E->isArrow()) {
+          if (!BaseType || !BaseType->isPointerType()) {
+            return;
+          }
+          BaseType = BaseType->getAs<PointerType>()
+                         ->getPointeeType()
+                         .getTypePtrOrNull();
+        }
+        addMembersReferencedViaDependentName(BaseType, E->getMember(),
+                                             /*IsNonstaticMember=*/true);
+      }
+      void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *E) {
+        addMembersReferencedViaDependentName(E->getQualifier()->getAsType(),
+                                             E->getDeclName(),
+                                             /*IsNonstaticMember=*/false);
+      }
       void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE) {
         Outer.add(OIRE->getDecl(), Flags);
       }
@@ -231,6 +248,37 @@
       void VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE) {
         Outer.add(OPE->getProtocol(), Flags);
       }
+
+      void addMembersReferencedViaDependentName(const Type *T,
+                                                const DeclarationName &Name,
+                                                bool IsNonstaticMember) {
+        // This code was adapted in part from indexDependentReference() in
+        // IndexBody.cpp.
+        if (!T)
+          return;
+        if (auto *ICNT = T->getAs<InjectedClassNameType>()) {
+          T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
+        }
+        auto *TST = T->getAs<TemplateSpecializationType>();
+        if (!TST)
+          return;
+        const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
+            TST->getTemplateName().getAsTemplateDecl());
+        if (!TD)
+          return;
+        CXXRecordDecl *RD = TD->getTemplatedDecl();
+        if (!RD->hasDefinition())
+          return;
+        RD = RD->getDefinition();
+        std::vector<const NamedDecl *> Decls =
+            RD->lookupDependentName(Name, [=](const NamedDecl *D) {
+              return IsNonstaticMember ? D->isCXXInstanceMember()
+                                       : !D->isCXXInstanceMember();
+            });
+        for (const NamedDecl *D : Decls) {
+          Outer.add(D, Flags);
+        }
+      }
     };
     Visitor(*this, Flags).Visit(S);
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to