nridge updated this revision to Diff 259160. nridge added a comment. Rebase on top of D75479 <https://reviews.llvm.org/D75479>
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D76451/new/ https://reviews.llvm.org/D76451 Files: clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/XRefs.h 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 @@ -663,14 +663,42 @@ int myFunction(int); // Not triggered for token which survived preprocessing. int var = m^yFunction(); - )cpp", + )cpp"}; + + for (const char *Test : Tests) { + Annotations T(Test); + llvm::Optional<Range> WantDecl; + if (!T.ranges().empty()) + WantDecl = T.range(); + + auto TU = TestTU::withCode(T.code()); + + auto AST = TU.build(); + auto Index = TU.index(); + auto Word = SpelledWord::touching( + cantFail(sourceLocationInMainFile(AST.getSourceManager(), T.point())), + AST.getTokens(), AST.getLangOpts()); + ASSERT_TRUE(Word); + auto Results = locateSymbolTextually( + *Word, AST, Index.get(), testPath(TU.Filename), /*IsDependent=*/false); + + if (!WantDecl) { + EXPECT_THAT(Results, IsEmpty()) << Test; + } else { + ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test; + EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test; + } + } +} // namespace + +TEST(LocateSymbol, TextualDependent) { + const char *Tests[] = { R"cpp(// Dependent type struct Foo { - void uniqueMethodName(); + void [[uniqueMethodName]](); }; template <typename T> void f(T t) { - // Not triggered for token which survived preprocessing. t->u^niqueMethodName(); } )cpp"}; @@ -685,15 +713,10 @@ auto AST = TU.build(); auto Index = TU.index(); - auto Word = SpelledWord::touching( - cantFail(sourceLocationInMainFile(AST.getSourceManager(), T.point())), - AST.getTokens(), AST.getLangOpts()); - if (!Word) { - ADD_FAILURE() << "No word touching point!" << Test; - continue; - } - auto Results = - locateSymbolTextually(*Word, AST, Index.get(), testPath(TU.Filename)); + // Need to use locateSymbolAt() since we are testing an + // interaction between locateASTReferent() and + // locateSymbolNamedTextuallyAt(). + auto Results = locateSymbolAt(AST, T.point(), Index.get()); if (!WantDecl) { EXPECT_THAT(Results, IsEmpty()) << Test; @@ -786,19 +809,18 @@ struct Bar { void $BarLoc[[uniqueMethodName]](); }; - // Will call u^niqueMethodName() on t. template <typename T> - void f(T t); + void f(T t) { + t.u^niqueMethodName(); + } )cpp"); auto TU = TestTU::withCode(T.code()); auto AST = TU.build(); auto Index = TU.index(); - auto Word = SpelledWord::touching( - cantFail(sourceLocationInMainFile(AST.getSourceManager(), T.point())), - AST.getTokens(), AST.getLangOpts()); - ASSERT_TRUE(Word); - auto Results = - locateSymbolTextually(*Word, AST, Index.get(), testPath(TU.Filename)); + // Need to use locateSymbolAt() since we are testing an + // interaction between locateASTReferent() and + // locateSymbolNamedTextuallyAt(). + auto Results = locateSymbolAt(AST, T.point(), Index.get()); EXPECT_THAT(Results, UnorderedElementsAre(Sym("uniqueMethodName", T.range("FooLoc")), Sym("uniqueMethodName", T.range("BarLoc")))); Index: clang-tools-extra/clangd/XRefs.h =================================================================== --- clang-tools-extra/clangd/XRefs.h +++ clang-tools-extra/clangd/XRefs.h @@ -62,8 +62,8 @@ // (This is for internal use by locateSymbolAt, and is exposed for testing). std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, - const SymbolIndex *Index, - const std::string &MainFilePath); + const SymbolIndex *Index, const std::string &MainFilePath, + bool IsDependent); // Try to find a proximate occurrence of `Word` as an identifier, which can be // used to resolve it. Index: clang-tools-extra/clangd/XRefs.cpp =================================================================== --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -22,6 +22,7 @@ #include "index/Relation.h" #include "index/SymbolLocation.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Attr.h" #include "clang/AST/Attrs.inc" #include "clang/AST/Decl.h" @@ -139,19 +140,31 @@ return Merged.CanonicalDeclaration; } -std::vector<const NamedDecl *> getDeclAtPosition(ParsedAST &AST, - SourceLocation Pos, - DeclRelationSet Relations) { +bool isDependentName(const DynTypedNode &N) { + if (const Stmt *S = N.get<Stmt>()) { + return llvm::isa<OverloadExpr>(S) || + llvm::isa<CXXDependentScopeMemberExpr>(S) || + llvm::isa<DependentScopeDeclRefExpr>(S); + } + return false; +} + +std::vector<const NamedDecl *> +getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations, + bool *IsDependentName = nullptr) { unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second; std::vector<const NamedDecl *> Result; - SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset, - Offset, [&](SelectionTree ST) { - if (const SelectionTree::Node *N = - ST.commonAncestor()) - llvm::copy(targetDecl(N->ASTNode, Relations), - std::back_inserter(Result)); - return !Result.empty(); - }); + SelectionTree::createEach( + AST.getASTContext(), AST.getTokens(), Offset, Offset, + [&](SelectionTree ST) { + if (const SelectionTree::Node *N = ST.commonAncestor()) { + if (IsDependentName && isDependentName(N->ASTNode)) + *IsDependentName = true; + llvm::copy(targetDecl(N->ASTNode, Relations), + std::back_inserter(Result)); + } + return !Result.empty(); + }); return Result; } @@ -221,7 +234,7 @@ std::vector<LocatedSymbol> locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier, ParsedAST &AST, llvm::StringRef MainFilePath, - const SymbolIndex *Index) { + const SymbolIndex *Index, bool *IsDependentName) { const SourceManager &SM = AST.getSourceManager(); // Results follow the order of Symbols.Decls. std::vector<LocatedSymbol> Result; @@ -250,7 +263,8 @@ // Emit all symbol locations (declaration or definition) from AST. DeclRelationSet Relations = DeclRelation::TemplatePattern | DeclRelation::Alias; - for (const NamedDecl *D : getDeclAtPosition(AST, CurLoc, Relations)) { + for (const NamedDecl *D : + getDeclAtPosition(AST, CurLoc, Relations, IsDependentName)) { // Special case: void foo() ^override: jump to the overridden method. if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) { const InheritableAttr *Attr = D->getAttr<OverrideAttr>(); @@ -336,10 +350,11 @@ std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, - const SymbolIndex *Index, - const std::string &MainFilePath) { - // Don't use heuristics if this is a real identifier, or not an identifier. - if (Word.ExpandedToken || !Word.LikelyIdentifier || !Index) + const SymbolIndex *Index, const std::string &MainFilePath, + bool IsDependent) { + // Don't use heuristics if this is a real non-dependent identifier, or not an + // identifier. + if ((Word.ExpandedToken && !IsDependent) || !Word.LikelyIdentifier || !Index) return {}; // We don't want to handle words in string literals. It'd be nice to whitelist // comments instead, but they're not retained in TokenBuffer. @@ -535,8 +550,9 @@ // expansion.) return {*std::move(Macro)}; - auto ASTResults = - locateASTReferent(*CurLoc, TouchedIdentifier, AST, *MainFilePath, Index); + bool IsDependentName = false; + auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST, + *MainFilePath, Index, &IsDependentName); if (!ASTResults.empty()) return ASTResults; @@ -550,13 +566,13 @@ if (auto Macro = locateMacroReferent(*NearbyIdent, AST, *MainFilePath)) return {*std::move(Macro)}; ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST, - *MainFilePath, Index); + *MainFilePath, Index, &IsDependentName); if (!ASTResults.empty()) return ASTResults; } // No nearby word, or it didn't refer to anything either. Try the index. - auto TextualResults = - locateSymbolTextually(*Word, AST, Index, *MainFilePath); + auto TextualResults = locateSymbolTextually(*Word, AST, Index, + *MainFilePath, IsDependentName); if (!TextualResults.empty()) return TextualResults; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits