nridge updated this revision to Diff 276320.
nridge added a comment.

Split patch


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,23 @@
   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()");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -58,6 +58,10 @@
   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 possibly-dependent type `T` and heuristically
 // resolves it to a CXXRecordDecl in which we can try name lookup.
@@ -79,6 +83,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
@@ -92,12 +109,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()));
@@ -132,7 +164,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);
       },
@@ -167,14 +199,15 @@
     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);
   }
   case Stmt::DependentScopeDeclRefExprClass: {
     const auto *RE = llvm::cast<DependentScopeDeclRefExpr>(E);
     return getMembersReferencedViaDependentName(
-        RE->getQualifier()->getAsType(),
+        nullptr, RE->getQualifier()->getAsType(),
         [RE](ASTContext &) { return RE->getDeclName(); },
         /*IsNonstaticMember=*/false);
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to