https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/123551
Fixes https://github.com/llvm/llvm-project/issues/123549 >From cd87f05f19f245e24f5c29b97af0b69266608d7a Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Mon, 20 Jan 2025 01:52:24 -0500 Subject: [PATCH 1/2] Upgrade HeuristicResolver to use QualType rather than Type* --- clang-tools-extra/clangd/FindTarget.cpp | 3 +- clang-tools-extra/clangd/XRefs.cpp | 7 +- clang/include/clang/Sema/HeuristicResolver.h | 4 +- clang/lib/Sema/HeuristicResolver.cpp | 77 ++++++++++---------- 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index 04fd6d437b7bdd..bb4c91b8313540 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -496,8 +496,7 @@ struct TargetFinder { return; case NestedNameSpecifier::Identifier: if (Resolver) { - add(QualType(Resolver->resolveNestedNameSpecifierToType(NNS), 0), - Flags); + add(Resolver->resolveNestedNameSpecifierToType(NNS), Flags); } return; case NestedNameSpecifier::TypeSpec: diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 0a093108b752c3..1a23f6cca77561 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -2034,9 +2034,10 @@ static void unwrapFindType( // For smart pointer types, add the underlying type if (H) - if (const auto* PointeeType = H->getPointeeType(T.getNonReferenceType().getTypePtr())) { - unwrapFindType(QualType(PointeeType, 0), H, Out); - return Out.push_back(T); + if (auto PointeeType = H->getPointeeType(T.getNonReferenceType()); + !PointeeType.isNull()) { + unwrapFindType(PointeeType, H, Out); + return Out.push_back(T); } return Out.push_back(T); diff --git a/clang/include/clang/Sema/HeuristicResolver.h b/clang/include/clang/Sema/HeuristicResolver.h index 947de7a4e83ce0..3760003aab89f1 100644 --- a/clang/include/clang/Sema/HeuristicResolver.h +++ b/clang/include/clang/Sema/HeuristicResolver.h @@ -66,13 +66,13 @@ class HeuristicResolver { // Try to heuristically resolve a dependent nested name specifier // to the type it likely denotes. Note that *dependent* name specifiers always // denote types, not namespaces. - const Type * + QualType resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const; // Given the type T of a dependent expression that appears of the LHS of a // "->", heuristically find a corresponding pointee type in whose scope we // could look up the name appearing on the RHS. - const Type *getPointeeType(const Type *T) const; + const QualType getPointeeType(QualType T) const; private: ASTContext &Ctx; diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 7c1b8450b96330..f883b85a80c60f 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -42,8 +42,8 @@ class HeuristicResolverImpl { resolveDependentNameType(const DependentNameType *DNT); std::vector<const NamedDecl *> resolveTemplateSpecializationType( const DependentTemplateSpecializationType *DTST); - const Type *resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS); - const Type *getPointeeType(const Type *T); + QualType resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS); + QualType getPointeeType(QualType T); private: ASTContext &Ctx; @@ -61,12 +61,12 @@ class HeuristicResolverImpl { // This heuristic will give the desired answer in many cases, e.g. // for a call to vector<T>::size(). std::vector<const NamedDecl *> - resolveDependentMember(const Type *T, DeclarationName Name, + resolveDependentMember(QualType T, DeclarationName Name, llvm::function_ref<bool(const NamedDecl *ND)> Filter); // Try to heuristically resolve the type of a possibly-dependent expression // `E`. - const Type *resolveExprToType(const Expr *E); + QualType resolveExprToType(const Expr *E); std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E); // Helper function for HeuristicResolver::resolveDependentMember() @@ -104,17 +104,17 @@ const auto TemplateFilter = [](const NamedDecl *D) { return isa<TemplateDecl>(D); }; -const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls, - ASTContext &Ctx) { +QualType resolveDeclsToType(const std::vector<const NamedDecl *> &Decls, + ASTContext &Ctx) { if (Decls.size() != 1) // Names an overload set -- just bail. - return nullptr; + return QualType(); if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) { - return Ctx.getTypeDeclType(TD).getTypePtr(); + return Ctx.getTypeDeclType(TD); } if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) { - return VD->getType().getTypePtrOrNull(); + return VD->getType(); } - return nullptr; + return QualType(); } TemplateName getReferencedTemplateName(const Type *T) { @@ -137,7 +137,8 @@ CXXRecordDecl *HeuristicResolverImpl::resolveTypeToRecordDecl(const Type *T) { T = T->getCanonicalTypeInternal().getTypePtr(); if (const auto *DNT = T->getAs<DependentNameType>()) { - T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx); + T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx) + .getTypePtrOrNull(); if (!T) return nullptr; T = T->getCanonicalTypeInternal().getTypePtr(); @@ -163,12 +164,12 @@ CXXRecordDecl *HeuristicResolverImpl::resolveTypeToRecordDecl(const Type *T) { return TD->getTemplatedDecl(); } -const Type *HeuristicResolverImpl::getPointeeType(const Type *T) { - if (!T) - return nullptr; +QualType HeuristicResolverImpl::getPointeeType(QualType T) { + if (T.isNull()) + return QualType(); if (T->isPointerType()) - return T->castAs<PointerType>()->getPointeeType().getTypePtrOrNull(); + return T->castAs<PointerType>()->getPointeeType(); // Try to handle smart pointer types. @@ -177,7 +178,7 @@ const Type *HeuristicResolverImpl::getPointeeType(const Type *T) { auto ArrowOps = resolveDependentMember( T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter); if (ArrowOps.empty()) - return nullptr; + return QualType(); // Getting the return type of the found operator-> method decl isn't useful, // because we discarded template arguments to perform lookup in the primary @@ -187,13 +188,13 @@ const Type *HeuristicResolverImpl::getPointeeType(const Type *T) { // form of SmartPtr<X, ...>, and assume X is the pointee type. auto *TST = T->getAs<TemplateSpecializationType>(); if (!TST) - return nullptr; + return QualType(); if (TST->template_arguments().size() == 0) - return nullptr; + return QualType(); const TemplateArgument &FirstArg = TST->template_arguments()[0]; if (FirstArg.getKind() != TemplateArgument::Type) - return nullptr; - return FirstArg.getAsType().getTypePtrOrNull(); + return QualType(); + return FirstArg.getAsType(); } std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( @@ -210,7 +211,8 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( // with `this` as the base expression as `X` as the qualifier // (which could be valid if `X` names a base class after instantiation). if (NestedNameSpecifier *NNS = ME->getQualifier()) { - if (const Type *QualifierType = resolveNestedNameSpecifierToType(NNS)) { + if (QualType QualifierType = resolveNestedNameSpecifierToType(NNS); + !QualifierType.isNull()) { auto Decls = resolveDependentMember(QualifierType, ME->getMember(), NoFilter); if (!Decls.empty()) @@ -225,11 +227,11 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( } // Try resolving the member inside the expression's base type. - const Type *BaseType = ME->getBaseType().getTypePtrOrNull(); + QualType BaseType = ME->getBaseType(); if (ME->isArrow()) { BaseType = getPointeeType(BaseType); } - if (!BaseType) + if (BaseType.isNull()) return {}; if (const auto *BT = BaseType->getAs<BuiltinType>()) { // If BaseType is the type of a dependent expression, it's just @@ -245,17 +247,17 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) { - return resolveDependentMember(RE->getQualifier()->getAsType(), + return resolveDependentMember(QualType(RE->getQualifier()->getAsType(), 0), RE->getDeclName(), StaticFilter); } std::vector<const NamedDecl *> HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) { - const auto *CalleeType = resolveExprToType(CE->getCallee()); - if (!CalleeType) + QualType CalleeType = resolveExprToType(CE->getCallee()); + if (CalleeType.isNull()) return {}; if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) - CalleeType = FnTypePtr->getPointeeType().getTypePtr(); + CalleeType = FnTypePtr->getPointeeType(); if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) { if (const auto *D = resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) { @@ -276,7 +278,7 @@ HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) { std::vector<const NamedDecl *> HeuristicResolverImpl::resolveUsingValueDecl( const UnresolvedUsingValueDecl *UUVD) { - return resolveDependentMember(UUVD->getQualifier()->getAsType(), + return resolveDependentMember(QualType(UUVD->getQualifier()->getAsType(), 0), UUVD->getNameInfo().getName(), ValueFilter); } @@ -317,18 +319,18 @@ HeuristicResolverImpl::resolveExprToDecls(const Expr *E) { return {}; } -const Type *HeuristicResolverImpl::resolveExprToType(const Expr *E) { +QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) { std::vector<const NamedDecl *> Decls = resolveExprToDecls(E); if (!Decls.empty()) return resolveDeclsToType(Decls, Ctx); - return E->getType().getTypePtr(); + return E->getType(); } -const Type *HeuristicResolverImpl::resolveNestedNameSpecifierToType( +QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType( const NestedNameSpecifier *NNS) { if (!NNS) - return nullptr; + return QualType(); // The purpose of this function is to handle the dependent (Kind == // Identifier) case, but we need to recurse on the prefix because @@ -337,7 +339,7 @@ const Type *HeuristicResolverImpl::resolveNestedNameSpecifierToType( switch (NNS->getKind()) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: - return NNS->getAsType(); + return QualType(NNS->getAsType(), 0); case NestedNameSpecifier::Identifier: { return resolveDeclsToType( resolveDependentMember( @@ -348,7 +350,7 @@ const Type *HeuristicResolverImpl::resolveNestedNameSpecifierToType( default: break; } - return nullptr; + return QualType(); } bool isOrdinaryMember(const NamedDecl *ND) { @@ -410,8 +412,9 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName( } std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember( - const Type *T, DeclarationName Name, + QualType QT, DeclarationName Name, llvm::function_ref<bool(const NamedDecl *ND)> Filter) { + const Type *T = QT.getTypePtrOrNull(); if (!T) return {}; if (auto *ET = T->getAs<EnumType>()) { @@ -457,11 +460,11 @@ HeuristicResolver::resolveTemplateSpecializationType( const DependentTemplateSpecializationType *DTST) const { return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(DTST); } -const Type *HeuristicResolver::resolveNestedNameSpecifierToType( +QualType HeuristicResolver::resolveNestedNameSpecifierToType( const NestedNameSpecifier *NNS) const { return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS); } -const Type *HeuristicResolver::getPointeeType(const Type *T) const { +const QualType HeuristicResolver::getPointeeType(QualType T) const { return HeuristicResolverImpl(Ctx).getPointeeType(T); } >From c623e7eacb48788b33977caf68c07f6e9230f1a2 Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Mon, 20 Jan 2025 01:57:42 -0500 Subject: [PATCH 2/2] Respect const-qualification on methods in resolveDependentMember() --- clang/lib/Sema/HeuristicResolver.cpp | 10 +++++++++- .../unittests/Sema/HeuristicResolverTest.cpp | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index f883b85a80c60f..fbce1a026be61c 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -425,7 +425,15 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember( if (!RD->hasDefinition()) return {}; RD = RD->getDefinition(); - return lookupDependentName(RD, Name, Filter); + return lookupDependentName(RD, Name, [&](const NamedDecl *ND) { + if (!Filter(ND)) + return false; + if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) { + if (QT.isConstQualified() && !MD->isConst()) + return false; + } + return true; + }); } return {}; } diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index c4f054683ccdc9..2cd5486b3227f0 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -135,6 +135,26 @@ TEST(HeuristicResolver, MemberExpr_SmartPointer) { cxxMethodDecl(hasName("foo")).bind("output")); } +TEST(HeuristicResolver, MemberExpr_SmartPointer_Qualified) { + std::string Code = R"cpp( + template <typename> struct Waldo { + void find(); + void find() const; + }; + template <typename T> struct unique_ptr { + T* operator->(); + }; + template <typename T> + void test(unique_ptr<const Waldo<T>>& w) { + w->find(); + } + )cpp"; + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("find")).bind("input"), + cxxMethodDecl(hasName("find"), isConst()).bind("output")); +} + TEST(HeuristicResolver, MemberExpr_Chained) { std::string Code = R"cpp( struct A { void foo() {} }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits