nridge created this revision.
Herald added subscribers: usaxena95, kadircet, arphaman, javed.absar.
nridge requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang.

https://github.com/clangd/clangd/issues/451


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D93522

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/ParsedAST.h
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.cpp
  clang-tools-extra/clangd/unittests/TestTU.cpp
  clang-tools-extra/clangd/unittests/TestTU.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
@@ -1165,7 +1165,8 @@
   for (const auto *Case : Tests) {
     SCOPED_TRACE(Case);
     auto T = Annotations(Case);
-    auto AST = TestTU::withCode(T.code()).build();
+    TestTU TU = TestTU::withCode(T.code());
+    auto AST = TU.build();
     EXPECT_THAT(locateSymbolAt(AST, T.point()),
                 UnorderedPointwise(DeclRange(), T.ranges()));
   }
Index: clang-tools-extra/clangd/unittests/TestTU.h
===================================================================
--- clang-tools-extra/clangd/unittests/TestTU.h
+++ clang-tools-extra/clangd/unittests/TestTU.h
@@ -76,9 +76,10 @@
   // to eliminate this option some day.
   bool OverlayRealFileSystemForModules = false;
 
-  // This is used to add the ASTContext of the AST produced by build() to the
-  // clangd Context.
+  // This is used to add the ASTContext and Sema of the AST produced by build()
+  // to the clangd Context.
   mutable std::unique_ptr<WithContextValue> ASTCtx;
+  mutable std::unique_ptr<WithContextValue> SemaCtx;
 
   // By default, build() will report Error diagnostics as GTest errors.
   // Suppress this behavior by adding an 'error-ok' comment to the code.
Index: clang-tools-extra/clangd/unittests/TestTU.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TestTU.cpp
+++ clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -141,6 +141,8 @@
   }
   ASTCtx = std::make_unique<WithContextValue>(ParsedAST::CurrentASTContext,
                                               &AST->getASTContext());
+  SemaCtx = std::make_unique<WithContextValue>(ParsedAST::CurrentSema,
+                                               &AST->getSema());
   return std::move(*AST);
 }
 
Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -227,7 +227,8 @@
       };
     )cpp";
   EXPECT_DECLS("UnresolvedUsingValueDecl", {"using Base<T>::waldo", Rel::Alias},
-               {"void waldo()"});
+               {"void waldo()", Rel::TemplatePattern},
+               {"void waldo()", Rel::TemplateInstantiation});
 }
 
 TEST_F(TargetDeclTest, ConstructorInitList) {
@@ -737,6 +738,20 @@
       )cpp";
   EXPECT_DECLS("CXXDependentScopeMemberExpr",
                "template <typename T> T convert() const");
+
+  Code = R"cpp(
+        template <typename T>
+        struct vector {
+          T front();
+        };
+        template <typename T>
+        void foo(vector<vector<T>> c) {
+          c.front().[[front]]();
+        }
+      )cpp";
+  EXPECT_DECLS("CXXDependentScopeMemberExpr",
+               {"T front()", Rel::TemplatePattern},
+               {"type-parameter-0-0 front()", Rel::TemplateInstantiation});
 }
 
 TEST_F(TargetDeclTest, DependentTypes) {
@@ -750,7 +765,8 @@
         template <typename T>
         void foo(typename A<T>::[[B]]);
       )cpp";
-  EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+  EXPECT_DECLS("DependentNameTypeLoc", {"struct B", Rel::TemplatePattern},
+               {"struct B", Rel::TemplateInstantiation});
 
   // Heuristic resolution of dependent type name which doesn't get a TypeLoc
   Code = R"cpp(
@@ -760,7 +776,8 @@
         template <typename T>
         void foo(typename A<T>::[[B]]::C);
       )cpp";
-  EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
+  EXPECT_DECLS("NestedNameSpecifierLoc", {"struct B", Rel::TemplatePattern},
+               {"struct B", Rel::TemplateInstantiation});
 
   // Heuristic resolution of dependent type name whose qualifier is also
   // dependent
@@ -986,37 +1003,36 @@
 
 TEST_F(FindExplicitReferencesTest, All) {
   std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
-      {
-          // Simple expressions.
-          {R"cpp(
+      {// Simple expressions.
+       {R"cpp(
         int global;
         int func();
         void foo(int param) {
           $0^global = $1^param + $2^func();
         }
         )cpp",
-           "0: targets = {global}\n"
-           "1: targets = {param}\n"
-           "2: targets = {func}\n"},
-          {R"cpp(
+        "0: targets = {global}\n"
+        "1: targets = {param}\n"
+        "2: targets = {func}\n"},
+       {R"cpp(
         struct X { int a; };
         void foo(X x) {
           $0^x.$1^a = 10;
         }
         )cpp",
-           "0: targets = {x}\n"
-           "1: targets = {X::a}\n"},
-          {R"cpp(
+        "0: targets = {x}\n"
+        "1: targets = {X::a}\n"},
+       {R"cpp(
         // error-ok: testing with broken code
         int bar();
         int foo() {
           return $0^bar() + $1^bar(42);
         }
         )cpp",
-           "0: targets = {bar}\n"
-           "1: targets = {bar}\n"},
-          // Namespaces and aliases.
-          {R"cpp(
+        "0: targets = {bar}\n"
+        "1: targets = {bar}\n"},
+       // Namespaces and aliases.
+       {R"cpp(
           namespace ns {}
           namespace alias = ns;
           void foo() {
@@ -1024,19 +1040,19 @@
             using namespace $1^alias;
           }
         )cpp",
-           "0: targets = {ns}\n"
-           "1: targets = {alias}\n"},
-          // Using declarations.
-          {R"cpp(
+        "0: targets = {ns}\n"
+        "1: targets = {alias}\n"},
+       // Using declarations.
+       {R"cpp(
           namespace ns { int global; }
           void foo() {
             using $0^ns::$1^global;
           }
         )cpp",
-           "0: targets = {ns}\n"
-           "1: targets = {ns::global}, qualifier = 'ns::'\n"},
-          // Simple types.
-          {R"cpp(
+        "0: targets = {ns}\n"
+        "1: targets = {ns::global}, qualifier = 'ns::'\n"},
+       // Simple types.
+       {R"cpp(
          struct Struct { int a; };
          using Typedef = int;
          void foo() {
@@ -1045,13 +1061,13 @@
            static_cast<$4^Struct*>(0);
          }
        )cpp",
-           "0: targets = {Struct}\n"
-           "1: targets = {x}, decl\n"
-           "2: targets = {Typedef}\n"
-           "3: targets = {y}, decl\n"
-           "4: targets = {Struct}\n"},
-          // Name qualifiers.
-          {R"cpp(
+        "0: targets = {Struct}\n"
+        "1: targets = {x}, decl\n"
+        "2: targets = {Typedef}\n"
+        "3: targets = {y}, decl\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 $3^x;
@@ -1059,16 +1075,16 @@
            $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 = {x}, decl\n"
-           "4: targets = {a}\n"
-           "5: targets = {a::b}, qualifier = 'a::'\n"
-           "6: targets = {a::b::S}\n"
-           "7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
-           "8: targets = {y}, decl\n"},
-          {R"cpp(
+        "0: targets = {a}\n"
+        "1: targets = {a::b}, qualifier = 'a::'\n"
+        "2: targets = {a::b::S}, qualifier = 'a::b::'\n"
+        "3: targets = {x}, decl\n"
+        "4: targets = {a}\n"
+        "5: targets = {a::b}, qualifier = 'a::'\n"
+        "6: targets = {a::b::S}\n"
+        "7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
+        "8: targets = {y}, decl\n"},
+       {R"cpp(
          void foo() {
            $0^ten: // PRINT "HELLO WORLD!"
            goto $1^ten;
@@ -1085,12 +1101,12 @@
             $2^vector<bool> $3^vb;
           }
         )cpp",
-           "0: targets = {vector<int>}\n"
-           "1: targets = {vi}, decl\n"
-           "2: targets = {vector<bool>}\n"
-           "3: targets = {vb}, decl\n"},
-          // Template type aliases.
-          {R"cpp(
+        "0: targets = {vector<int>}\n"
+        "1: targets = {vi}, decl\n"
+        "2: targets = {vector<bool>}\n"
+        "3: targets = {vb}, decl\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>;
@@ -1099,12 +1115,12 @@
               $2^valias<bool> $3^vb;
             }
           )cpp",
-           "0: targets = {valias}\n"
-           "1: targets = {vi}, decl\n"
-           "2: targets = {valias}\n"
-           "3: targets = {vb}, decl\n"},
-          // Injected class name.
-          {R"cpp(
+        "0: targets = {valias}\n"
+        "1: targets = {vi}, decl\n"
+        "2: targets = {valias}\n"
+        "3: targets = {vb}, decl\n"},
+       // Injected class name.
+       {R"cpp(
             namespace foo {
               template <typename $0^T>
               class $1^Bar {
@@ -1113,13 +1129,13 @@
               };
             }
           )cpp",
-           "0: targets = {foo::Bar::T}, decl\n"
-           "1: targets = {foo::Bar}, decl\n"
-           "2: targets = {foo::Bar}\n"
-           "3: targets = {foo::Bar::f}, decl\n"
-           "4: targets = {foo::Bar}\n"},
-          // MemberExpr should know their using declaration.
-          {R"cpp(
+        "0: targets = {foo::Bar::T}, decl\n"
+        "1: targets = {foo::Bar}, decl\n"
+        "2: targets = {foo::Bar}\n"
+        "3: targets = {foo::Bar::f}, decl\n"
+        "4: targets = {foo::Bar}\n"},
+       // MemberExpr should know their using declaration.
+       {R"cpp(
             struct X { void func(int); };
             struct Y : X {
               using X::func;
@@ -1128,10 +1144,10 @@
               $0^y.$1^func(1);
             }
         )cpp",
-           "0: targets = {y}\n"
-           "1: targets = {Y::func}\n"},
-          // DeclRefExpr should know their using declaration.
-          {R"cpp(
+        "0: targets = {y}\n"
+        "1: targets = {Y::func}\n"},
+       // DeclRefExpr should know their using declaration.
+       {R"cpp(
             namespace ns { void bar(int); }
             using ns::bar;
 
@@ -1139,9 +1155,9 @@
               $0^bar(10);
             }
         )cpp",
-           "0: targets = {bar}\n"},
-          // References from a macro.
-          {R"cpp(
+        "0: targets = {bar}\n"},
+       // References from a macro.
+       {R"cpp(
             #define FOO a
             #define BAR b
 
@@ -1149,10 +1165,10 @@
               $0^FOO+$1^BAR;
             }
         )cpp",
-           "0: targets = {a}\n"
-           "1: targets = {b}\n"},
-          // No references from implicit nodes.
-          {R"cpp(
+        "0: targets = {a}\n"
+        "1: targets = {b}\n"},
+       // No references from implicit nodes.
+       {R"cpp(
             struct vector {
               int *begin();
               int *end();
@@ -1164,15 +1180,15 @@
               }
             }
         )cpp",
-           "0: targets = {x}, decl\n"
-           "1: targets = {vector}\n"
-           "2: targets = {x}\n"},
+        "0: targets = {x}, decl\n"
+        "1: targets = {vector}\n"
+        "2: targets = {x}\n"},
 // Handle UnresolvedLookupExpr.
 // FIXME
 // This case fails when expensive checks are enabled.
 // Seems like the order of ns1::func and ns2::func isn't defined.
 #ifndef EXPENSIVE_CHECKS
-          {R"cpp(
+       {R"cpp(
             namespace ns1 { void func(char*); }
             namespace ns2 { void func(int*); }
             using namespace ns1;
@@ -1183,11 +1199,11 @@
               $0^func($1^t);
             }
         )cpp",
-           "0: targets = {ns1::func, ns2::func}\n"
-           "1: targets = {t}\n"},
+        "0: targets = {ns1::func, ns2::func}\n"
+        "1: targets = {t}\n"},
 #endif
-          // Handle UnresolvedMemberExpr.
-          {R"cpp(
+       // Handle UnresolvedMemberExpr.
+       {R"cpp(
             struct X {
               void func(char*);
               void func(int*);
@@ -1198,11 +1214,11 @@
               $0^x.$1^func($2^t);
             }
         )cpp",
-           "0: targets = {x}\n"
-           "1: targets = {X::func, X::func}\n"
-           "2: targets = {t}\n"},
-          // Handle DependentScopeDeclRefExpr.
-          {R"cpp(
+        "0: targets = {x}\n"
+        "1: targets = {X::func, X::func}\n"
+        "2: targets = {t}\n"},
+       // Handle DependentScopeDeclRefExpr.
+       {R"cpp(
             template <class T>
             struct S {
               static int value;
@@ -1213,11 +1229,11 @@
               $0^S<$1^T>::$2^value;
             }
        )cpp",
-           "0: targets = {S}\n"
-           "1: targets = {T}\n"
-           "2: targets = {S::value}, qualifier = 'S<T>::'\n"},
-          // Handle CXXDependentScopeMemberExpr.
-          {R"cpp(
+        "0: targets = {S}\n"
+        "1: targets = {T}\n"
+        "2: targets = {S<type-parameter-0-0>::value}, qualifier = 'S<T>::'\n"},
+       // Handle CXXDependentScopeMemberExpr.
+       {R"cpp(
             template <class T>
             struct S {
               int value;
@@ -1228,10 +1244,10 @@
               $0^t.$1^value;
             }
        )cpp",
-           "0: targets = {t}\n"
-           "1: targets = {S::value}\n"},
-          // Type template parameters.
-          {R"cpp(
+        "0: targets = {t}\n"
+        "1: targets = {S<type-parameter-0-0>::value}\n"},
+       // Type template parameters.
+       {R"cpp(
             template <class T>
             void foo() {
               static_cast<$0^T>(0);
@@ -1239,21 +1255,21 @@
               $2^T $3^t;
             }
         )cpp",
-           "0: targets = {T}\n"
-           "1: targets = {T}\n"
-           "2: targets = {T}\n"
-           "3: targets = {t}, decl\n"},
-          // Non-type template parameters.
-          {R"cpp(
+        "0: targets = {T}\n"
+        "1: targets = {T}\n"
+        "2: targets = {T}\n"
+        "3: targets = {t}, decl\n"},
+       // Non-type template parameters.
+       {R"cpp(
             template <int I>
             void foo() {
               int $0^x = $1^I;
             }
         )cpp",
-           "0: targets = {x}, decl\n"
-           "1: targets = {I}\n"},
-          // Template template parameters.
-          {R"cpp(
+        "0: targets = {x}, decl\n"
+        "1: targets = {I}\n"},
+       // Template template parameters.
+       {R"cpp(
             template <class T> struct vector {};
 
             template <template<class> class TT, template<class> class ...TP>
@@ -1264,16 +1280,16 @@
               $6^foo<$7^TP...>();
             }
         )cpp",
-           "0: targets = {TT}\n"
-           "1: targets = {x}, decl\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(
+        "0: targets = {TT}\n"
+        "1: targets = {x}, decl\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();
             template <int(*)()> struct wrapper {};
 
@@ -1283,12 +1299,12 @@
               $3^FuncParam();
             }
         )cpp",
-           "0: targets = {wrapper<&func>}\n"
-           "1: targets = {func}\n"
-           "2: targets = {w}, decl\n"
-           "3: targets = {FuncParam}\n"},
-          // declaration references.
-          {R"cpp(
+        "0: targets = {wrapper<&func>}\n"
+        "1: targets = {func}\n"
+        "2: targets = {w}, decl\n"
+        "3: targets = {FuncParam}\n"},
+       // declaration references.
+       {R"cpp(
              namespace ns {}
              class S {};
              void foo() {
@@ -1300,19 +1316,19 @@
                namespace $9^NS = $10^ns;
              }
            )cpp",
-           "0: targets = {Foo}, decl\n"
-           "1: targets = {foo()::Foo::Foo}, decl\n"
-           "2: targets = {Foo}\n"
-           "3: targets = {foo()::Foo::field}, decl\n"
-           "4: targets = {Var}, decl\n"
-           "5: targets = {E}, decl\n"
-           "6: targets = {foo()::ABC}, decl\n"
-           "7: targets = {INT}, decl\n"
-           "8: targets = {INT2}, decl\n"
-           "9: targets = {NS}, decl\n"
-           "10: targets = {ns}\n"},
-          // User-defined conversion operator.
-          {R"cpp(
+        "0: targets = {Foo}, decl\n"
+        "1: targets = {foo()::Foo::Foo}, decl\n"
+        "2: targets = {Foo}\n"
+        "3: targets = {foo()::Foo::field}, decl\n"
+        "4: targets = {Var}, decl\n"
+        "5: targets = {E}, decl\n"
+        "6: targets = {foo()::ABC}, decl\n"
+        "7: targets = {INT}, decl\n"
+        "8: targets = {INT2}, decl\n"
+        "9: targets = {NS}, decl\n"
+        "10: targets = {ns}\n"},
+       // User-defined conversion operator.
+       {R"cpp(
             void foo() {
                class $0^Bar {};
                class $1^Foo {
@@ -1325,18 +1341,18 @@
                $7^f.$8^operator $9^Bar();
             }
         )cpp",
-           "0: targets = {Bar}, decl\n"
-           "1: targets = {Foo}, decl\n"
-           "2: targets = {foo()::Foo::operator Bar}, decl\n"
-           "3: targets = {Bar}\n"
-           "4: targets = {Bar}\n"
-           "5: targets = {Foo}\n"
-           "6: targets = {f}, decl\n"
-           "7: targets = {f}\n"
-           "8: targets = {foo()::Foo::operator Bar}\n"
-           "9: targets = {Bar}\n"},
-          // Destructor.
-          {R"cpp(
+        "0: targets = {Bar}, decl\n"
+        "1: targets = {Foo}, decl\n"
+        "2: targets = {foo()::Foo::operator Bar}, decl\n"
+        "3: targets = {Bar}\n"
+        "4: targets = {Bar}\n"
+        "5: targets = {Foo}\n"
+        "6: targets = {f}, decl\n"
+        "7: targets = {f}\n"
+        "8: targets = {foo()::Foo::operator Bar}\n"
+        "9: targets = {Bar}\n"},
+       // Destructor.
+       {R"cpp(
              void foo() {
                class $0^Foo {
                public:
@@ -1351,18 +1367,18 @@
                $6^f.~ /*...*/ $7^Foo();
              }
            )cpp",
-           "0: targets = {Foo}, decl\n"
-           // FIXME: It's better to target destructor's FunctionDecl instead of
-           // the type itself (similar to constructor).
-           "1: targets = {Foo}\n"
-           "2: targets = {foo()::Foo::destructMe}, decl\n"
-           "3: targets = {Foo}\n"
-           "4: targets = {Foo}\n"
-           "5: targets = {f}, decl\n"
-           "6: targets = {f}\n"
-           "7: targets = {Foo}\n"},
-          // cxx constructor initializer.
-          {R"cpp(
+        "0: targets = {Foo}, decl\n"
+        // FIXME: It's better to target destructor's FunctionDecl instead of
+        // the type itself (similar to constructor).
+        "1: targets = {Foo}\n"
+        "2: targets = {foo()::Foo::destructMe}, decl\n"
+        "3: targets = {Foo}\n"
+        "4: targets = {Foo}\n"
+        "5: targets = {f}, decl\n"
+        "6: targets = {f}\n"
+        "7: targets = {Foo}\n"},
+       // cxx constructor initializer.
+       {R"cpp(
              class Base {};
              void foo() {
                // member initializer
@@ -1382,34 +1398,34 @@
                };
              }
            )cpp",
-           "0: targets = {X}, decl\n"
-           "1: targets = {foo()::X::abc}, decl\n"
-           "2: targets = {foo()::X::X}, decl\n"
-           "3: targets = {foo()::X::abc}\n"
-           "4: targets = {Derived}, decl\n"
-           "5: targets = {Base}\n"
-           "6: targets = {Base}\n"
-           "7: targets = {foo()::Derived::B}, decl\n"
-           "8: targets = {foo()::Derived::Derived}, decl\n"
-           "9: targets = {Base}\n"
-           "10: targets = {Foo}, decl\n"
-           "11: targets = {foo()::Foo::Foo}, decl\n"
-           "12: targets = {foo()::Foo::Foo}, decl\n"
-           "13: targets = {Foo}\n"},
-          // Anonymous entities should not be reported.
-          {
-              R"cpp(
+        "0: targets = {X}, decl\n"
+        "1: targets = {foo()::X::abc}, decl\n"
+        "2: targets = {foo()::X::X}, decl\n"
+        "3: targets = {foo()::X::abc}\n"
+        "4: targets = {Derived}, decl\n"
+        "5: targets = {Base}\n"
+        "6: targets = {Base}\n"
+        "7: targets = {foo()::Derived::B}, decl\n"
+        "8: targets = {foo()::Derived::Derived}, decl\n"
+        "9: targets = {Base}\n"
+        "10: targets = {Foo}, decl\n"
+        "11: targets = {foo()::Foo::Foo}, decl\n"
+        "12: targets = {foo()::Foo::Foo}, decl\n"
+        "13: targets = {Foo}\n"},
+       // Anonymous entities should not be reported.
+       {
+           R"cpp(
              void foo() {
               class {} $0^x;
               int (*$1^fptr)(int $2^a, int) = nullptr;
              }
            )cpp",
-              "0: targets = {x}, decl\n"
-              "1: targets = {fptr}, decl\n"
-              "2: targets = {a}, decl\n"},
-          // Namespace aliases should be handled properly.
-          {
-              R"cpp(
+           "0: targets = {x}, decl\n"
+           "1: targets = {fptr}, decl\n"
+           "2: targets = {a}, decl\n"},
+       // Namespace aliases should be handled properly.
+       {
+           R"cpp(
                 namespace ns { struct Type {}; }
                 namespace alias = ns;
                 namespace rec_alias = alias;
@@ -1420,28 +1436,28 @@
                   $6^rec_alias::$7^Type $8^c;
                 }
            )cpp",
-              "0: targets = {ns}\n"
-              "1: targets = {ns::Type}, qualifier = 'ns::'\n"
-              "2: targets = {a}, decl\n"
-              "3: targets = {alias}\n"
-              "4: targets = {ns::Type}, qualifier = 'alias::'\n"
-              "5: targets = {b}, decl\n"
-              "6: targets = {rec_alias}\n"
-              "7: targets = {ns::Type}, qualifier = 'rec_alias::'\n"
-              "8: targets = {c}, decl\n"},
-          // Handle SizeOfPackExpr.
-          {
-              R"cpp(
+           "0: targets = {ns}\n"
+           "1: targets = {ns::Type}, qualifier = 'ns::'\n"
+           "2: targets = {a}, decl\n"
+           "3: targets = {alias}\n"
+           "4: targets = {ns::Type}, qualifier = 'alias::'\n"
+           "5: targets = {b}, decl\n"
+           "6: targets = {rec_alias}\n"
+           "7: targets = {ns::Type}, qualifier = 'rec_alias::'\n"
+           "8: targets = {c}, decl\n"},
+       // Handle SizeOfPackExpr.
+       {
+           R"cpp(
                 template <typename... E>
                 void foo() {
                   constexpr int $0^size = sizeof...($1^E);
                 };
             )cpp",
-              "0: targets = {size}, decl\n"
-              "1: targets = {E}\n"},
-          // Class template argument deduction
-          {
-              R"cpp(
+           "0: targets = {size}, decl\n"
+           "1: targets = {E}\n"},
+       // Class template argument deduction
+       {
+           R"cpp(
                 template <typename T>
                 struct Test {
                 Test(T);
@@ -1450,51 +1466,51 @@
                 $0^Test $1^a(5);
               }
             )cpp",
-              "0: targets = {Test}\n"
-              "1: targets = {a}, decl\n"},
-          // Templates
-          {R"cpp(
+           "0: targets = {Test}\n"
+           "1: targets = {a}, decl\n"},
+       // Templates
+       {R"cpp(
             namespace foo {
               template <typename $0^T>
               class $1^Bar {};
             }
           )cpp",
-           "0: targets = {foo::Bar::T}, decl\n"
-           "1: targets = {foo::Bar}, decl\n"},
-          // Templates
-          {R"cpp(
+        "0: targets = {foo::Bar::T}, decl\n"
+        "1: targets = {foo::Bar}, decl\n"},
+       // Templates
+       {R"cpp(
             namespace foo {
               template <typename $0^T>
               void $1^func();
             }
           )cpp",
-           "0: targets = {T}, decl\n"
-           "1: targets = {foo::func}, decl\n"},
-          // Templates
-          {R"cpp(
+        "0: targets = {T}, decl\n"
+        "1: targets = {foo::func}, decl\n"},
+       // Templates
+       {R"cpp(
             namespace foo {
               template <typename $0^T>
               $1^T $2^x;
             }
           )cpp",
-           "0: targets = {foo::T}, decl\n"
-           "1: targets = {foo::T}\n"
-           "2: targets = {foo::x}, decl\n"},
-          // Templates
-          {R"cpp(
+        "0: targets = {foo::T}, decl\n"
+        "1: targets = {foo::T}\n"
+        "2: targets = {foo::x}, decl\n"},
+       // Templates
+       {R"cpp(
             template<typename T> class vector {};
             namespace foo {
               template <typename $0^T>
               using $1^V = $2^vector<$3^T>;
             }
           )cpp",
-           "0: targets = {foo::T}, decl\n"
-           "1: targets = {foo::V}, decl\n"
-           "2: targets = {vector}\n"
-           "3: targets = {foo::T}\n"},
-          // Concept
-          {
-              R"cpp(
+        "0: targets = {foo::T}, decl\n"
+        "1: targets = {foo::V}, decl\n"
+        "2: targets = {vector}\n"
+        "3: targets = {foo::T}\n"},
+       // Concept
+       {
+           R"cpp(
               template <typename T>
               concept Drawable = requires (T t) { t.draw(); };
 
@@ -1505,17 +1521,17 @@
                 }
               }
           )cpp",
-              "0: targets = {T}, decl\n"
-              "1: targets = {Drawable}\n"
-              "2: targets = {T}\n"
-              "3: targets = {foo::bar}, decl\n"
-              "4: targets = {T}\n"
-              "5: targets = {t}, decl\n"
-              "6: targets = {t}\n"
-              "7: targets = {}\n"},
-          // Objective-C: properties
-          {
-              R"cpp(
+           "0: targets = {T}, decl\n"
+           "1: targets = {Drawable}\n"
+           "2: targets = {T}\n"
+           "3: targets = {foo::bar}, decl\n"
+           "4: targets = {T}\n"
+           "5: targets = {t}, decl\n"
+           "6: targets = {t}\n"
+           "7: targets = {}\n"},
+       // Objective-C: properties
+       {
+           R"cpp(
             @interface I {}
             @property(retain) I* x;
             @property(retain) I* y;
@@ -1525,12 +1541,12 @@
               $0^f.$1^x.$2^y = 0;
             }
           )cpp",
-              "0: targets = {f}\n"
-              "1: targets = {I::x}\n"
-              "2: targets = {I::y}\n"},
-          // Objective-C: implicit properties
-          {
-              R"cpp(
+           "0: targets = {f}\n"
+           "1: targets = {I::x}\n"
+           "2: targets = {I::y}\n"},
+       // Objective-C: implicit properties
+       {
+           R"cpp(
             @interface I {}
             -(I*)x;
             -(void)setY:(I*)y;
@@ -1540,11 +1556,11 @@
               $0^f.$1^x.$2^y = 0;
             }
           )cpp",
