Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/include/clang/Sema/HeuristicResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ class HeuristicResolver {
// could look up the name appearing on the RHS.
const QualType getPointeeType(QualType T) const;

// Heuristically resolve a possibly-dependent type `T` to a TagDecl
// in which a member's name can be looked up.
TagDecl *resolveTypeToTagDecl(QualType T) const;

// Simplify the type `Type`.
// `E` is the expression whose type `Type` is, if known. This sometimes
// contains information relevant to the type that's not stored in `Type`
// itself.
// If `UnwrapPointer` is true, exactly only pointer type will be unwrapped
// during simplification, and the operation fails if no pointer type is found.
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);

private:
ASTContext &Ctx;
};
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ class FileNullabilityMap {
/// parameter. This avoids updating the type on hot paths in the parser.
class PreferredTypeBuilder {
public:
PreferredTypeBuilder(bool Enabled) : Enabled(Enabled) {}
PreferredTypeBuilder(ASTContext *Ctx, bool Enabled)
: Ctx(Ctx), Enabled(Enabled) {}

void enterCondition(Sema &S, SourceLocation Tok);
void enterReturn(Sema &S, SourceLocation Tok);
Expand Down Expand Up @@ -336,6 +337,7 @@ class PreferredTypeBuilder {
}

private:
ASTContext *Ctx;
bool Enabled;
/// Start position of a token for which we store expected type.
SourceLocation ExpectedLoc;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
}

Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
: PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions),
Diags(PP.getDiagnostics()), StackHandler(Diags),
: PP(pp),
PreferredType(&actions.getASTContext(), pp.isCodeCompletionEnabled()),
Actions(actions), Diags(PP.getDiagnostics()), StackHandler(Diags),
GreaterThanIsOperator(true), ColonIsSacred(false),
InMessageExpression(false), TemplateParameterDepth(0),
ParsingInObjCContainer(false) {
Expand Down
49 changes: 25 additions & 24 deletions clang/lib/Sema/HeuristicResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class HeuristicResolverImpl {
std::vector<const NamedDecl *>
lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
TagDecl *resolveTypeToTagDecl(QualType T);
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);

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

// Helper function for HeuristicResolver::resolveDependentMember()
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a TagDecl in which we can try name lookup.
TagDecl *resolveTypeToTagDecl(const Type *T);

// Helper function for simplifying a type.
// `Type` is the type to simplify.
// `E` is the expression whose type `Type` is, if known. This sometimes
// contains information relevant to the type that's not stored in `Type`
// itself.
// If `UnwrapPointer` is true, exactly only pointer type will be unwrapped
// during simplification, and the operation fails if no pointer type is found.
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);

bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name);
Expand Down Expand Up @@ -133,8 +121,10 @@ TemplateName getReferencedTemplateName(const Type *T) {
// Helper function for HeuristicResolver::resolveDependentMember()
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a CXXRecordDecl in which we can try name lookup.
TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(const Type *T) {
assert(T);
TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {
const Type *T = QT.getTypePtrOrNull();
if (!T)
return nullptr;

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

if (auto *TT = T->getAs<TagType>()) {
return TT->getDecl();
TagDecl *TD = TT->getDecl();
// Template might not be instantiated yet, fall back to primary template
// in such cases.
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {
if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) {
return CTSD->getSpecializedTemplate()->getTemplatedDecl();
}
}
return TD;
}

if (const auto *ICNT = T->getAs<InjectedClassNameType>())
Expand Down Expand Up @@ -330,8 +328,7 @@ HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {
if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
CalleeType = FnTypePtr->getPointeeType();
if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
if (const auto *D =
resolveTypeToTagDecl(FnType->getReturnType().getTypePtr())) {
if (const auto *D = resolveTypeToTagDecl(FnType->getReturnType())) {
return {D};
}
}
Expand Down Expand Up @@ -442,7 +439,7 @@ bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
DeclarationName Name) {
TagDecl *TD = resolveTypeToTagDecl(Specifier->getType().getTypePtr());
TagDecl *TD = resolveTypeToTagDecl(Specifier->getType());
if (const auto *RD = dyn_cast_if_present<CXXRecordDecl>(TD)) {
return findOrdinaryMember(RD, Path, Name);
}
Expand Down Expand Up @@ -485,10 +482,7 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(
QualType QT, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
const Type *T = QT.getTypePtrOrNull();
if (!T)
return {};
TagDecl *TD = resolveTypeToTagDecl(T);
TagDecl *TD = resolveTypeToTagDecl(QT);
if (!TD)
return {};
if (auto *ED = dyn_cast<EnumDecl>(TD)) {
Expand Down Expand Up @@ -555,5 +549,12 @@ std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
const QualType HeuristicResolver::getPointeeType(QualType T) const {
return HeuristicResolverImpl(Ctx).getPointeeType(T);
}
TagDecl *HeuristicResolver::resolveTypeToTagDecl(QualType T) const {
return HeuristicResolverImpl(Ctx).resolveTypeToTagDecl(T);
}
QualType HeuristicResolver::simplifyType(QualType Type, const Expr *E,
bool UnwrapPointer) {
return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);
}

} // namespace clang
43 changes: 15 additions & 28 deletions clang/lib/Sema/SemaCodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,15 +436,17 @@ void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) {
ExpectedLoc = Tok;
}

static QualType getDesignatedType(QualType BaseType, const Designation &Desig);
static QualType getDesignatedType(QualType BaseType, const Designation &Desig,
HeuristicResolver &Resolver);

void PreferredTypeBuilder::enterDesignatedInitializer(SourceLocation Tok,
QualType BaseType,
const Designation &D) {
if (!Enabled)
return;
ComputeType = nullptr;
Type = getDesignatedType(BaseType, D);
HeuristicResolver Resolver(*Ctx);
Type = getDesignatedType(BaseType, D, Resolver);
ExpectedLoc = Tok;
}

Expand Down Expand Up @@ -5346,27 +5348,11 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
// Returns the RecordDecl inside the BaseType, falling back to primary template
// in case of specializations. Since we might not have a decl for the
// instantiation/specialization yet, e.g. dependent code.
static RecordDecl *getAsRecordDecl(QualType BaseType) {
BaseType = BaseType.getNonReferenceType();
if (auto *RD = BaseType->getAsRecordDecl()) {
if (const auto *CTSD =
llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
// Template might not be instantiated yet, fall back to primary template
// in such cases.
if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared)
RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
}
return RD;
}

if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
if (const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl())) {
return TD->getTemplatedDecl();
}
}

