sammccall created this revision.
sammccall added a reviewer: hokein.
Herald added a project: All.
sammccall requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When the initializer of an `auto` variable is dependent, clang doesn't give the
DeclRefExpr a useful dependent type that we can apply heuristics to.
However we can dig one up by looking at the initializer.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140044

Files:
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp

Index: clang/test/CodeCompletion/member-access.cpp
===================================================================
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -108,9 +108,17 @@
 // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:97:10 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
 // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:98:12 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
 
+  auto copy_object = object;
+  auto copy_object2 = object2;
+  object.field;
+  object2->field;
+// CHECK-AUTO: field : [#T#]field
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:113:10 %s -o - | FileCheck -check-prefix=CHECK-AUTO %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:114:12 %s -o - | FileCheck -check-prefix=CHECK-AUTO %s
+
   object.relatedField.relatedFunction().baseTemplateField;
 // CHECK-DEP-CHAIN: baseTemplateField : [#T#]baseTemplateField
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:111:41 %s -o - | FileCheck -check-prefix=CHECK-DEP-CHAIN %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:119:41 %s -o - | FileCheck -check-prefix=CHECK-DEP-CHAIN %s
 }
 
 
@@ -127,8 +135,8 @@
 // CHECK-CC3: overload1 : [#void#]overload1(<#const int &#>)
 // CHECK-CC3: overload1 : [#void#]overload1(<#const double &#>)
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:119:10 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:120:12 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:127:10 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:128:12 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
 }
 
 template <typename T>
@@ -142,17 +150,17 @@
 // CHECK-CC4: BaseTemplate : BaseTemplate::
 // CHECK-CC4: baseTemplateField : [#int#]baseTemplateField
 // CHECK-CC4: baseTemplateFunction : [#int#]baseTemplateFunction()
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:141:8 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:149:8 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
     o2.baseTemplateField;
 // CHECK-CC5: BaseTemplate : BaseTemplate::
 // CHECK-CC5: baseTemplateField : [#T#]baseTemplateField
 // CHECK-CC5: baseTemplateFunction : [#T#]baseTemplateFunction()
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:146:8 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:154:8 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
     this->o1;
 // CHECK-CC6: [#void#]function()
 // CHECK-CC6: o1 : [#BaseTemplate<int>#]o1
 // CHECK-CC6: o2 : [#BaseTemplate<T>#]o2
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:151:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:159:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
   }
 
   static void staticFn(T &obj);
@@ -169,9 +177,9 @@
 // CHECK-CC7: o2 : [#BaseTemplate<T>#]o2
 // CHECK-CC7: staticFn : [#void#]staticFn(<#T &obj#>)
 // CHECK-CC7: Template : Template
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:165:16 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:173:16 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
   typename Template<T>::Nested m;
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:173:25 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:181:25 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
 }
 
 class Proxy2 {
@@ -188,34 +196,34 @@
   p.
 }
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:184:6 %s -o - | FileCheck -check-prefix=CHECK-CC8 --implicit-check-not="Derived : Derived(" %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:192:6 %s -o - | FileCheck -check-prefix=CHECK-CC8 --implicit-check-not="Derived : Derived(" %s
 // CHECK-CC8: Base1 (InBase) : Base1::
 // CHECK-CC8: member1 (InBase) : [#int#][#Base1::#]member1
 // CHECK-CC8: member1 (InBase) : [#int#][#Base2::#]member1
 // CHECK-CC8: member2 (InBase) : [#float#][#Base1::#]member2
 // CHECK-CC8: member3 (InBase) : [#double#][#Base2::#]member3
 // CHECK-CC8: member4 : [#int#]member4
-// CHECK-CC8: member5 : [#int#]member5 (requires fix-it: {184:4-184:6} to ".")
+// CHECK-CC8: member5 : [#int#]member5 (requires fix-it: {192:4-192:6} to ".")
 // CHECK-CC8: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#float#>)
 // CHECK-CC8: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#double#>)[# const#]
 // CHECK-CC8: memfun1 (Hidden,InBase) : [#void#]Base2::memfun1(<#int#>)
 // CHECK-CC8: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>)
 // CHECK-CC8: memfun3 : [#int#]memfun3(<#int#>)
