https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/130473
Fixes https://github.com/llvm/llvm-project/issues/130468 >From 0999f2fb15b6703fc9f5c4ba5c9e21c14a90b4ed Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Sun, 9 Mar 2025 01:36:25 -0500 Subject: [PATCH 1/4] Change the parameter type of resolveTypeToTagDecl() to QualType --- clang/lib/Sema/HeuristicResolver.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 7aecd2a73b539..3c7918165ee42 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -75,7 +75,7 @@ class HeuristicResolverImpl { // 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); + TagDecl *resolveTypeToTagDecl(QualType T); // Helper function for simplifying a type. // `Type` is the type to simplify. @@ -132,8 +132,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(); @@ -315,8 +317,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}; } } @@ -427,7 +428,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); } @@ -470,10 +471,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)) { >From a3c77212039245d9f4704567fd426f36a29e947f Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Sun, 9 Mar 2025 01:43:25 -0500 Subject: [PATCH 2/4] Expose resolveTypeToTagDecl() publically in HeuristicResolver --- clang/include/clang/Sema/HeuristicResolver.h | 4 ++++ clang/lib/Sema/HeuristicResolver.cpp | 9 ++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Sema/HeuristicResolver.h b/clang/include/clang/Sema/HeuristicResolver.h index f511815b40199..c971b9a6a7b51 100644 --- a/clang/include/clang/Sema/HeuristicResolver.h +++ b/clang/include/clang/Sema/HeuristicResolver.h @@ -81,6 +81,10 @@ 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; + private: ASTContext &Ctx; }; diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 3c7918165ee42..11fe786fa91c6 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -47,6 +47,7 @@ class HeuristicResolverImpl { std::vector<const NamedDecl *> lookupDependentName(CXXRecordDecl *RD, DeclarationName Name, llvm::function_ref<bool(const NamedDecl *ND)> Filter); + TagDecl *resolveTypeToTagDecl(QualType T); private: ASTContext &Ctx; @@ -72,11 +73,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(QualType 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 @@ -538,5 +534,8 @@ 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); +} } // namespace clang >From c3d034150f2ed4a917fc46f8095137efe1f4efc1 Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Sun, 9 Mar 2025 03:08:18 -0400 Subject: [PATCH 3/4] Plumb a HeuristicResolver parameter into getAsRecordDec() --- clang/include/clang/Sema/Sema.h | 4 +++- clang/lib/Parse/Parser.cpp | 5 +++-- clang/lib/Sema/SemaCodeComplete.cpp | 20 ++++++++++++-------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fdef57e84ee3d..89ce852b0a09f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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); @@ -336,6 +337,7 @@ class PreferredTypeBuilder { } private: + ASTContext *Ctx; bool Enabled; /// Start position of a token for which we store expected type. SourceLocation ExpectedLoc; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 0710542f5e938..09e784a8e04de 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -52,8 +52,9 @@ IdentifierInfo *Parser::getSEHExceptKeyword() { } Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) - : PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions), - Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), + : PP(pp), + PreferredType(&actions.getASTContext(), pp.isCodeCompletionEnabled()), + Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), TemplateParameterDepth(0), ParsingInObjCContainer(false) { SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index db467d76b5d32..37c2fefd6489b 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -436,7 +436,8 @@ 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, @@ -444,7 +445,8 @@ void PreferredTypeBuilder::enterDesignatedInitializer(SourceLocation Tok, if (!Enabled) return; ComputeType = nullptr; - Type = getDesignatedType(BaseType, D); + HeuristicResolver Resolver(*Ctx); + Type = getDesignatedType(BaseType, D, Resolver); ExpectedLoc = Tok; } @@ -5346,7 +5348,8 @@ 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) { +static RecordDecl *getAsRecordDecl(QualType BaseType, + HeuristicResolver &Resolver) { BaseType = BaseType.getNonReferenceType(); if (auto *RD = BaseType->getAsRecordDecl()) { if (const auto *CTSD = @@ -5911,7 +5914,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 = @@ -6674,7 +6677,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; @@ -6685,7 +6689,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)) { @@ -6701,10 +6705,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; >From 19bbad8a4e10841abc988b8394318853196a7f0c Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Sun, 9 Mar 2025 03:08:54 -0400 Subject: [PATCH 4/4] Reimplement getAsRecordDecl() using HeuristicResolver --- clang/lib/Sema/SemaCodeComplete.cpp | 22 ++------------------- clang/test/CodeCompletion/member-access.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 37c2fefd6489b..4b62625751a8f 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5350,26 +5350,8 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, // instantiation/specialization yet, e.g. dependent code. static RecordDecl *getAsRecordDecl(QualType BaseType, HeuristicResolver &Resolver) { - 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; + return dyn_cast_if_present<RecordDecl>( + Resolver.resolveTypeToTagDecl(BaseType)); } namespace { diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp index b181466cdb628..8526ed7273474 100644 --- a/clang/test/CodeCompletion/member-access.cpp +++ b/clang/test/CodeCompletion/member-access.cpp @@ -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 } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits