hokein created this revision.
hokein added a reviewer: ilya-biryukov.
Herald added subscribers: usaxena95, kadircet, arphaman, jkorous, MaskRay.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68977

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/FindTarget.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.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
@@ -2277,7 +2277,8 @@
       if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
         Names.push_back(ND->getQualifiedNameAsString());
     }
-    EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls));
+    EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
+        << File.code();
   }
 }
 
Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -520,8 +520,28 @@
     findExplicitReferences(Func.getBody(), [&Refs](ReferenceLoc R) {
       Refs.push_back(std::move(R));
     });
+    return dumpReferences(std::move(Refs), Code, AST.getSourceManager());
+  }
+
+  /// Similar to annotateReferencesInFoo, but finds all references in the main
+  /// AST.
+  AllRefs annotateReferencesInMainAST(llvm::StringRef Code) {
+    TestTU TU;
+    TU.Code = Code;
 
-    auto &SM = AST.getSourceManager();
+    auto AST = TU.build();
+    std::vector<ReferenceLoc> Refs;
+    for (const auto *ToplLevelDecl : AST.getLocalTopLevelDecls()) {
+      findExplicitReferences(ToplLevelDecl, [&Refs](ReferenceLoc R) {
+        Refs.push_back(std::move(R));
+      });
+    }
+    return dumpReferences(std::move(Refs), Code, AST.getSourceManager());
+  }
+
+private:
+  AllRefs dumpReferences(std::vector<ReferenceLoc> Refs, llvm::StringRef Code,
+                         const SourceManager &SM) {
     llvm::sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
       return SM.isBeforeInTranslationUnit(L.NameLoc, R.NameLoc);
     });
@@ -590,8 +610,8 @@
             using namespace $1^alias;
           }
         )cpp",
-           "0: targets = {ns}\n"
-           "1: targets = {alias}\n"},
+           "0: targets = {ns}, decl ref\n"
+           "1: targets = {alias}, decl ref\n"},
           // Using declarations.
           {R"cpp(
           namespace ns { int global; }
@@ -600,59 +620,67 @@
           }
         )cpp",
            "0: targets = {ns}\n"
-           "1: targets = {ns::global}, qualifier = 'ns::'\n"},
+           "1: targets = {ns::global}, qualifier = 'ns::', decl ref\n"},
           // Simple types.
           {R"cpp(
          struct Struct { int a; };
          using Typedef = int;
          void foo() {
-           $0^Struct x;
-           $1^Typedef y;
-           static_cast<$2^Struct*>(0);
+           $0^Struct $1^x;
+           $2^Typedef $3^y;
+           static_cast<$4^Struct*>(0);
          }
        )cpp",
            "0: targets = {Struct}\n"
-           "1: targets = {Typedef}\n"
-           "2: targets = {Struct}\n"},
+           "1: targets = {x}, decl ref\n"
+           "2: targets = {Typedef}\n"
+           "3: targets = {y}, decl ref\n"
+           "4: targets = {Struct}\n"},
           // Name qualifiers.
           {R"cpp(
          namespace a { namespace b { struct S { typedef int type; }; } }
          void foo() {
-           $0^a::$1^b::$2^S x;
-           using namespace $3^a::$4^b;
-           $5^S::$6^type y;
+           $0^a::$1^b::$2^S $3^x;
+           using namespace $4^a::$5^b;
+           $6^S::$7^type $8^y;
          }
         )cpp",
            "0: targets = {a}\n"
            "1: targets = {a::b}, qualifier = 'a::'\n"
            "2: targets = {a::b::S}, qualifier = 'a::b::'\n"
-           "3: targets = {a}\n"
-           "4: targets = {a::b}, qualifier = 'a::'\n"
-           "5: targets = {a::b::S}\n"
-           "6: targets = {a::b::S::type}, qualifier = 'struct S::'\n"},
+           "3: targets = {x}, decl ref\n"
+           "4: targets = {a}\n"
+           "5: targets = {a::b}, qualifier = 'a::', decl ref\n"
+           "6: targets = {a::b::S}\n"
+           "7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
+           "8: targets = {y}, decl ref\n"},
           // Simple templates.
           {R"cpp(
           template <class T> struct vector { using value_type = T; };
           template <> struct vector<bool> { using value_type = bool; };
           void foo() {
-            $0^vector<int> vi;
-            $1^vector<bool> vb;
+            $0^vector<int> $1^vi;
+            $2^vector<bool> $3^vb;
           }
         )cpp",
            "0: targets = {vector<int>}\n"
-           "1: targets = {vector<bool>}\n"},
+           "1: targets = {vi}, decl ref\n"
+           "2: targets = {vector<bool>}\n"
+           "3: targets = {vb}, decl ref\n"},
           // Template type aliases.
           {R"cpp(
             template <class T> struct vector { using value_type = T; };
             template <> struct vector<bool> { using value_type = bool; };
             template <class T> using valias = vector<T>;
             void foo() {
-              $0^valias<int> vi;
-              $1^valias<bool> vb;
+              $0^valias<int> $1^vi;
+              $2^valias<bool> $3^vb;
             }
           )cpp",
            "0: targets = {valias}\n"
-           "1: targets = {valias}\n"},
+           "1: targets = {vi}, decl ref\n"
+           "2: targets = {valias}\n"
+           "3: targets = {vb}, decl ref\n"},
           // MemberExpr should know their using declaration.
           {R"cpp(
             struct X { void func(int); }
@@ -694,13 +722,14 @@
             };
 
             void foo() {
-              for (int x : $0^vector()) {
-                $1^x = 10;
+              for (int $0^x : $1^vector()) {
+                $2^x = 10;
               }
             }
         )cpp",
-           "0: targets = {vector}\n"
-           "1: targets = {x}\n"},
+           "0: targets = {x}, decl ref\n"
+           "1: targets = {vector}\n"
+           "2: targets = {x}\n"},
           // Handle UnresolvedLookupExpr.
           {R"cpp(
             namespace ns1 { void func(char*); }
@@ -736,39 +765,42 @@
             void foo() {
               static_cast<$0^T>(0);
               $1^T();
-              $2^T t;
+              $2^T $3^t;
             }
         )cpp",
            "0: targets = {T}\n"
            "1: targets = {T}\n"
-           "2: targets = {T}\n"},
+           "2: targets = {T}\n"
+           "3: targets = {t}, decl ref\n"},
           // Non-type template parameters.
           {R"cpp(
             template <int I>
             void foo() {
-              int x = $0^I;
+              int $0^x = $1^I;
             }
         )cpp",
-           "0: targets = {I}\n"},
+           "0: targets = {x}, decl ref\n"
+           "1: targets = {I}\n"},
           // Template template parameters.
           {R"cpp(
             template <class T> struct vector {};
 
             template <template<class> class TT, template<class> class ...TP>
             void foo() {
-              $0^TT<int> x;
-              $1^foo<$2^TT>();
-              $3^foo<$4^vector>()
-              $5^foo<$6^TP...>();
+              $0^TT<int> $1^x;
+              $2^foo<$3^TT>();
+              $4^foo<$5^vector>()
+              $6^foo<$7^TP...>();
             }
         )cpp",
            "0: targets = {TT}\n"
-           "1: targets = {foo}\n"
-           "2: targets = {TT}\n"
-           "3: targets = {foo}\n"
-           "4: targets = {vector}\n"
-           "5: targets = {foo}\n"
-           "6: targets = {TP}\n"},
+           "1: targets = {x}, decl ref\n"
+           "2: targets = {foo}\n"
+           "3: targets = {TT}\n"
+           "4: targets = {foo}\n"
+           "5: targets = {vector}\n"
+           "6: targets = {foo}\n"
+           "7: targets = {TP}\n"},
           // Non-type template parameters with declarations.
           {R"cpp(
             int func();
@@ -776,13 +808,14 @@
 
             template <int(*FuncParam)()>
             void foo() {
-              $0^wrapper<$1^func> w;
-              $2^FuncParam();
+              $0^wrapper<$1^func> $2^w;
+              $3^FuncParam();
             }
         )cpp",
            "0: targets = {wrapper<&func>}\n"
            "1: targets = {func}\n"
-           "2: targets = {FuncParam}\n"},
+           "2: targets = {w}, decl ref\n"
+           "3: targets = {FuncParam}\n"},
       };
 
   for (const auto &C : Cases) {
@@ -796,6 +829,70 @@
   }
 }
 
+TEST_F(FindExplicitReferencesTest, DeclReference) {
+  std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
+      {
+          // simple declarations.
+          {R"cpp(
+             class $0^Foo { $1^Foo(); $2^~$3^Foo(); int $4^field; };
+             int $5^Var;
+             void $6^Fun() {}
+             enum $7^E { $8^ABC };
+             typedef int $9^INT;
+             using $10^INT2 = int;
+             template<typename $11^T>
+             // FIXME: the duplicated locations are from FunctionTemplateDecl and
+             // the underlying FunctionDecl. we should report just one.
+             void $12^$13^F() {}
+           )cpp",
+           "0: targets = {Foo}, decl ref\n"
+           "1: targets = {Foo::Foo}, decl ref\n"
+           "2: targets = {Foo::~Foo}, decl ref\n"
+           "3: targets = {Foo}\n"
+           "4: targets = {Foo::field}, decl ref\n"
+           "5: targets = {Var}, decl ref\n"
+           "6: targets = {Fun}, decl ref\n"
+           "7: targets = {E}, decl ref\n"
+           "8: targets = {ABC}, decl ref\n"
+           "9: targets = {INT}, decl ref\n"
+           "10: targets = {INT2}, decl ref\n"
+           "11: targets = {T}, decl ref\n"
+           "12: targets = {F}, decl ref\n"
+           "13: targets = {F}, decl ref\n"},
+          // declarations with qualifiers.
+          {R"cpp(
+             namespace $0^ns {
+             class $1^Foo {
+               void $2^method();
+             };
+             void $3^func();
+             }
+             void $4^ns::$5^Foo::$6^method() {}
+             void $7^ns::$8^func() {}
+           )cpp",
+           "0: targets = {ns}, decl ref\n"
+           "1: targets = {ns::Foo}, decl ref\n"
+           "2: targets = {ns::Foo::method}, decl ref\n"
+           "3: targets = {ns::func}, decl ref\n"
+           "4: targets = {ns}\n"
+           "5: targets = {ns::Foo}, qualifier = 'ns::'\n"
+           "6: targets = {ns::Foo::method}, qualifier = 'ns::class Foo::', "
+           "decl ref\n"
+           "7: targets = {ns}\n"
+           "8: targets = {ns::func}, qualifier = 'ns::', decl ref\n"},
+      };
+
+  for (const auto &C : Cases) {
+    llvm::StringRef ExpectedCode = C.first;
+    llvm::StringRef ExpectedRefs = C.second;
+
+    auto Actual =
+        annotateReferencesInMainAST(llvm::Annotations(ExpectedCode).code());
+    EXPECT_EQ(ExpectedCode, Actual.AnnotatedCode);
+    EXPECT_EQ(ExpectedRefs, Actual.DumpedReferences) << ExpectedCode;
+  }
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -1307,7 +1307,8 @@
   llvm::DenseSet<const Decl *> DeclRefs;
   findExplicitReferences(FD, [&](ReferenceLoc Ref) {
     for (const Decl *D : Ref.Targets) {
-      if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter())
+      if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
+          !Ref.IsDecl)
         DeclRefs.insert(D);
     }
   });
Index: clang-tools-extra/clangd/FindTarget.h
===================================================================
--- clang-tools-extra/clangd/FindTarget.h
+++ clang-tools-extra/clangd/FindTarget.h
@@ -86,6 +86,8 @@
   NestedNameSpecifierLoc Qualifier;
   /// Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'.
   SourceLocation NameLoc;
+  /// True if the reference is a declaration or definition;
+  bool IsDecl;
   // FIXME: add info about template arguments.
   /// A list of targets referenced by this name. Normally this has a single
   /// element, but multiple is also possible, e.g. in case of using declarations
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -415,15 +415,16 @@
 Optional<ReferenceLoc> refInDecl(const Decl *D) {
   struct Visitor : ConstDeclVisitor<Visitor> {
     llvm::Optional<ReferenceLoc> Ref;
-
+    bool DeclRef = true;
     void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
       Ref = ReferenceLoc{D->getQualifierLoc(),
                          D->getIdentLocation(),
+                         DeclRef,
                          {D->getNominatedNamespaceAsWritten()}};
     }
 
     void VisitUsingDecl(const UsingDecl *D) {
-      Ref = ReferenceLoc{D->getQualifierLoc(), D->getLocation(),
+      Ref = ReferenceLoc{D->getQualifierLoc(), D->getLocation(), DeclRef,
                          explicitReferenceTargets(DynTypedNode::create(*D),
                                                   DeclRelation::Underlying)};
     }
@@ -431,8 +432,24 @@
     void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
       Ref = ReferenceLoc{D->getQualifierLoc(),
                          D->getTargetNameLoc(),
+                         DeclRef,
                          {D->getAliasedNamespace()}};
     }
+
+    void VisitTagDecl(const TagDecl *ND) {
+      Ref =
+          ReferenceLoc{ND->getQualifierLoc(), ND->getLocation(), DeclRef, {ND}};
+    }
+
+    void VisitDeclaratorDecl(const DeclaratorDecl *ND) {
+      Ref =
+          ReferenceLoc{ND->getQualifierLoc(), ND->getLocation(), DeclRef, {ND}};
+    }
+
+    void VisitNamedDecl(const NamedDecl *ND) {
+      Ref = ReferenceLoc{
+          NestedNameSpecifierLoc(), ND->getLocation(), DeclRef, {ND}};
+    }
   };
 
   Visitor V;
@@ -444,20 +461,24 @@
   struct Visitor : ConstStmtVisitor<Visitor> {
     // FIXME: handle more complicated cases, e.g. ObjC, designated initializers.
     llvm::Optional<ReferenceLoc> Ref;
-
+    bool NotDeclRef = false;
     void VisitDeclRefExpr(const DeclRefExpr *E) {
-      Ref = ReferenceLoc{
-          E->getQualifierLoc(), E->getNameInfo().getLoc(), {E->getFoundDecl()}};
+      Ref = ReferenceLoc{E->getQualifierLoc(),
+                         E->getNameInfo().getLoc(),
+                         NotDeclRef,
+                         {E->getFoundDecl()}};
     }
 
     void VisitMemberExpr(const MemberExpr *E) {
       Ref = ReferenceLoc{E->getQualifierLoc(),
                          E->getMemberNameInfo().getLoc(),
+                         NotDeclRef,
                          {E->getFoundDecl()}};
     }
 
     void VisitOverloadExpr(const OverloadExpr *E) {
       Ref = ReferenceLoc{E->getQualifierLoc(), E->getNameInfo().getLoc(),
+                         NotDeclRef,
                          llvm::SmallVector<const NamedDecl *, 1>(
                              E->decls().begin(), E->decls().end())};
     }
@@ -471,7 +492,7 @@
 Optional<ReferenceLoc> refInTypeLoc(TypeLoc L) {
   struct Visitor : TypeLocVisitor<Visitor> {
     llvm::Optional<ReferenceLoc> Ref;
-
+    bool NotDeclRef = false;
     void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
       // We only know about qualifier, rest if filled by inner locations.
       Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
@@ -483,13 +504,13 @@
     }
 
     void VisitTagTypeLoc(TagTypeLoc L) {
-      Ref =
-          ReferenceLoc{NestedNameSpecifierLoc(), L.getNameLoc(), {L.getDecl()}};
+      Ref = ReferenceLoc{
+          NestedNameSpecifierLoc(), L.getNameLoc(), NotDeclRef, {L.getDecl()}};
     }
 
     void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
-      Ref =
-          ReferenceLoc{NestedNameSpecifierLoc(), L.getNameLoc(), {L.getDecl()}};
+      Ref = ReferenceLoc{
+          NestedNameSpecifierLoc(), L.getNameLoc(), NotDeclRef, {L.getDecl()}};
     }
 
     void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
@@ -502,14 +523,14 @@
       //    2. 'vector<int>' with mask 'Underlying'.
       //  we want to return only #1 in this case.
       Ref = ReferenceLoc{
-          NestedNameSpecifierLoc(), L.getTemplateNameLoc(),
+          NestedNameSpecifierLoc(), L.getTemplateNameLoc(), NotDeclRef,
           explicitReferenceTargets(DynTypedNode::create(L.getType()),
                                    DeclRelation::Alias)};
     }
     void VisitDeducedTemplateSpecializationTypeLoc(
         DeducedTemplateSpecializationTypeLoc L) {
       Ref = ReferenceLoc{
-          NestedNameSpecifierLoc(), L.getNameLoc(),
+          NestedNameSpecifierLoc(), L.getNameLoc(), NotDeclRef,
           explicitReferenceTargets(DynTypedNode::create(L.getType()),
                                    DeclRelation::Alias)};
     }
@@ -517,19 +538,21 @@
     void VisitDependentTemplateSpecializationTypeLoc(
         DependentTemplateSpecializationTypeLoc L) {
       Ref = ReferenceLoc{
-          L.getQualifierLoc(), L.getTemplateNameLoc(),
+          L.getQualifierLoc(), L.getTemplateNameLoc(), NotDeclRef,
           explicitReferenceTargets(DynTypedNode::create(L.getType()))};
     }
 
     void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
       Ref = ReferenceLoc{
-          L.getQualifierLoc(), L.getNameLoc(),
+          L.getQualifierLoc(), L.getNameLoc(), NotDeclRef,
           explicitReferenceTargets(DynTypedNode::create(L.getType()))};
     }
 
     void VisitTypedefTypeLoc(TypedefTypeLoc L) {
-      Ref = ReferenceLoc{
-          NestedNameSpecifierLoc(), L.getNameLoc(), {L.getTypedefNameDecl()}};
+      Ref = ReferenceLoc{NestedNameSpecifierLoc(),
+                         L.getNameLoc(),
+                         NotDeclRef,
+                         {L.getTypedefNameDecl()}};
     }
   };
 
@@ -575,6 +598,7 @@
     case TemplateArgument::TemplateExpansion:
       reportReference(ReferenceLoc{A.getTemplateQualifierLoc(),
                                    A.getTemplateNameLoc(),
+                                   false,
                                    {A.getArgument()
                                         .getAsTemplateOrTemplatePattern()
                                         .getAsTemplateDecl()}},
@@ -631,7 +655,7 @@
     if (auto *E = N.get<Expr>())
       return refInExpr(E);
     if (auto *NNSL = N.get<NestedNameSpecifierLoc>())
-      return ReferenceLoc{NNSL->getPrefix(), NNSL->getLocalBeginLoc(),
+      return ReferenceLoc{NNSL->getPrefix(), NNSL->getLocalBeginLoc(), false,
                           explicitReferenceTargets(DynTypedNode::create(
                               *NNSL->getNestedNameSpecifier()))};
     if (const TypeLoc *TL = N.get<TypeLoc>())
@@ -642,6 +666,7 @@
       assert(CCI->isAnyMemberInitializer());
       return ReferenceLoc{NestedNameSpecifierLoc(),
                           CCI->getMemberLocation(),
+                          false,
                           {CCI->getAnyMember()}};
     }
     // We do not have location information for other nodes (QualType, etc)
@@ -727,6 +752,8 @@
                                                 PrintingPolicy(LangOptions()));
     OS << "'";
   }
+  if (R.IsDecl)
+    OS << ", decl ref";
   return OS;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to