-              "0: targets = {f}\n"
-              "1: targets = {I::x}\n"
-              "2: targets = {I::setY:}\n"},
-          // Designated initializers.
-          {R"cpp(
+           "0: targets = {f}\n"
+           "1: targets = {I::x}\n"
+           "2: targets = {I::setY:}\n"},
+       // Designated initializers.
+       {R"cpp(
             void foo() {
               struct $0^Foo {
                 int $1^Bar;
@@ -1552,12 +1568,12 @@
               $2^Foo $3^f { .$4^Bar = 42 };
             }
         )cpp",
-           "0: targets = {Foo}, decl\n"
-           "1: targets = {foo()::Foo::Bar}, decl\n"
-           "2: targets = {Foo}\n"
-           "3: targets = {f}, decl\n"
-           "4: targets = {foo()::Foo::Bar}\n"},
-          {R"cpp(
+        "0: targets = {Foo}, decl\n"
+        "1: targets = {foo()::Foo::Bar}, decl\n"
+        "2: targets = {Foo}\n"
+        "3: targets = {f}, decl\n"
+        "4: targets = {foo()::Foo::Bar}\n"},
+       {R"cpp(
             void foo() {
               struct $0^Baz {
                 int $1^Field;
Index: clang-tools-extra/clangd/TUScheduler.cpp
===================================================================
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -721,8 +721,9 @@
       return Action(error(llvm::errc::invalid_argument, "invalid AST"));
     vlog("ASTWorker running {0} on version {2} of {1}", Name, FileName,
          FileInputs.Version);
-    WithContextValue Ctx(ParsedAST::CurrentASTContext,
-                         &(*AST)->getASTContext());
+    WithContextValue ASTCtx(ParsedAST::CurrentASTContext,
+                            &(*AST)->getASTContext());
+    WithContextValue SemaCtx(ParsedAST::CurrentSema, &(*AST)->getSema());
     Action(InputsAndAST{FileInputs, **AST});
   };
   startTask(Name, std::move(Task), /*UpdateType=*/None, Invalidation);
Index: clang-tools-extra/clangd/ParsedAST.h
===================================================================
--- clang-tools-extra/clangd/ParsedAST.h
+++ clang-tools-extra/clangd/ParsedAST.h
@@ -68,6 +68,8 @@
   ASTContext &getASTContext();
   const ASTContext &getASTContext() const;
 
+  Sema &getSema();
+
   Preprocessor &getPreprocessor();
   std::shared_ptr<Preprocessor> getPreprocessorPtr();
   const Preprocessor &getPreprocessor() const;
@@ -110,9 +112,10 @@
   /// AST. Might be None if no Preamble is used.
   llvm::Optional<llvm::StringRef> preambleVersion() const;
 
-  /// This context variable makes available the ASTContext of the AST being
-  /// operated on currently.
+  /// This context variable makes available the ASTContext and Sema of the AST
+  /// being operated on currently.
   static Key<ASTContext *> CurrentASTContext;
+  static Key<Sema *> CurrentSema;
 
 private:
   ParsedAST(llvm::StringRef Version,
Index: clang-tools-extra/clangd/ParsedAST.cpp
===================================================================
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -238,6 +238,7 @@
 } // namespace
 
 Key<ASTContext *> ParsedAST::CurrentASTContext;
+Key<Sema *> ParsedAST::CurrentSema;
 
 llvm::Optional<ParsedAST>
 ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
@@ -473,6 +474,8 @@
   return Clang->getASTContext();
 }
 
+Sema &ParsedAST::getSema() { return Clang->getSema(); }
+
 Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
 
 std::shared_ptr<Preprocessor> ParsedAST::getPreprocessorPtr() {
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -34,6 +34,7 @@
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Specifiers.h"
+#include "clang/Sema/Template.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Casting.h"
@@ -60,10 +61,33 @@
   return S;
 }
 
+// FIXME: Use ASTContext::getCanonicalTemplateArgument()
+TemplateArgument canonicalizeTemplateArg(const TemplateArgument &Arg) {
+  switch (Arg.getKind()) {
+  case TemplateArgument::Type: {
+    return TemplateArgument(Arg.getAsType().getCanonicalType());
+  }
+  default:
+    return Arg;
+  }
+}
+
+// A structure that resolveTypeToRecordDecl() can optionally populate
+// in the case where it discards template arguments.
+// The discarded template arguments are saved, along with other info
+// the caller may need to substitute the arguments back into declarations
+// it derives from the result of the operation (such as, into members of
+// the RecordDecl).
+struct SubstInfo {
+  // The template arguments that were discarded.
+  SmallVector<TemplateArgument, 4> TemplateArgs;
+};
+
 // Helper function for getMembersReferencedViaDependentName()
 // which takes a possibly-dependent type `T` and heuristically
 // resolves it to a CXXRecordDecl in which we can try name lookup.
-CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) {
+CXXRecordDecl *resolveTypeToRecordDecl(const Type *T,
+                                       SubstInfo *OutSubstInfo = nullptr) {
   assert(T);
 
   if (const auto *RT = T->getAs<RecordType>())
@@ -78,14 +102,55 @@
   if (!TST)
     return nullptr;
 
-  const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
+  ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
       TST->getTemplateName().getAsTemplateDecl());
   if (!TD)
     return nullptr;
 
+  if (OutSubstInfo) {
+    for (const TemplateArgument &Arg : TST->template_arguments()) {
+      OutSubstInfo->TemplateArgs.push_back(canonicalizeTemplateArg(Arg));
+    }
+  }
   return TD->getTemplatedDecl();
 }
 
