[llvm-branch-commits] [FlowSensitive] [PtrCaching] add is[Smart]PointerLikeConstructor (PR #164031)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Oct 17 16:12:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-analysis
Author: Florian Mayer (fmayer)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/164031.diff
3 Files Affected:
- (modified) clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h (+16)
- (modified) clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp (+25-8)
- (modified) clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp (+72)
``````````diff
diff --git a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
index b5bdff2df8ed6..c775d04f0ba8a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
+++ b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
@@ -58,6 +58,8 @@ namespace clang::dataflow {
/// for `std::optional`, we assume the (Matcher, TransferFunction) case
/// with custom handling is ordered early so that these generic cases
/// do not trigger.
+ast_matchers::StatementMatcher isPointerLikeConstructor();
+ast_matchers::StatementMatcher isSmartPointerLikeConstructor();
ast_matchers::StatementMatcher isPointerLikeOperatorStar();
ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar();
ast_matchers::StatementMatcher isPointerLikeOperatorArrow();
@@ -80,6 +82,8 @@ isSmartPointerLikeGetMethodCall(clang::StringRef MethodName = "get");
const FunctionDecl *
getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE);
+const FunctionDecl *
+getCanonicalSmartPointerLikeOperatorCalleeForType(const CXXRecordDecl *RD);
/// A transfer function for `operator*` (and `value`) calls that can be
/// cached. Runs the `InitializeLoc` callback to initialize any new
/// StorageLocations.
@@ -163,6 +167,18 @@ void transferSmartPointerLikeCachedDeref(
State.Env.setStorageLocation(*DerefExpr, LocForValue);
}
+template <typename LatticeT>
+void transferSmartPointerLikeConstructor(
+ const CXXConstructExpr *ConstructOperator,
+ RecordStorageLocation *SmartPointerLoc, TransferState<LatticeT> &State,
+ llvm::function_ref<void(QualType, StorageLocation &)> InitializeLoc) {
+ const FunctionDecl *CanonicalCallee =
+ getCanonicalSmartPointerLikeOperatorCalleeForType(
+ ConstructOperator->getType()->getAsCXXRecordDecl());
+ State.Lattice.getOrCreateConstMethodReturnStorageLocation(
+ *SmartPointerLoc, CanonicalCallee, State.Env, InitializeLoc);
+}
+
template <typename LatticeT>
void transferSmartPointerLikeCachedGet(
const CallExpr *GetExpr, RecordStorageLocation *SmartPointerLoc,
diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
index d87b2e6f03857..e639119e1a290 100644
--- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
+++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
@@ -129,6 +129,12 @@ AST_MATCHER(clang::CXXRecordDecl, pointerClass) {
namespace clang::dataflow {
+ast_matchers::StatementMatcher isSmartPointerLikeConstructor() {
+ using namespace ast_matchers;
+ return cxxConstructExpr(hasType(hasCanonicalType(qualType(
+ hasDeclaration(cxxRecordDecl(smartPointerClassWithGetOrValue()))))));
+}
+
ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar() {
return cxxOperatorCallExpr(
hasOverloadedOperatorName("*"),
@@ -145,6 +151,12 @@ ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() {
ofClass(smartPointerClassWithGetOrValue()))));
}
+ast_matchers::StatementMatcher isPointerLikeConstructor() {
+ using namespace ast_matchers;
+ return cxxConstructExpr(hasType(hasCanonicalType(
+ qualType(hasDeclaration(cxxRecordDecl(pointerClass()))))));
+}
+
ast_matchers::StatementMatcher isPointerLikeOperatorStar() {
return cxxOperatorCallExpr(
hasOverloadedOperatorName("*"),
@@ -177,15 +189,8 @@ isSmartPointerLikeGetMethodCall(clang::StringRef MethodName) {
}
const FunctionDecl *
-getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {
+getCanonicalSmartPointerLikeOperatorCalleeForType(const CXXRecordDecl *RD) {
const FunctionDecl *CanonicalCallee = nullptr;
- const CXXMethodDecl *Callee =
- cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
- if (Callee == nullptr)
- return nullptr;
- const CXXRecordDecl *RD = Callee->getParent();
- if (RD == nullptr)
- return nullptr;
for (const auto *MD : RD->methods()) {
if (MD->getOverloadedOperator() == OO_Star && MD->isConst() &&
MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) {
@@ -196,4 +201,16 @@ getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {
return CanonicalCallee;
}
+const FunctionDecl *
+getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {
+ const CXXMethodDecl *Callee =
+ cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
+ if (Callee == nullptr)
+ return nullptr;
+ const CXXRecordDecl *RD = Callee->getParent();
+ if (RD == nullptr)
+ return nullptr;
+ return getCanonicalSmartPointerLikeOperatorCalleeForType(RD);
+}
+
} // namespace clang::dataflow
diff --git a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
index 5d3d5b0cfea09..05c66b0847c7a 100644
--- a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
@@ -64,6 +64,15 @@ TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrowGet) {
isSmartPointerLikeOperatorArrow()));
EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
isPointerLikeOperatorArrow()));
+
+ EXPECT_TRUE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_TRUE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrow) {
@@ -101,6 +110,15 @@ TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrow) {
isSmartPointerLikeOperatorArrow()));
EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
isPointerLikeOperatorArrow()));
+
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_TRUE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
@@ -141,6 +159,15 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
EXPECT_TRUE(matches(Decls,
"int target(std::unique_ptr<S, S> P) { return P->i; }",
isPointerLikeOperatorArrow()));
+
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S, T>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S, T>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
@@ -163,6 +190,15 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
EXPECT_FALSE(
matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
isPointerLikeOperatorStar()));
+
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
@@ -196,6 +232,15 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
EXPECT_FALSE(
matches(Decls, "int target(std::unique_ptr<S> P) { return P.get()->i; }",
isSmartPointerLikeGetMethodCall()));
+
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfNoStarMethod) {
@@ -221,6 +266,15 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfNoStarMethod) {
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S> P) { return P->i; }",
isSmartPointerLikeGetMethodCall()));
+
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_FALSE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, MatchesWithValueAndNonConstOverloads) {
@@ -276,6 +330,13 @@ TEST(SmartPointerAccessorCachingTest, MatchesWithValueAndNonConstOverloads) {
Decls,
"int target(const std::optional<S> &Const) { return Const.value().i; }",
isSmartPointerLikeValueMethodCall()));
+
+ EXPECT_TRUE(matches(
+ Decls, "std::optional<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
+ EXPECT_TRUE(matches(
+ Decls, "std::optional<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, MatchesWithTypeAliases) {
@@ -329,6 +390,9 @@ TEST(SmartPointerAccessorCachingTest, MatchesWithTypeAliases) {
EXPECT_TRUE(matches(
Decls, "int target(const HasGetAndValue<S> &Const) { return Const->i; }",
isPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(
+ Decls, "HasGetAndValue<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
EXPECT_TRUE(matches(
Decls,
@@ -346,6 +410,9 @@ TEST(SmartPointerAccessorCachingTest, MatchesWithTypeAliases) {
Decls,
"int target(const HasGetAndValue<S> &Const) { return Const.get()->i; }",
isSmartPointerLikeGetMethodCall()));
+ EXPECT_TRUE(matches(
+ Decls, "HasGetAndValue<S>& Helper(); int target() { auto S = Helper(); }",
+ isSmartPointerLikeConstructor()));
}
TEST(SmartPointerAccessorCachingTest, Renamed) {
@@ -390,6 +457,11 @@ TEST(SmartPointerAccessorCachingTest, Renamed) {
EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
isPointerLikeOperatorArrow()));
+
+ EXPECT_TRUE(matches(
+ Decls,
+ "std::unique_ptr<S>& Helper(); int target() { auto S = Helper(); }",
+ isPointerLikeConstructor()));
}
} // namespace
``````````
</details>
https://github.com/llvm/llvm-project/pull/164031
More information about the llvm-branch-commits
mailing list