nridge updated this revision to Diff 276916.
nridge marked 4 inline comments as done.
nridge added a comment.

Address review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82739/new/

https://reviews.llvm.org/D82739

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -548,6 +548,40 @@
   EXPECT_DECLS("UnresolvedMemberExpr", "void func(int *)", "void func(char *)");
 }
 
+TEST_F(TargetDeclTest, DependentExprs) {
+  Flags = {"-fno-delayed-template-parsing"};
+
+  // Heuristic resolution of method of dependent field
+  Code = R"cpp(
+        struct A { void foo() {} };
+        template <typename T>
+        struct B {
+          A a;
+          void bar() {
+            this->a.[[foo]]();
+          }
+        };
+      )cpp";
+  EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
+
+  Code = R"cpp(
+        struct A {
+          void foo() {}
+        };
+        struct B {
+          A getA();
+        };
+        template <typename T>
+        struct C {
+          B c;
+          void bar() { 
+            this->c.getA().[[foo]]();
+          }
+        };
+    )cpp";
+  EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
@@ -705,36 +739,37 @@
 
 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() {
@@ -742,19 +777,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() {
@@ -763,13 +798,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;
@@ -777,25 +812,25 @@
            $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;
          }
        )cpp",
-       "0: targets = {ten}, decl\n"
-       "1: targets = {ten}\n"},
-       // Simple templates.
-       {R"cpp(
+           "0: targets = {ten}, decl\n"
+           "1: targets = {ten}\n"},
+          // Simple templates.
+          {R"cpp(
           template <class T> struct vector { using value_type = T; };
           template <> struct vector<bool> { using value_type = bool; };
           void foo() {
@@ -803,12 +838,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>;
@@ -817,12 +852,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 {
@@ -831,13 +866,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;
@@ -846,10 +881,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;
 
@@ -857,9 +892,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
 
@@ -867,10 +902,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();
@@ -882,15 +917,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;
@@ -901,11 +936,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*);
@@ -916,11 +951,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;
@@ -931,11 +966,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::value}, qualifier = 'S<T>::'\n"},
+          // Handle CXXDependentScopeMemberExpr.
+          {R"cpp(
             template <class T>
             struct S {
               int value;
@@ -946,10 +981,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::value}\n"},
+          // Type template parameters.
+          {R"cpp(
             template <class T>
             void foo() {
               static_cast<$0^T>(0);
@@ -957,21 +992,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>
@@ -982,16 +1017,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 {};
 
@@ -1001,12 +1036,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() {
@@ -1018,19 +1053,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 {
@@ -1043,18 +1078,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:
@@ -1069,18 +1104,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
@@ -1100,34 +1135,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;
@@ -1138,28 +1173,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);
@@ -1168,51 +1203,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(); };
 
@@ -1223,17 +1258,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;
@@ -1243,12 +1278,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;
@@ -1258,11 +1293,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;
@@ -1270,12 +1305,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;
@@ -1286,16 +1321,16 @@
               $5^Bar $6^bar { .$7^Foo.$8^Field = 42 };
             }
         )cpp",
-        "0: targets = {Baz}, decl\n"
-        "1: targets = {foo()::Baz::Field}, decl\n"
-        "2: targets = {Bar}, decl\n"
-        "3: targets = {Baz}\n"
-        "4: targets = {foo()::Bar::Foo}, decl\n"
-        "5: targets = {Bar}\n"
-        "6: targets = {bar}, decl\n"
-        "7: targets = {foo()::Bar::Foo}\n"
-        "8: targets = {foo()::Baz::Field}\n"},
-      {R"cpp(
+           "0: targets = {Baz}, decl\n"
+           "1: targets = {foo()::Baz::Field}, decl\n"
+           "2: targets = {Bar}, decl\n"
+           "3: targets = {Baz}\n"
+           "4: targets = {foo()::Bar::Foo}, decl\n"
+           "5: targets = {Bar}\n"
+           "6: targets = {bar}, decl\n"
+           "7: targets = {foo()::Bar::Foo}\n"
+           "8: targets = {foo()::Baz::Field}\n"},
+          {R"cpp(
            template<typename T>
            void crash(T);
            template<typename T>
@@ -1303,12 +1338,11 @@
              $0^crash({.$1^x = $2^T()});
            }
         )cpp",
-        "0: targets = {crash}\n"
-        "1: targets = {}\n"
-        "2: targets = {T}\n"
-      },
-      // unknown template name should not crash.
-      {R"cpp(
+           "0: targets = {crash}\n"
+           "1: targets = {}\n"
+           "2: targets = {T}\n"},
+          // unknown template name should not crash.
+          {R"cpp(
         template <template <typename> typename T>
         struct Base {};
         namespace foo {
@@ -1316,12 +1350,12 @@
         struct $1^Derive : $2^Base<$3^T::template $4^Unknown> {};
         }
       )cpp",
-      "0: targets = {foo::Derive::T}, decl\n"
-      "1: targets = {foo::Derive}, decl\n"
-      "2: targets = {Base}\n"
-      "3: targets = {foo::Derive::T}\n"
-      "4: targets = {}, qualifier = 'T::'\n"},
-    };
+           "0: targets = {foo::Derive::T}, decl\n"
+           "1: targets = {foo::Derive}, decl\n"
+           "2: targets = {Base}\n"
+           "3: targets = {foo::Derive::T}\n"
+           "4: targets = {}, qualifier = 'T::'\n"},
+      };
 
   for (const auto &C : Cases) {
     llvm::StringRef ExpectedCode = C.first;
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -58,11 +58,20 @@
   return S;
 }
 
+// Forward declaration, needed as this function is mutually recursive
+// with some of the other helpers below.
+std::vector<const NamedDecl *> resolveDependentExprToDecls(const Expr *E);
+
 // Helper function for getMembersReferencedViaDependentName()
-// which takes a dependent type `T` and heuristically
+// 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) {
   assert(T);
+
+  if (auto *RT = T->getAs<RecordType>()) {
+    return dyn_cast<CXXRecordDecl>(RT->getDecl());
+  }
+
   if (const auto *ICNT = T->getAs<InjectedClassNameType>()) {
     T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
   }
@@ -76,6 +85,19 @@
   return TD->getTemplatedDecl();
 }
 
+// Try to heuristically resolve the type of a dependent expression `E`.
+const Type *resolveDependentExprToType(const Expr *E) {
+  std::vector<const NamedDecl *> Decls = resolveDependentExprToDecls(E);
+  if (Decls.size() != 1) // Names an overload set -- just bail.
+    return nullptr;
+  if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
+    return TD->getTypeForDecl();
+  } else if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
+    return VD->getType().getTypePtrOrNull();
+  }
+  return nullptr;
+}
+
 // Given a dependent 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
@@ -89,12 +111,27 @@
 // an ASTContext, because an ASTContext may be needed to obtain the
 // name (e.g. if it's an operator name), but the caller may not have
 // access to an ASTContext.
+// Optionally, in cases where the type represents the type of a
+// dependent expression, the expression `E` in question can be
+// provided, which allows us to provide richer heuristics by
+// introspecting the expression and trying to reason about its type.
 std::vector<const NamedDecl *> getMembersReferencedViaDependentName(
-    const Type *T,
+    Expr *E, const Type *T,
     llvm::function_ref<DeclarationName(ASTContext &)> NameFactory,
     bool IsNonstaticMember) {
   if (!T)
     return {};
+  if (auto *BT = T->getAs<BuiltinType>()) {
+    // If T is the type of a dependent expression, it's just represented
+    // as BultinType::Dependent which gives us no information. If the
+    // caller provides the expression `E`, we can get further by
+    // analyzing it.
+    if (E && BT->getKind() == BuiltinType::Dependent) {
+      T = resolveDependentExprToType(E);
+      if (!T)
+        return {};
+    }
+  }
   if (auto *ET = T->getAs<EnumType>()) {
     auto Result =
         ET->getDecl()->lookup(NameFactory(ET->getDecl()->getASTContext()));
@@ -129,7 +166,7 @@
   // Look up operator-> in the primary template. If we find one, it's probably a
   // smart pointer type.
   auto ArrowOps = getMembersReferencedViaDependentName(
-      T,
+      nullptr, T,
       [](ASTContext &Ctx) {
         return Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow);
       },
@@ -163,16 +200,29 @@
     if (ME->isArrow()) {
       BaseType = getPointeeType(BaseType);
     }
+    Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
     return getMembersReferencedViaDependentName(
-        BaseType, [ME](ASTContext &) { return ME->getMember(); },
+        Base, BaseType, [ME](ASTContext &) { return ME->getMember(); },
         /*IsNonstaticMember=*/true);
   }
   if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
     return getMembersReferencedViaDependentName(
-        RE->getQualifier()->getAsType(),
+        nullptr, RE->getQualifier()->getAsType(),
         [RE](ASTContext &) { return RE->getDeclName(); },
         /*IsNonstaticMember=*/false);
   }
+  if (const auto *CE = dyn_cast<CallExpr>(E)) {
+    const auto *CalleeType = resolveDependentExprToType(CE->getCallee());
+    if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) {
+      CalleeType = FnTypePtr->getPointeeType().getTypePtr();
+    }
+    if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
+      if (const auto *D =
+              resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
+        return {D};
+      }
+    }
+  }
   return {};
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to