Skip to content

Commit 715ad67

Browse files
[clang][CodeComplete] Use HeuristicResolver in getAsRecordDecl() (#130473)
Fixes #130468
1 parent eccd7aa commit 715ad67

File tree

6 files changed

+62
-57
lines changed

6 files changed

+62
-57
lines changed

clang/include/clang/Sema/HeuristicResolver.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ class HeuristicResolver {
8181
// could look up the name appearing on the RHS.
8282
const QualType getPointeeType(QualType T) const;
8383

84+
// Heuristically resolve a possibly-dependent type `T` to a TagDecl
85+
// in which a member's name can be looked up.
86+
TagDecl *resolveTypeToTagDecl(QualType T) const;
87+
88+
// Simplify the type `Type`.
89+
// `E` is the expression whose type `Type` is, if known. This sometimes
90+
// contains information relevant to the type that's not stored in `Type`
91+
// itself.
92+
// If `UnwrapPointer` is true, exactly only pointer type will be unwrapped
93+
// during simplification, and the operation fails if no pointer type is found.
94+
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);
95+
8496
private:
8597
ASTContext &Ctx;
8698
};

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ class FileNullabilityMap {
291291
/// parameter. This avoids updating the type on hot paths in the parser.
292292
class PreferredTypeBuilder {
293293
public:
294-
PreferredTypeBuilder(bool Enabled) : Enabled(Enabled) {}
294+
PreferredTypeBuilder(ASTContext *Ctx, bool Enabled)
295+
: Ctx(Ctx), Enabled(Enabled) {}
295296

296297
void enterCondition(Sema &S, SourceLocation Tok);
297298
void enterReturn(Sema &S, SourceLocation Tok);
@@ -337,6 +338,7 @@ class PreferredTypeBuilder {
337338
}
338339

339340
private:
341+
ASTContext *Ctx;
340342
bool Enabled;
341343
/// Start position of a token for which we store expected type.
342344
SourceLocation ExpectedLoc;

clang/lib/Parse/Parser.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
5454
}
5555

5656
Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
57-
: PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions),
58-
Diags(PP.getDiagnostics()), StackHandler(Diags),
57+
: PP(pp),
58+
PreferredType(&actions.getASTContext(), pp.isCodeCompletionEnabled()),
59+
Actions(actions), Diags(PP.getDiagnostics()), StackHandler(Diags),
5960
GreaterThanIsOperator(true), ColonIsSacred(false),
6061
InMessageExpression(false), TemplateParameterDepth(0),
6162
ParsingInObjCContainer(false) {

clang/lib/Sema/HeuristicResolver.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class HeuristicResolverImpl {
4848
std::vector<const NamedDecl *>
4949
lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,
5050
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
51+
TagDecl *resolveTypeToTagDecl(QualType T);
52+
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);
5153

5254
private:
5355
ASTContext &Ctx;
@@ -73,20 +75,6 @@ class HeuristicResolverImpl {
7375
QualType resolveExprToType(const Expr *E);
7476
std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);
7577

76-
// Helper function for HeuristicResolver::resolveDependentMember()
77-
// which takes a possibly-dependent type `T` and heuristically
78-
// resolves it to a TagDecl in which we can try name lookup.
79-
TagDecl *resolveTypeToTagDecl(const Type *T);
80-
81-
// Helper function for simplifying a type.
82-
// `Type` is the type to simplify.
83-
// `E` is the expression whose type `Type` is, if known. This sometimes
84-
// contains information relevant to the type that's not stored in `Type`
85-
// itself.
86-
// If `UnwrapPointer` is true, exactly only pointer type will be unwrapped
87-
// during simplification, and the operation fails if no pointer type is found.
88-
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);
89-
9078
bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
9179
CXXBasePath &Path,
9280
DeclarationName Name);
@@ -133,8 +121,10 @@ TemplateName getReferencedTemplateName(const Type *T) {
133121
// Helper function for HeuristicResolver::resolveDependentMember()
134122
// which takes a possibly-dependent type `T` and heuristically
135123
// resolves it to a CXXRecordDecl in which we can try name lookup.
136-
TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(const Type *T) {
137-
assert(T);
124+
TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {
125+
const Type *T = QT.getTypePtrOrNull();
126+
if (!T)
127+
return nullptr;
138128

139129
// Unwrap type sugar such as type aliases.
140130
T = T->getCanonicalTypeInternal().getTypePtr();
@@ -148,7 +138,15 @@ TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(const Type *T) {
148138
}
149139

150140
if (auto *TT = T->getAs<TagType>()) {
151-
return TT->getDecl();
141+
TagDecl *TD = TT->getDecl();
142+
// Template might not be instantiated yet, fall back to primary template
143+
// in such cases.
144+
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {
145+
if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) {
146+
return CTSD->getSpecializedTemplate()->getTemplatedDecl();
147+
}
148+
}
149+
return TD;
152150
}
153151

154152
if (const auto *ICNT = T->getAs<InjectedClassNameType>())
@@ -330,8 +328,7 @@ HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {
330328
if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
331329
CalleeType = FnTypePtr->getPointeeType();
332330
if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
333-
if (const auto *D =
334-
resolveTypeToTagDecl(FnType->getReturnType().getTypePtr())) {
331+
if (const auto *D = resolveTypeToTagDecl(FnType->getReturnType())) {
335332
return {D};
336333
}
337334
}
@@ -442,7 +439,7 @@ bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
442439
bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(
443440
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
444441
DeclarationName Name) {
445-
TagDecl *TD = resolveTypeToTagDecl(Specifier->getType().getTypePtr());
442+
TagDecl *TD = resolveTypeToTagDecl(Specifier->getType());
446443
if (const auto *RD = dyn_cast_if_present<CXXRecordDecl>(TD)) {
447444
return findOrdinaryMember(RD, Path, Name);
448445
}
@@ -485,10 +482,7 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(
485482
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(
486483
QualType QT, DeclarationName Name,
487484
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
488-
const Type *T = QT.getTypePtrOrNull();
489-
if (!T)
490-
return {};
491-
TagDecl *TD = resolveTypeToTagDecl(T);
485+
TagDecl *TD = resolveTypeToTagDecl(QT);
492486
if (!TD)
493487
return {};
494488
if (auto *ED = dyn_cast<EnumDecl>(TD)) {
@@ -555,5 +549,12 @@ std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
555549
const QualType HeuristicResolver::getPointeeType(QualType T) const {
556550
return HeuristicResolverImpl(Ctx).getPointeeType(T);
557551
}
552+
TagDecl *HeuristicResolver::resolveTypeToTagDecl(QualType T) const {
553+
return HeuristicResolverImpl(Ctx).resolveTypeToTagDecl(T);
554+
}
555+
QualType HeuristicResolver::simplifyType(QualType Type, const Expr *E,
556+
bool UnwrapPointer) {
557+
return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);
558+
}
558559

559560
} // namespace clang

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -436,15 +436,17 @@ void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) {
436436
ExpectedLoc = Tok;
437437
}
438438

439-
static QualType getDesignatedType(QualType BaseType, const Designation &Desig);
439+
static QualType getDesignatedType(QualType BaseType, const Designation &Desig,
440+
HeuristicResolver &Resolver);
440441

441442
void PreferredTypeBuilder::enterDesignatedInitializer(SourceLocation Tok,
442443
QualType BaseType,
443444
const Designation &D) {
444445
if (!Enabled)
445446
return;
446447
ComputeType = nullptr;
447-
Type = getDesignatedType(BaseType, D);
448+
HeuristicResolver Resolver(*Ctx);
449+
Type = getDesignatedType(BaseType, D, Resolver);
448450
ExpectedLoc = Tok;
449451
}
450452

@@ -5346,27 +5348,11 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
53465348
// Returns the RecordDecl inside the BaseType, falling back to primary template
53475349
// in case of specializations. Since we might not have a decl for the
53485350
// instantiation/specialization yet, e.g. dependent code.
5349-
static RecordDecl *getAsRecordDecl(QualType BaseType) {
5350-
BaseType = BaseType.getNonReferenceType();
5351-
if (auto *RD = BaseType->getAsRecordDecl()) {
5352-
if (const auto *CTSD =
5353-
llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
5354-
// Template might not be instantiated yet, fall back to primary template
5355-
// in such cases.
5356-
if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared)
5357-
RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
5358-
}
5359-
return RD;
5360-
}
5361-
5362-
if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
5363-
if (const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(
5364-
TST->getTemplateName().getAsTemplateDecl())) {
5365-
return TD->getTemplatedDecl();
5366-
}
5367-
}
5368-
5369-
return nullptr;
5351+
static RecordDecl *getAsRecordDecl(QualType BaseType,
5352+
HeuristicResolver &Resolver) {
5353+
BaseType = Resolver.simplifyType(BaseType, nullptr, /*UnwrapPointer=*/false);
5354+
return dyn_cast_if_present<RecordDecl>(
5355+
Resolver.resolveTypeToTagDecl(BaseType));
53705356
}
53715357

53725358
namespace {
@@ -5912,7 +5898,7 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
59125898
}
59135899
}
59145900

5915-
if (RecordDecl *RD = getAsRecordDecl(BaseType)) {
5901+
if (RecordDecl *RD = getAsRecordDecl(BaseType, Resolver)) {
59165902
AddRecordMembersCompletionResults(SemaRef, Results, S, BaseType, BaseKind,
59175903
RD, std::move(AccessOpFixIt));
59185904
} else if (const auto *TTPT =
@@ -6675,7 +6661,8 @@ QualType SemaCodeCompletion::ProduceTemplateArgumentSignatureHelp(
66756661
/*Braced=*/false);
66766662
}
66776663

6678-
static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {
6664+
static QualType getDesignatedType(QualType BaseType, const Designation &Desig,
6665+
HeuristicResolver &Resolver) {
66796666
for (unsigned I = 0; I < Desig.getNumDesignators(); ++I) {
66806667
if (BaseType.isNull())
66816668
break;
@@ -6686,7 +6673,7 @@ static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {
66866673
NextType = BaseType->getAsArrayTypeUnsafe()->getElementType();
66876674
} else {
66886675
assert(D.isFieldDesignator());
6689-
auto *RD = getAsRecordDecl(BaseType);
6676+
auto *RD = getAsRecordDecl(BaseType, Resolver);
66906677
if (RD && RD->isCompleteDefinition()) {
66916678
for (const auto *Member : RD->lookup(D.getFieldDecl()))
66926679
if (const FieldDecl *FD = llvm::dyn_cast<FieldDecl>(Member)) {
@@ -6702,10 +6689,10 @@ static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {
67026689

67036690
void SemaCodeCompletion::CodeCompleteDesignator(
67046691
QualType BaseType, llvm::ArrayRef<Expr *> InitExprs, const Designation &D) {
6705-
BaseType = getDesignatedType(BaseType, D);
6692+
BaseType = getDesignatedType(BaseType, D, Resolver);
67066693
if (BaseType.isNull())
67076694
return;
6708-
const auto *RD = getAsRecordDecl(BaseType);
6695+
const auto *RD = getAsRecordDecl(BaseType, Resolver);
67096696
if (!RD || RD->fields().empty())
67106697
return;
67116698

clang/test/CodeCompletion/member-access.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,9 @@ using Alias = S<T>;
431431
template <typename T>
432432
void f(Alias<T> s) {
433433
s.a.b;
434-
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:433:7 %s -o - | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS %s
435-
// CHECK-TEMPLATE-ALIAS: [#int#]b
434+
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:433:5 %s -o - | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS %s
435+
// CHECK-TEMPLATE-ALIAS: [#A#]a
436+
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:433:7 %s -o - | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS-NESTED %s
437+
// CHECK-TEMPLATE-ALIAS-NESTED: [#int#]b
436438
}
437439
}

0 commit comments

Comments
 (0)