summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Sema/Sema.h3
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp13
-rw-r--r--clang/lib/Sema/SemaLookup.cpp46
-rw-r--r--clang/test/CodeCompletion/member-access.cpp80
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
+ }
+};
OpenPOWER on IntegriCloud