diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 46 | ||||
-rw-r--r-- | clang/test/CodeCompletion/member-access.cpp | 80 |
4 files changed, 126 insertions, 16 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0f8e2a02518..7b4ccddd7fc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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. diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index eec01b0c892..8fb2f413923 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -3881,7 +3881,8 @@ static void AddRecordMembersCompletionResults(Sema &SemaRef, 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::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, 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; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index ce76e14982d..6a3b0179839 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3445,7 +3445,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, bool InBaseClass, VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited) { + VisibleDeclsRecord &Visited, + bool IncludeDependentBases = false) { if (!Ctx) return; @@ -3501,7 +3502,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, 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(DeclContext *Ctx, LookupResult &Result, 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(DeclContext *Ctx, LookupResult &Result, // 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, LookupNameKind Kind, 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(DeclContext *Ctx, LookupNameKind Kind, 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. diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp index 66872272ee6..53af121951b 100644 --- a/clang/test/CodeCompletion/member-access.cpp +++ b/clang/test/CodeCompletion/member-access.cpp @@ -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 + } +}; |