r302797 - [CodeCompletion] Provide member completions for dependent expressions whose

Alex Lorenz via cfe-commits cfe-commits at lists.llvm.org
Thu May 11 06:48:57 PDT 2017


Author: arphaman
Date: Thu May 11 08:48:57 2017
New Revision: 302797

URL: http://llvm.org/viewvc/llvm-project?rev=302797&view=rev
Log:
[CodeCompletion] Provide member completions for dependent expressions whose
type is a TemplateSpecializationType or InjectedClassNameType

Fixes PR30847. Partially fixes PR20973 (first position only).

PR17614 is still not working, its expression has the dependent
builtin type. We'll have to teach the completion engine how to "resolve"
dependent expressions to fix it.

rdar://29818301

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/CodeCompletion/member-access.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=302797&r1=302796&r2=302797&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu May 11 08:48:57 2017
@@ -3068,7 +3068,8 @@ public:
                           bool IncludeGlobalScope = true);
   void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
                           VisibleDeclConsumer &Consumer,
-                          bool IncludeGlobalScope = true);
+                          bool IncludeGlobalScope = true,
+                          bool IncludeDependentBases = false);
 
   enum CorrectTypoKind {
     CTK_NonError,     // CorrectTypo used in a non error recovery situation.

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=302797&r1=302796&r2=302797&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu May 11 08:48:57 2017
@@ -3881,7 +3881,8 @@ static void AddRecordMembersCompletionRe
   Results.allowNestedNameSpecifiers();
   CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);
   SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer,
-                             SemaRef.CodeCompleter->includeGlobals());
+                             SemaRef.CodeCompleter->includeGlobals(),
+                             /*IncludeDependentBases=*/true);
 
   if (SemaRef.getLangOpts().CPlusPlus) {
     if (!Results.empty()) {
@@ -3949,6 +3950,16 @@ void Sema::CodeCompleteMemberReferenceEx
   if (const RecordType *Record = BaseType->getAs<RecordType>()) {
     AddRecordMembersCompletionResults(*this, Results, S, BaseType,
                                       Record->getDecl());
+  } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
+    TemplateName TN = TST->getTemplateName();
+    if (const auto *TD =
+            dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) {
+      CXXRecordDecl *RD = TD->getTemplatedDecl();
+      AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
+    }
+  } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) {
+    if (auto *RD = ICNT->getDecl())
+      AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
   } else if (!IsArrow && BaseType->isObjCObjectPointerType()) {
     // Objective-C property reference.
     AddedPropertiesSet AddedProperties;

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=302797&r1=302796&r2=302797&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu May 11 08:48:57 2017
@@ -3445,7 +3445,8 @@ static void LookupVisibleDecls(DeclConte
                                bool QualifiedNameLookup,
                                bool InBaseClass,
                                VisibleDeclConsumer &Consumer,
-                               VisibleDeclsRecord &Visited) {
+                               VisibleDeclsRecord &Visited,
+                               bool IncludeDependentBases = false) {
   if (!Ctx)
     return;
 
@@ -3501,7 +3502,8 @@ static void LookupVisibleDecls(DeclConte
     ShadowContextRAII Shadow(Visited);
     for (auto I : Ctx->using_directives()) {
       LookupVisibleDecls(I->getNominatedNamespace(), Result,
-                         QualifiedNameLookup, InBaseClass, Consumer, Visited);
+                         QualifiedNameLookup, InBaseClass, Consumer, Visited,
+                         IncludeDependentBases);
     }
   }
 
@@ -3513,14 +3515,28 @@ static void LookupVisibleDecls(DeclConte
     for (const auto &B : Record->bases()) {
       QualType BaseType = B.getType();
 
-      // Don't look into dependent bases, because name lookup can't look
-      // there anyway.
-      if (BaseType->isDependentType())
-        continue;
-
-      const RecordType *Record = BaseType->getAs<RecordType>();
-      if (!Record)
-        continue;
+      RecordDecl *RD;
+      if (BaseType->isDependentType()) {
+        if (!IncludeDependentBases) {
+          // Don't look into dependent bases, because name lookup can't look
+          // there anyway.
+          continue;
+        }
+        const auto *TST = BaseType->getAs<TemplateSpecializationType>();
+        if (!TST)
+          continue;
+        TemplateName TN = TST->getTemplateName();
+        const auto *TD =
+            dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+        if (!TD)
+          continue;
+        RD = TD->getTemplatedDecl();
+      } else {
+        const auto *Record = BaseType->getAs<RecordType>();
+        if (!Record)
+          continue;
+        RD = Record->getDecl();
+      }
 
       // FIXME: It would be nice to be able to determine whether referencing
       // a particular member would be ambiguous. For example, given
@@ -3543,8 +3559,8 @@ static void LookupVisibleDecls(DeclConte
 
       // Find results in this base class (and its bases).
       ShadowContextRAII Shadow(Visited);
-      LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
-                         true, Consumer, Visited);
+      LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer,
+                         Visited, IncludeDependentBases);
     }
   }
 
@@ -3713,7 +3729,8 @@ void Sema::LookupVisibleDecls(Scope *S,
 
 void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
                               VisibleDeclConsumer &Consumer,
-                              bool IncludeGlobalScope) {
+                              bool IncludeGlobalScope,
+                              bool IncludeDependentBases) {
   LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
   Result.setAllowHidden(Consumer.includeHiddenDecls());
   VisibleDeclsRecord Visited;
@@ -3721,7 +3738,8 @@ void Sema::LookupVisibleDecls(DeclContex
     Visited.visitedContext(Context.getTranslationUnitDecl());
   ShadowContextRAII Shadow(Visited);
   ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
-                       /*InBaseClass=*/false, Consumer, Visited);
+                       /*InBaseClass=*/false, Consumer, Visited,
+                       IncludeDependentBases);
 }
 
 /// LookupOrCreateLabel - Do a name lookup of a label with the specified name.

Modified: cfe/trunk/test/CodeCompletion/member-access.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/member-access.cpp?rev=302797&r1=302796&r2=302797&view=diff
==============================================================================
--- cfe/trunk/test/CodeCompletion/member-access.cpp (original)
+++ cfe/trunk/test/CodeCompletion/member-access.cpp Thu May 11 08:48:57 2017
@@ -66,3 +66,83 @@ struct Bar {
 
 // Make sure this also doesn't crash
 // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:47:14 %s
+
+
+template<typename T>
+class BaseTemplate {
+public:
+  T baseTemplateFunction();
+
+  T baseTemplateField;
+};
+
+template<typename T, typename S>
+class TemplateClass: public Base1 , public BaseTemplate<T> {
+public:
+  T function() { }
+  T field;
+
+  void overload1(const T &);
+  void overload1(const S &);
+};
+
+template<typename T, typename S>
+void completeDependentMembers(TemplateClass<T, S> &object,
+                              TemplateClass<int, S> *object2) {
+  object.field;
+  object2->field;
+// CHECK-CC2: baseTemplateField : [#T#][#BaseTemplate<T>::#]baseTemplateField
+// CHECK-CC2: baseTemplateFunction : [#T#][#BaseTemplate<T>::#]baseTemplateFunction()
+// CHECK-CC2: field : [#T#]field
+// CHECK-CC2: function : [#T#]function()
+// CHECK-CC2: member1 : [#int#][#Base1::#]member1
+// CHECK-CC2: member2 : [#float#][#Base1::#]member2
+// CHECK-CC2: overload1 : [#void#]overload1(<#const T &#>)
+// CHECK-CC2: overload1 : [#void#]overload1(<#const S &#>)
+
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:92:10 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:93:12 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+}
+
+
+void completeDependentSpecializedMembers(TemplateClass<int, double> &object,
+                                         TemplateClass<int, double> *object2) {
+  object.field;
+  object2->field;
+// CHECK-CC3: baseTemplateField : [#int#][#BaseTemplate<int>::#]baseTemplateField
+// CHECK-CC3: baseTemplateFunction : [#int#][#BaseTemplate<int>::#]baseTemplateFunction()
+// CHECK-CC3: field : [#int#]field
+// CHECK-CC3: function : [#int#]function()
+// CHECK-CC3: member1 : [#int#][#Base1::#]member1
+// CHECK-CC3: member2 : [#float#][#Base1::#]member2
+// CHECK-CC3: overload1 : [#void#]overload1(<#const int &#>)
+// CHECK-CC3: overload1 : [#void#]overload1(<#const double &#>)
+
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:110:10 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:111:12 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+}
+
+template <typename T>
+class Template {
+public:
+  BaseTemplate<int> o1;
+  BaseTemplate<T> o2;
+
+  void function() {
+    o1.baseTemplateField;
+// CHECK-CC4: BaseTemplate : BaseTemplate::
+// CHECK-CC4: baseTemplateField : [#int#]baseTemplateField
+// CHECK-CC4: baseTemplateFunction : [#int#]baseTemplateFunction()
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:132: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:137: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:142:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
+  }
+};




More information about the cfe-commits mailing list