-// CHECK-CC8: operator-> : [#Derived *#]operator->()[# const#] (requires fix-it: {184:4-184:6} to ".")
+// CHECK-CC8: operator-> : [#Derived *#]operator->()[# const#] (requires fix-it: {192:4-192:6} to ".")
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:188:6 %s -o - | FileCheck -check-prefix=CHECK-CC9 --implicit-check-not="Derived : Derived(" %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:196:6 %s -o - | FileCheck -check-prefix=CHECK-CC9 --implicit-check-not="Derived : Derived(" %s
 // CHECK-CC9: Base1 (InBase) : Base1::
-// CHECK-CC9: member1 (InBase) : [#int#][#Base1::#]member1 (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: member1 (InBase) : [#int#][#Base2::#]member1 (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: member2 (InBase) : [#float#][#Base1::#]member2 (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: member3 (InBase) : [#double#][#Base2::#]member3 (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: member4 : [#int#]member4 (requires fix-it: {188:4-188:5} to "->")
+// CHECK-CC9: member1 (InBase) : [#int#][#Base1::#]member1 (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: member1 (InBase) : [#int#][#Base2::#]member1 (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: member2 (InBase) : [#float#][#Base1::#]member2 (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: member3 (InBase) : [#double#][#Base2::#]member3 (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: member4 : [#int#]member4 (requires fix-it: {196:4-196:5} to "->")
 // CHECK-CC9: member5 : [#int#]member5
-// CHECK-CC9: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#float#>) (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#double#>)[# const#] (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: memfun1 (Hidden,InBase) : [#void#]Base2::memfun1(<#int#>) (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>) (requires fix-it: {188:4-188:5} to "->")
-// CHECK-CC9: memfun3 : [#int#]memfun3(<#int#>) (requires fix-it: {188:4-188:5} to "->")
+// CHECK-CC9: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#float#>) (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#double#>)[# const#] (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: memfun1 (Hidden,InBase) : [#void#]Base2::memfun1(<#int#>) (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>) (requires fix-it: {196:4-196:5} to "->")
+// CHECK-CC9: memfun3 : [#int#]memfun3(<#int#>) (requires fix-it: {196:4-196:5} to "->")
 // CHECK-CC9: operator-> : [#Derived *#]operator->()[# const#]
 
 // These overload sets differ only by return type and this-qualifiers.
@@ -241,28 +249,28 @@
   static_cast<Overloads&&>(X).
 }
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:232:7 %s -o - | FileCheck -check-prefix=CHECK-LVALUE %s \
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:240:7 %s -o - | FileCheck -check-prefix=CHECK-LVALUE %s \
 // RUN: --implicit-check-not="[#int#]ConstOverload(" \
 // RUN: --implicit-check-not="[#double#]RefOverload(" \
 // RUN: --implicit-check-not="[#char#]RefOverload("
 // CHECK-LVALUE-DAG: [#double#]ConstOverload(
 // CHECK-LVALUE-DAG: [#int#]RefOverload(
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:235:12 %s -o - | FileCheck -check-prefix=CHECK-CONSTLVALUE %s \
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:243:12 %s -o - | FileCheck -check-prefix=CHECK-CONSTLVALUE %s \
 // RUN: --implicit-check-not="[#double#]ConstOverload(" \
 // RUN: --implicit-check-not="[#int#]RefOverload(" \
 // RUN: --implicit-check-not="[#char#]RefOverload("
 // CHECK-CONSTLVALUE: [#int#]ConstOverload(
 // CHECK-CONSTLVALUE: [#double#]RefOverload(
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:238:15 %s -o - | FileCheck -check-prefix=CHECK-PRVALUE %s \
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:246:15 %s -o - | FileCheck -check-prefix=CHECK-PRVALUE %s \
 // RUN: --implicit-check-not="[#int#]ConstOverload(" \
 // RUN: --implicit-check-not="[#int#]RefOverload(" \
 // RUN: --implicit-check-not="[#double#]RefOverload("
 // CHECK-PRVALUE: [#double#]ConstOverload(
 // CHECK-PRVALUE: [#char#]RefOverload(
 
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:241:31 %s -o - | FileCheck -check-prefix=CHECK-XVALUE %s \
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:249:31 %s -o - | FileCheck -check-prefix=CHECK-XVALUE %s \
 // RUN: --implicit-check-not="[#int#]ConstOverload(" \
 // RUN: --implicit-check-not="[#int#]RefOverload(" \
 // RUN: --implicit-check-not="[#double#]RefOverload("
