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

Reply via email to