[clang] [clang-tools-extra] [clang][Sema] Respect const-qualification of methods in heuristic results (PR #123551)
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 20 23:59:38 PST 2025
https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/123551
>From cd87f05f19f245e24f5c29b97af0b69266608d7a Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at 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 aec579fb35a400652d104745023d3f36b7622e78 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at 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..2a726fe51d355e 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)) {
+ return MD->getMethodQualifiers().compatiblyIncludes(QT.getQualifiers(),
+ Ctx);
+ }
+ 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() {} };
More information about the cfe-commits
mailing list