return nullptr;
static RecordDecl *getAsRecordDecl(QualType BaseType,
HeuristicResolver &Resolver) {
BaseType = Resolver.simplifyType(BaseType, nullptr, /*UnwrapPointer=*/false);
return dyn_cast_if_present<RecordDecl>(
Resolver.resolveTypeToTagDecl(BaseType));
}

namespace {
Expand Down Expand Up @@ -5911,7 +5897,7 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
}
}

if (RecordDecl *RD = getAsRecordDecl(BaseType)) {
if (RecordDecl *RD = getAsRecordDecl(BaseType, Resolver)) {
AddRecordMembersCompletionResults(SemaRef, Results, S, BaseType, BaseKind,
RD, std::move(AccessOpFixIt));
} else if (const auto *TTPT =
Expand Down Expand Up @@ -6674,7 +6660,8 @@ QualType SemaCodeCompletion::ProduceTemplateArgumentSignatureHelp(
/*Braced=*/false);
}

static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {
static QualType getDesignatedType(QualType BaseType, const Designation &Desig,
HeuristicResolver &Resolver) {
for (unsigned I = 0; I < Desig.getNumDesignators(); ++I) {
if (BaseType.isNull())
break;
Expand All @@ -6685,7 +6672,7 @@ static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {
NextType = BaseType->getAsArrayTypeUnsafe()->getElementType();
} else {
assert(D.isFieldDesignator());
auto *RD = getAsRecordDecl(BaseType);
auto *RD = getAsRecordDecl(BaseType, Resolver);
if (RD && RD->isCompleteDefinition()) {
for (const auto *Member : RD->lookup(D.getFieldDecl()))
if (const FieldDecl *FD = llvm::dyn_cast<FieldDecl>(Member)) {
Expand All @@ -6701,10 +6688,10 @@ static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {

void SemaCodeCompletion::CodeCompleteDesignator(
QualType BaseType, llvm::ArrayRef<Expr *> InitExprs, const Designation &D) {
BaseType = getDesignatedType(BaseType, D);
BaseType = getDesignatedType(BaseType, D, Resolver);
if (BaseType.isNull())
return;
const auto *RD = getAsRecordDecl(BaseType);
const auto *RD = getAsRecordDecl(BaseType, Resolver);
if (!RD || RD->fields().empty())
return;

Expand Down
6 changes: 4 additions & 2 deletions clang/test/CodeCompletion/member-access.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,9 @@ using Alias = S<T>;
template <typename T>
void f(Alias<T> s) {
s.a.b;
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:433:7 %s -o - | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS %s
// CHECK-TEMPLATE-ALIAS: [#int#]b
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:433:5 %s -o - | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS %s
// CHECK-TEMPLATE-ALIAS: [#A#]a
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:433:7 %s -o - | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS-NESTED %s
// CHECK-TEMPLATE-ALIAS-NESTED: [#int#]b
}
}