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