+const NamedDecl *getTemplatePattern(const NamedDecl *D) {
+  if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
+    if (const auto *Result = CRD->getTemplateInstantiationPattern())
+      return Result;
+    // getTemplateInstantiationPattern returns null if the Specialization is
+    // incomplete (e.g. the type didn't need to be complete), fall back to the
+    // primary template.
+    if (CRD->getTemplateSpecializationKind() == TSK_Undeclared)
+      if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(CRD))
+        return Spec->getSpecializedTemplate()->getTemplatedDecl();
+  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    return FD->getTemplateInstantiationPattern();
+  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+    // Hmm: getTIP returns its arg if it's not an instantiation?!
+    VarDecl *T = VD->getTemplateInstantiationPattern();
+    return (T == D) ? nullptr : T;
+  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+    return ED->getInstantiatedFromMemberEnum();
+  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
+    if (const auto *Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
+      if (const DeclContext *ParentPat =
+              dyn_cast_or_null<DeclContext>(getTemplatePattern(Parent)))
+        for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
+          if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
+            return BaseND;
+  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
+    if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
+      if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
+        for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
+          return BaseECD;
+      }
+    }
+  }
+  return nullptr;
+}
+
 // Given a tag-decl type and a member name, heuristically resolve the
 // name to one or more declarations.
 // The current heuristic is simply to look up the name in the primary
@@ -108,10 +173,44 @@
     auto Result = ET->getDecl()->lookup(Name);
     return {Result.begin(), Result.end()};
   }
-  if (auto *RD = resolveTypeToRecordDecl(T)) {
-    if (!RD->hasDefinition())
-      return {};
+  SubstInfo SubstInfo;
+  if (auto *RD = resolveTypeToRecordDecl(T, &SubstInfo)) {
+    if (!RD->hasDefinition()) {
+      // FIXME: Explain why we try the template pattern here.
+      RD = const_cast<CXXRecordDecl *>(
+          cast<CXXRecordDecl>(getTemplatePattern(RD)));
+      if (!RD->hasDefinition()) {
+        return {};
+      }
+    }
     RD = RD->getDefinition();
+
+    // If resolveTypeToRecordDecl() discarded template arguments,
+    // substitute them back into the decl here. This makes the
+    // results of lookupDependentName() more useful; for example,
+    // if the incoming type was `vector<vector<U>>`, and we are looking
+    // up the name `front()`, the return type of the lookup result
+    // will be `vector<U>` rather than just a template-parameter, making
+    // it possible to do another lookup in the return type.
+    if (!SubstInfo.TemplateArgs.empty()) {
+      auto *Sema = Context::current().getExisting(ParsedAST::CurrentSema);
+      Sema::InstantiatingTemplate Inst(*Sema, RD->getLocation(), RD);
+      void *InsertPos = nullptr;
+      ClassTemplateDecl *CT = RD->getDescribedClassTemplate();
+      assert(CT);
+      ClassTemplateSpecializationDecl *SubstRD =
+          CT->findSpecialization(SubstInfo.TemplateArgs, InsertPos);
+      if (!SubstRD) {
+        SubstRD = ClassTemplateSpecializationDecl::Create(
+            Sema->getASTContext(), CT->getTemplatedDecl()->getTagKind(),
+            CT->getDeclContext(), CT->getTemplatedDecl()->getBeginLoc(),
+            CT->getLocation(), CT, SubstInfo.TemplateArgs, nullptr);
+        Sema->InstantiateClassTemplateSpecialization(RD->getLocation(), SubstRD,
+                                                     TSK_ImplicitInstantiation);
+      }
+      RD = SubstRD;
+    }
+
     return RD->lookupDependentName(Name, Filter);
   }
   return {};
@@ -258,42 +357,6 @@
   return nullptr;
 }
 
-const NamedDecl *getTemplatePattern(const NamedDecl *D) {
-  if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
-    if (const auto *Result = CRD->getTemplateInstantiationPattern())
-      return Result;
-    // getTemplateInstantiationPattern returns null if the Specialization is
-    // incomplete (e.g. the type didn't need to be complete), fall back to the
-    // primary template.
-    if (CRD->getTemplateSpecializationKind() == TSK_Undeclared)
-      if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(CRD))
-        return Spec->getSpecializedTemplate()->getTemplatedDecl();
-  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
-    return FD->getTemplateInstantiationPattern();
-  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
-    // Hmm: getTIP returns its arg if it's not an instantiation?!
-    VarDecl *T = VD->getTemplateInstantiationPattern();
-    return (T == D) ? nullptr : T;
-  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
-    return ED->getInstantiatedFromMemberEnum();
-  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
-    if (const auto *Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
-      if (const DeclContext *ParentPat =
-              dyn_cast_or_null<DeclContext>(getTemplatePattern(Parent)))
-        for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
-          if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
-            return BaseND;
-  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
-    if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
-      if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
-        for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
-          return BaseECD;
-      }
-    }
-  }
-  return nullptr;
-}
-
 // TargetFinder locates the entities that an AST node refers to.
 //
 // Typically this is (possibly) one declaration and (possibly) one type, but
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -79,6 +79,7 @@
 
   void onMainAST(PathRef Path, ParsedAST &AST, PublishFn Publish) override {
     WithContextValue ASTCtx(ParsedAST::CurrentASTContext, &AST.getASTContext());
+    WithContextValue SemaCtx(ParsedAST::CurrentSema, &AST.getSema());
 
     if (FIndex)
       FIndex->updateMain(Path, AST);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D93522: [WIP] [clangd... Nathan Ridge via Phabricator via cfe-commits

Reply via email to