Author: Nathan Ridge
Date: 2025-01-23T01:43:44-05:00
New Revision: ba174855203403f6c3e2a46bdd79dbb3e27ac6a4

URL: 
https://github.com/llvm/llvm-project/commit/ba174855203403f6c3e2a46bdd79dbb3e27ac6a4
DIFF: 
https://github.com/llvm/llvm-project/commit/ba174855203403f6c3e2a46bdd79dbb3e27ac6a4.diff

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

Fixes https://github.com/clangd/clangd/issues/1249

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaCodeComplete.cpp
    clang/test/CodeCompletion/member-access.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 75931bb25f06d9..a03f42ab910edd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1272,6 +1272,13 @@ libclang
 - Added ``clang_getOffsetOfBase``, which allows computing the offset of a base
   class in a class's layout.
 
+
+Code Completion
+---------------
+
+- Use ``HeuristicResolver`` (upstreamed from clangd) to improve code 
completion results
+  in dependent code
+
 Static Analyzer
 ---------------
 

diff  --git a/clang/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index 69cda6e68bd36b..58f3efbe0daf89 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5736,11 +5736,19 @@ 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>()) {
+    if (auto Decls = Resolver.resolveDependentNameType(DNT);
+        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 +5757,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 +5800,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 +5821,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 +5866,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 +5906,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
+}
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to