@@ -276,7 +284,7 @@
   } s;
   return s.
 }
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:277:12 %s -o - | FileCheck -check-prefix=CHECK-OPER %s \
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:285:12 %s -o - | FileCheck -check-prefix=CHECK-OPER %s \
 // RUN: --implicit-check-not="[#char#]operator=("
 // CHECK-OPER: [#int#]operator=(
 
@@ -287,14 +295,14 @@
   // No overload matches, but we have recovery-expr with the correct type.
   overloaded().
 }
-// RUN: not %clang_cc1 -fsyntax-only -frecovery-ast -frecovery-ast-type -code-completion-at=%s:288:16 %s -o - | FileCheck -check-prefix=CHECK-RECOVERY %s
+// RUN: not %clang_cc1 -fsyntax-only -frecovery-ast -frecovery-ast-type -code-completion-at=%s:296:16 %s -o - | FileCheck -check-prefix=CHECK-RECOVERY %s
 // CHECK-RECOVERY: [#int#]member
 template <typename T>
 void fooDependent(T t) {
   // Overload not resolved, but we notice all candidates return the same type.
   overloaded(t).
 }
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:295:17 %s -o - | FileCheck -check-prefix=CHECK-OVERLOAD %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:303:17 %s -o - | FileCheck -check-prefix=CHECK-OVERLOAD %s
 // CHECK-OVERLOAD: [#int#]member
 
 struct Base4 {
@@ -308,7 +316,7 @@
 void testMembersFromBasesInDependentContext() {
   Derived2<T> X;
   (void)X.base4().base4();
-  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:310:19 %s -o - | FileCheck -check-prefix=CHECK-MEMBERS-FROM-BASE-DEPENDENT %s
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:318:19 %s -o - | FileCheck -check-prefix=CHECK-MEMBERS-FROM-BASE-DEPENDENT %s
   // CHECK-MEMBERS-FROM-BASE-DEPENDENT: [#Base4#]base4
 }
 
@@ -324,12 +332,12 @@
   void testMethod(Baz* ptr) {
     ptr.m
   }
-  // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:325:10 %s -o - | FileCheck -check-prefix=CHECK-METHOD-DECLARED-VIA-USING %s
-  // CHECK-METHOD-DECLARED-VIA-USING: [#void#]method() (requires fix-it: {325:8-325:9} to "->")
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:333:10 %s -o - | FileCheck -check-prefix=CHECK-METHOD-DECLARED-VIA-USING %s
+  // CHECK-METHOD-DECLARED-VIA-USING: [#void#]method() (requires fix-it: {333:8-333:9} to "->")
 
   void testField(Baz* ptr) {
     ptr.f
   }
-  // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:331:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
-  // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {331:8-331:9} to "->")
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
+  // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
Index: clang/lib/Sema/SemaCodeComplete.cpp
===================================================================
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -5512,11 +5512,16 @@
 // We accept some lossiness (like dropping parameters).
 // We only try to handle common expressions on the LHS of MemberExpr.
 QualType getApproximateType(const Expr *E) {
+  if (E->getType().isNull())
+    return QualType();
+  E = E->IgnoreParenImpCasts();
   QualType Unresolved = E->getType();
-  if (Unresolved.isNull() ||
-      !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent))
-    return Unresolved;
-  E = E->IgnoreParens();
+  // We only resolve DependentTy, or undeduced autos (including auto* etc).
+  if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
+    AutoType *Auto = Unresolved->getContainedAutoType();
+    if (!Auto || !Auto->isUndeducedAutoType())
+      return Unresolved;
+  }
   // 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());
@@ -5579,6 +5584,13 @@
       }
     }
   }
+  // A reference to an `auto` variable: approximate-resolve its initializer.
+  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 Unresolved;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to