[clang] [clang][CodeComplete] Use HeuristicResolver to resolve DependentNameTypes (PR #123818)

Nathan Ridge via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 21 23:47:08 PST 2025


https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/123818

>From 25fdf43fb182212e859aba806ab32cc25ec466af Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Thu, 26 Dec 2024 20:59:06 -0500
Subject: [PATCH 1/3] [clang][CodeComplete] Use HeuristicResolver to resolve
 pointee types

Fixes https://github.com/clangd/clangd/issues/810
---
 clang/include/clang/Sema/SemaCodeCompletion.h |  2 ++
 clang/lib/Sema/SemaCodeComplete.cpp           | 15 ++++++++++-----
 clang/test/CodeCompletion/member-access.cpp   | 17 +++++++++++++++++
 3 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h b/clang/include/clang/Sema/SemaCodeCompletion.h
index 50409439389b06..e931596c215d31 100644
--- a/clang/include/clang/Sema/SemaCodeCompletion.h
+++ b/clang/include/clang/Sema/SemaCodeCompletion.h
@@ -23,6 +23,7 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Designator.h"
+#include "clang/Sema/HeuristicResolver.h"
 #include "clang/Sema/Ownership.h"
 #include "clang/Sema/SemaBase.h"
 #include "llvm/ADT/StringRef.h"
@@ -43,6 +44,7 @@ class SemaCodeCompletion : public SemaBase {
 
   /// Code-completion consumer.
   CodeCompleteConsumer *CodeCompleter;
+  HeuristicResolver Resolver;
 
   /// Describes the context in which code completion occurs.
   enum ParserCompletionContext {
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8a848df70cc5a1..69cda6e68bd36b 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -34,6 +34,7 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Designator.h"
+#include "clang/Sema/HeuristicResolver.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Overload.h"
 #include "clang/Sema/ParsedAttr.h"
@@ -5861,8 +5862,10 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
   enum CodeCompletionContext::Kind contextKind;
 
   if (IsArrow) {
-    if (const auto *Ptr = ConvertedBaseType->getAs<PointerType>())
-      ConvertedBaseType = Ptr->getPointeeType();
+    if (QualType PointeeType = Resolver.getPointeeType(ConvertedBaseType);
+        !PointeeType.isNull()) {
+      ConvertedBaseType = PointeeType;
+    }
   }
 
   if (IsArrow) {
@@ -5899,8 +5902,9 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
     ExprValueKind BaseKind = Base->getValueKind();
 
     if (IsArrow) {
-      if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
-        BaseType = Ptr->getPointeeType();
+      if (QualType PointeeType = Resolver.getPointeeType(BaseType);
+          !PointeeType.isNull()) {
+        BaseType = PointeeType;
         BaseKind = VK_LValue;
       } else if (BaseType->isObjCObjectPointerType() ||
                  BaseType->isTemplateTypeParmType()) {
@@ -10472,4 +10476,5 @@ void SemaCodeCompletion::GatherGlobalCodeCompletions(
 
 SemaCodeCompletion::SemaCodeCompletion(Sema &S,
                                        CodeCompleteConsumer *CompletionConsumer)
-    : SemaBase(S), CodeCompleter(CompletionConsumer) {}
+    : SemaBase(S), CodeCompleter(CompletionConsumer),
+      Resolver(S.getASTContext()) {}
diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp
index 912f269db6c1ac..ab6dc69bf2923d 100644
--- a/clang/test/CodeCompletion/member-access.cpp
+++ b/clang/test/CodeCompletion/member-access.cpp
@@ -384,3 +384,20 @@ void Foo() {
 // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:382:5 %s -o - | FileCheck -check-prefix=CHECK-DEREF-DEPENDENT %s
 // CHECK-DEREF-DEPENDENT: [#void#]Add()
 }
+
+namespace dependent_smart_pointer {
+template <typename T>
+struct smart_pointer {
+  T* operator->();
+};
+
+template <typename T>
+struct node {
+  smart_pointer<node<T>> next;
+  void foo() {
+    next->next;
+    // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:398:11 %s -o - | FileCheck -check-prefix=CHECK-DEPENDENT-SMARTPTR %s
+    // CHECK-DEPENDENT-SMARTPTR: [#smart_pointer<node<T>>#]next
+  }
+};
+}

>From 58029449d63af7f452820dd02aba0d10134f588c Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Tue, 21 Jan 2025 15:56:27 -0500
Subject: [PATCH 2/3] [clang][CodeComplete] Use HeuristicResolver to resolve
 DependentNameTypes

Fixes https://github.com/clangd/clangd/issues/1249
---
 clang/lib/Sema/SemaCodeComplete.cpp         | 25 +++++++++++++++------
 clang/test/CodeCompletion/member-access.cpp | 16 +++++++++++++
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 69cda6e68bd36b..d349928e1a171b 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5736,11 +5736,20 @@ class ConceptInfo {
 // In particular, when E->getType() is DependentTy, try to guess a likely type.
 // We accept some lossiness (like dropping parameters).
 // We only try to handle common expressions on the LHS of MemberExpr.
-QualType getApproximateType(const Expr *E) {
+QualType getApproximateType(const Expr *E, HeuristicResolver &Resolver) {
   if (E->getType().isNull())
     return QualType();
   E = E->IgnoreParenImpCasts();
   QualType Unresolved = E->getType();
+  // Resolve DependentNameType
+  if (const auto *DNT = Unresolved->getAs<DependentNameType>()) {
+    auto Decls = Resolver.resolveDependentNameType(DNT);
+    if (Decls.size() == 1) {
+      if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
+        return QualType(TD->getTypeForDecl(), 0);
+      }
+    }
+  }
   // We only resolve DependentTy, or undeduced autos (including auto* etc).
   if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
     AutoType *Auto = Unresolved->getContainedAutoType();
@@ -5749,7 +5758,7 @@ QualType getApproximateType(const Expr *E) {
   }
   // A call: approximate-resolve callee to a function type, get its return type
   if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) {
-    QualType Callee = getApproximateType(CE->getCallee());
+    QualType Callee = getApproximateType(CE->getCallee(), Resolver);
     if (Callee.isNull() ||
         Callee->isSpecificPlaceholderType(BuiltinType::BoundMember))
       Callee = Expr::findBoundMemberType(CE->getCallee());
@@ -5792,7 +5801,7 @@ QualType getApproximateType(const Expr *E) {
   if (const auto *CDSME = llvm::dyn_cast<CXXDependentScopeMemberExpr>(E)) {
     QualType Base = CDSME->isImplicitAccess()
                         ? CDSME->getBaseType()
-                        : getApproximateType(CDSME->getBase());
+                        : getApproximateType(CDSME->getBase(), Resolver);
     if (CDSME->isArrow() && !Base.isNull())
       Base = Base->getPointeeType(); // could handle unique_ptr etc here?
     auto *RD =
@@ -5813,14 +5822,15 @@ QualType getApproximateType(const Expr *E) {
   if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) {
     if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) {
       if (VD->hasInit())
-        return getApproximateType(VD->getInit());
+        return getApproximateType(VD->getInit(), Resolver);
     }
   }
   if (const auto *UO = llvm::dyn_cast<UnaryOperator>(E)) {
     if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) {
       // We recurse into the subexpression because it could be of dependent
       // type.
-      if (auto Pointee = getApproximateType(UO->getSubExpr())->getPointeeType();
+      if (auto Pointee =
+              getApproximateType(UO->getSubExpr(), Resolver)->getPointeeType();
           !Pointee.isNull())
         return Pointee;
       // Our caller expects a non-null result, even though the SubType is
@@ -5857,7 +5867,8 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
       SemaRef.PerformMemberExprBaseConversion(Base, IsArrow);
   if (ConvertedBase.isInvalid())
     return;
-  QualType ConvertedBaseType = getApproximateType(ConvertedBase.get());
+  QualType ConvertedBaseType =
+      getApproximateType(ConvertedBase.get(), Resolver);
 
   enum CodeCompletionContext::Kind contextKind;
 
@@ -5896,7 +5907,7 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
       return false;
     Base = ConvertedBase.get();
 
-    QualType BaseType = getApproximateType(Base);
+    QualType BaseType = getApproximateType(Base, Resolver);
     if (BaseType.isNull())
       return false;
     ExprValueKind BaseKind = Base->getValueKind();
diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp
index ab6dc69bf2923d..bf35f7ad021f71 100644
--- a/clang/test/CodeCompletion/member-access.cpp
+++ b/clang/test/CodeCompletion/member-access.cpp
@@ -401,3 +401,19 @@ struct node {
   }
 };
 }
+
+namespace dependent_nested_class {
+template <typename T>
+struct Foo {
+  struct Bar {
+    int field;
+  };
+};
+template <typename T>
+void f() {
+  typename Foo<T>::Bar bar;
+  bar.field;
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:415:7 %s -o - | FileCheck -check-prefix=CHECK-DEPENDENT-NESTEDCLASS %s
+  // CHECK-DEPENDENT-NESTEDCLASS: [#int#]field
+}
+}

>From bc4b90d8b6599d6108e6873e59b6974d6971af19 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Wed, 22 Jan 2025 02:46:59 -0500
Subject: [PATCH 3/3] Add blank line

Co-authored-by: Younan Zhang <zyn7109 at gmail.com>
---
 clang/test/CodeCompletion/member-access.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp
index 4efb1fa0cc90fe..bf35f7ad021f71 100644
--- a/clang/test/CodeCompletion/member-access.cpp
+++ b/clang/test/CodeCompletion/member-access.cpp
@@ -416,4 +416,4 @@ void f() {
   // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:415:7 %s -o - | FileCheck -check-prefix=CHECK-DEPENDENT-NESTEDCLASS %s
   // CHECK-DEPENDENT-NESTEDCLASS: [#int#]field
 }
-}
\ No newline at end of file
+}



More information about the cfe-commits mailing list