[clang] 1cbcaa4 - [clang][dataflow] Add matcher for pointer-like types to be cached (#132314)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 21 10:27:13 PDT 2025
Author: Florian Mayer
Date: 2025-03-21T13:27:11-04:00
New Revision: 1cbcaa458020d7fa2b9b5d91db609f5a81d59346
URL: https://github.com/llvm/llvm-project/commit/1cbcaa458020d7fa2b9b5d91db609f5a81d59346
DIFF: https://github.com/llvm/llvm-project/commit/1cbcaa458020d7fa2b9b5d91db609f5a81d59346.diff
LOG: [clang][dataflow] Add matcher for pointer-like types to be cached (#132314)
This is used e.g. for iterators.
Added:
Modified:
clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
index 1b116a0cf76ed..b4291347e0969 100644
--- a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
+++ b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h
@@ -58,7 +58,9 @@ 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 isPointerLikeOperatorStar();
ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar();
+ast_matchers::StatementMatcher isPointerLikeOperatorArrow();
ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow();
ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall();
ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall();
diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
index 4f5d18225c414..0860cc1dbaf8e 100644
--- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
+++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
@@ -120,6 +120,14 @@ AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) {
return HasStarAndArrow && (HasGet || HasValue);
}
+AST_MATCHER(clang::CXXRecordDecl, pointerClass) {
+ bool HasGet = false;
+ bool HasValue = false;
+ bool HasStarAndArrow =
+ clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue);
+ return HasStarAndArrow;
+}
+
} // namespace
namespace clang::dataflow {
@@ -140,6 +148,22 @@ ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() {
ofClass(smartPointerClassWithGetOrValue()))));
}
+ast_matchers::StatementMatcher isPointerLikeOperatorStar() {
+ return cxxOperatorCallExpr(
+ hasOverloadedOperatorName("*"),
+ callee(cxxMethodDecl(parameterCountIs(0),
+ returns(hasCanonicalType(referenceType())),
+ ofClass(pointerClass()))));
+}
+
+ast_matchers::StatementMatcher isPointerLikeOperatorArrow() {
+ return cxxOperatorCallExpr(
+ hasOverloadedOperatorName("->"),
+ callee(cxxMethodDecl(parameterCountIs(0),
+ returns(hasCanonicalType(pointerType())),
+ ofClass(pointerClass()))));
+}
+
ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall() {
return cxxMemberCallExpr(callee(cxxMethodDecl(
parameterCountIs(0), returns(hasCanonicalType(referenceType())),
diff --git a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
index 18b9f80e32bbf..0f7477d875960 100644
--- a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp
@@ -45,15 +45,62 @@ TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrowGet) {
EXPECT_TRUE(matches(Decls,
"int target(std::unique_ptr<S> P) { return (*P).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_TRUE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return (*P).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_TRUE(matches(Decls,
"int target(std::unique_ptr<S> P) { return P->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_TRUE(matches(Decls,
"int target(std::unique_ptr<S> P) { return P.get()->i; }",
isSmartPointerLikeGetMethodCall()));
EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
+}
+
+TEST(SmartPointerAccessorCachingTest, MatchesClassWithStarArrow) {
+ llvm::StringRef Decls(R"cc(
+ namespace std {
+ template <class T>
+ struct unique_ptr {
+ T* operator->() const;
+ T& operator*() const;
+ };
+ } // namespace std
+
+ template <class T>
+ using UniquePtrAlias = std::unique_ptr<T>;
+
+ struct S { int i; };
+ )cc");
+
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return (*P).i; }",
+ isSmartPointerLikeOperatorStar()));
+ EXPECT_TRUE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return (*P).i; }",
+ isPointerLikeOperatorStar()));
+
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return P->i; }",
+ isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
+
+ EXPECT_FALSE(matches(Decls,
+ "int target(UniquePtrAlias<S> P) { return P->i; }",
+ isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
@@ -75,15 +122,25 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfUnexpectedReturnTypes) {
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S, T> P) { return (*P).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S, T> P) { return (*P).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S, T> P) { return P->j; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S, T> P) { return P->j; }",
+ isPointerLikeOperatorArrow()));
// The class matching arguably accidentally matches, just because the
// instantiation is with S, S. Hopefully doesn't happen too much in real code
// with such operator* and operator-> overloads.
EXPECT_TRUE(matches(Decls,
"int target(std::unique_ptr<S, S> P) { return P->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(Decls,
+ "int target(std::unique_ptr<S, S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
@@ -103,6 +160,9 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfBinaryStar) {
EXPECT_FALSE(
matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_FALSE(
+ matches(Decls, "int target(std::unique_ptr<S> P) { return (P * 10).i; }",
+ isPointerLikeOperatorStar()));
}
TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
@@ -122,9 +182,17 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfNoConstOverloads) {
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S> P) { return (*P).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return (*P).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S> P) { return P->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_FALSE(
matches(Decls, "int target(std::unique_ptr<S> P) { return P.get()->i; }",
isSmartPointerLikeGetMethodCall()));
@@ -146,6 +214,10 @@ TEST(SmartPointerAccessorCachingTest, NoMatchIfNoStarMethod) {
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S> P) { return P->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_FALSE(matches(Decls,
+ "int target(std::unique_ptr<S> P) { return P->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_FALSE(matches(Decls,
"int target(std::unique_ptr<S> P) { return P->i; }",
isSmartPointerLikeGetMethodCall()));
@@ -171,15 +243,31 @@ TEST(SmartPointerAccessorCachingTest, MatchesWithValueAndNonConstOverloads) {
EXPECT_TRUE(matches(
Decls, "int target(std::optional<S> &NonConst) { return (*NonConst).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_TRUE(matches(
+ Decls, "int target(std::optional<S> &NonConst) { return (*NonConst).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_TRUE(matches(
Decls, "int target(const std::optional<S> &Const) { return (*Const).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_TRUE(matches(
+ Decls, "int target(const std::optional<S> &Const) { return (*Const).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_TRUE(matches(
Decls, "int target(std::optional<S> &NonConst) { return NonConst->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(
+ Decls, "int target(std::optional<S> &NonConst) { return NonConst->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_TRUE(matches(
Decls, "int target(const std::optional<S> &Const) { return Const->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(
+ Decls, "int target(const std::optional<S> &Const) { return Const->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_TRUE(matches(
Decls,
"int target(std::optional<S> &NonConst) { return NonConst.value().i; }",
@@ -214,16 +302,34 @@ TEST(SmartPointerAccessorCachingTest, MatchesWithTypeAliases) {
Decls,
"int target(HasGetAndValue<S> &NonConst) { return (*NonConst).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_TRUE(matches(
+ Decls,
+ "int target(HasGetAndValue<S> &NonConst) { return (*NonConst).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_TRUE(matches(
Decls,
"int target(const HasGetAndValue<S> &Const) { return (*Const).i; }",
isSmartPointerLikeOperatorStar()));
+ EXPECT_TRUE(matches(
+ Decls,
+ "int target(const HasGetAndValue<S> &Const) { return (*Const).i; }",
+ isPointerLikeOperatorStar()));
+
EXPECT_TRUE(matches(
Decls, "int target(HasGetAndValue<S> &NonConst) { return NonConst->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(
+ Decls, "int target(HasGetAndValue<S> &NonConst) { return NonConst->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_TRUE(matches(
Decls, "int target(const HasGetAndValue<S> &Const) { return Const->i; }",
isSmartPointerLikeOperatorArrow()));
+ EXPECT_TRUE(matches(
+ Decls, "int target(const HasGetAndValue<S> &Const) { return Const->i; }",
+ isPointerLikeOperatorArrow()));
+
EXPECT_TRUE(matches(
Decls,
"int target(HasGetAndValue<S> &NonConst) { return NonConst.value().i; }",
More information about the cfe-commits
mailing list