https://github.com/fmayer updated https://github.com/llvm/llvm-project/pull/133350
>From 8ece858e76fad0962b2567f03bf80bcaf2828348 Mon Sep 17 00:00:00 2001 From: Florian Mayer <fma...@google.com> Date: Thu, 27 Mar 2025 18:25:23 -0700 Subject: [PATCH 1/5] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?= =?UTF-8?q?itial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 --- .../SmartPointerAccessorCaching.h | 6 +- .../SmartPointerAccessorCaching.cpp | 125 ++++++++++-------- .../SmartPointerAccessorCachingTest.cpp | 40 ++++++ 3 files changed, 114 insertions(+), 57 deletions(-) diff --git a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h index b4291347e0969..e55b83aa845d4 100644 --- a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h +++ b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h @@ -62,8 +62,10 @@ ast_matchers::StatementMatcher isPointerLikeOperatorStar(); ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar(); ast_matchers::StatementMatcher isPointerLikeOperatorArrow(); ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow(); -ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall(); -ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall(); +ast_matchers::StatementMatcher +isSmartPointerLikeValueMethodCall(clang::StringRef MethodName = "value"); +ast_matchers::StatementMatcher +isSmartPointerLikeGetMethodCall(clang::StringRef MethodName = "get"); // Common transfer functions. diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp index 0860cc1dbaf8e..638f5211152b2 100644 --- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp +++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp @@ -2,6 +2,7 @@ #include "clang/AST/CanonicalType.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" #include "clang/Basic/OperatorKinds.h" @@ -23,8 +24,7 @@ using ast_matchers::pointerType; using ast_matchers::referenceType; using ast_matchers::returns; -bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet, - bool &HasValue) { +CanQualType pointerLikeReturnType(const CXXRecordDecl &RD) { // We may want to cache this search, but in current profiles it hasn't shown // up as a hot spot (possibly because there aren't many hits, relatively). bool HasArrow = false; @@ -55,38 +55,47 @@ bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet, .getUnqualifiedType(); } break; - case OO_None: { - IdentifierInfo *II = MD->getIdentifier(); - if (II == nullptr) - continue; - if (II->isStr("get")) { - if (MD->getReturnType()->isPointerType()) { - HasGet = true; - GetReturnType = MD->getReturnType() - ->getPointeeType() - ->getCanonicalTypeUnqualified() - .getUnqualifiedType(); - } - } else if (II->isStr("value")) { - if (MD->getReturnType()->isReferenceType()) { - HasValue = true; - ValueReturnType = MD->getReturnType() - .getNonReferenceType() - ->getCanonicalTypeUnqualified() - .getUnqualifiedType(); - } - } - } break; default: break; } } + if (HasStar && HasArrow && StarReturnType == ArrowReturnType) + return StarReturnType; - if (!HasStar || !HasArrow || StarReturnType != ArrowReturnType) - return false; - HasGet = HasGet && (GetReturnType == StarReturnType); - HasValue = HasValue && (ValueReturnType == StarReturnType); - return true; + return {}; +} +CanQualType getLikeReturnType(QualType RT) { + if (!RT.isNull() && RT->isPointerType()) { + return RT->getPointeeType() + ->getCanonicalTypeUnqualified() + .getUnqualifiedType(); + } + return {}; +} + +CanQualType valueLikeReturnType(QualType RT) { + if (!RT.isNull() && RT->isReferenceType()) { + return RT.getNonReferenceType() + ->getCanonicalTypeUnqualified() + .getUnqualifiedType(); + } + return {}; +} + +QualType findReturnType(const CXXRecordDecl &RD, StringRef MethodName) { + for (const auto *MD : RD.methods()) { + // We only consider methods that are const and have zero parameters. + // It may be that there is a non-const overload for the method, but + // there should at least be a const overload as well. + if (!MD->isConst() || MD->getNumParams() != 0 || + MD->getOverloadedOperator() != OO_None) + continue; + clang::IdentifierInfo *II = MD->getIdentifier(); + if (II && II->isStr(MethodName)) { + return MD->getReturnType(); + } + } + return {}; } } // namespace @@ -96,36 +105,39 @@ bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet, // its own anonymous namespace instead of in clang::dataflow. namespace { -AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGet) { - bool HasGet = false; - bool HasValue = false; - bool HasStarAndArrow = - clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); - return HasStarAndArrow && HasGet; +AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithGetLike, + clang::StringRef, MethodName) { + auto RT = clang::dataflow::pointerLikeReturnType(Node); + if (RT.isNull()) + return false; + return clang::dataflow::getLikeReturnType( + clang::dataflow::findReturnType(Node, MethodName)) == RT; } -AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithValue) { - bool HasGet = false; - bool HasValue = false; - bool HasStarAndArrow = - clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); - return HasStarAndArrow && HasValue; +AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithValueLike, + clang::StringRef, MethodName) { + auto RT = clang::dataflow::pointerLikeReturnType(Node); + if (RT.isNull()) + return false; + return clang::dataflow::valueLikeReturnType( + clang::dataflow::findReturnType(Node, MethodName)) == RT; } AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) { - bool HasGet = false; - bool HasValue = false; - bool HasStarAndArrow = - clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); - return HasStarAndArrow && (HasGet || HasValue); + auto RT = clang::dataflow::pointerLikeReturnType(Node); + if (RT.isNull()) + return false; + if (clang::dataflow::getLikeReturnType( + clang::dataflow::findReturnType(Node, "get")) == RT) + return true; + if (clang::dataflow::valueLikeReturnType( + clang::dataflow::findReturnType(Node, "value")) == RT) + return true; + return false; } AST_MATCHER(clang::CXXRecordDecl, pointerClass) { - bool HasGet = false; - bool HasValue = false; - bool HasStarAndArrow = - clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); - return HasStarAndArrow; + return !clang::dataflow::pointerLikeReturnType(Node).isNull(); } } // namespace @@ -164,16 +176,19 @@ ast_matchers::StatementMatcher isPointerLikeOperatorArrow() { ofClass(pointerClass())))); } -ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall() { +ast_matchers::StatementMatcher +isSmartPointerLikeValueMethodCall(clang::StringRef MethodName) { return cxxMemberCallExpr(callee(cxxMethodDecl( parameterCountIs(0), returns(hasCanonicalType(referenceType())), - hasName("value"), ofClass(smartPointerClassWithValue())))); + hasName(MethodName), + ofClass(smartPointerClassWithValueLike(MethodName))))); } -ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall() { +ast_matchers::StatementMatcher +isSmartPointerLikeGetMethodCall(clang::StringRef MethodName) { return cxxMemberCallExpr(callee(cxxMethodDecl( parameterCountIs(0), returns(hasCanonicalType(pointerType())), - hasName("get"), ofClass(smartPointerClassWithGet())))); + hasName(MethodName), ofClass(smartPointerClassWithGetLike(MethodName))))); } const FunctionDecl * diff --git a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp index 0f7477d875960..34f3b016d58fa 100644 --- a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp @@ -348,5 +348,45 @@ TEST(SmartPointerAccessorCachingTest, MatchesWithTypeAliases) { isSmartPointerLikeGetMethodCall())); } +TEST(SmartPointerAccessorCachingTest, Renamed) { + llvm::StringRef Decls(R"cc( + namespace std { + template <class T> + struct unique_ptr { + T* operator->() const; + T& operator*() const; + T* Get() const; + T& Value() const; + }; + } // namespace std + + template <class T> + using UniquePtrAlias = std::unique_ptr<T>; + + struct S { int i; }; + )cc"); + + 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; }", + isPointerLikeOperatorArrow())); + + EXPECT_TRUE(matches(Decls, + "int target(std::unique_ptr<S> P) { return P.Get()->i; }", + isSmartPointerLikeGetMethodCall("Get"))); + + EXPECT_TRUE( + matches(Decls, "int target(std::unique_ptr<S> P) { return P.Value().i; }", + isSmartPointerLikeValueMethodCall("Value"))); + + EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }", + isPointerLikeOperatorArrow())); + EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }", + isPointerLikeOperatorArrow())); +} + } // namespace } // namespace clang::dataflow >From b1d87ca25ef26738d1009fd22a4b738e8aa19268 Mon Sep 17 00:00:00 2001 From: Florian Mayer <fma...@google.com> Date: Thu, 27 Mar 2025 19:52:00 -0700 Subject: [PATCH 2/5] refactor Created using spr 1.3.4 --- .../SmartPointerAccessorCaching.cpp | 56 ++++++++----------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp index 638f5211152b2..95125ab5cb799 100644 --- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp +++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp @@ -24,11 +24,27 @@ using ast_matchers::pointerType; using ast_matchers::referenceType; using ast_matchers::returns; +CanQualType getLikeReturnType(QualType RT) { + if (!RT.isNull() && RT->isPointerType()) { + return RT->getPointeeType() + ->getCanonicalTypeUnqualified() + .getUnqualifiedType(); + } + return {}; +} + +CanQualType valueLikeReturnType(QualType RT) { + if (!RT.isNull() && RT->isReferenceType()) { + return RT.getNonReferenceType() + ->getCanonicalTypeUnqualified() + .getUnqualifiedType(); + } + return {}; +} + CanQualType pointerLikeReturnType(const CXXRecordDecl &RD) { // We may want to cache this search, but in current profiles it hasn't shown // up as a hot spot (possibly because there aren't many hits, relatively). - bool HasArrow = false; - bool HasStar = false; CanQualType StarReturnType, ArrowReturnType, GetReturnType, ValueReturnType; for (const auto *MD : RD.methods()) { // We only consider methods that are const and have zero parameters. @@ -38,49 +54,21 @@ CanQualType pointerLikeReturnType(const CXXRecordDecl &RD) { continue; switch (MD->getOverloadedOperator()) { case OO_Star: - if (MD->getReturnType()->isReferenceType()) { - HasStar = true; - StarReturnType = MD->getReturnType() - .getNonReferenceType() - ->getCanonicalTypeUnqualified() - .getUnqualifiedType(); - } + StarReturnType = valueLikeReturnType(MD->getReturnType()); break; case OO_Arrow: - if (MD->getReturnType()->isPointerType()) { - HasArrow = true; - ArrowReturnType = MD->getReturnType() - ->getPointeeType() - ->getCanonicalTypeUnqualified() - .getUnqualifiedType(); - } + ArrowReturnType = getLikeReturnType(MD->getReturnType()); break; default: break; } } - if (HasStar && HasArrow && StarReturnType == ArrowReturnType) + if (!StarReturnType.isNull() && !ArrowReturnType.isNull() && + StarReturnType == ArrowReturnType) return StarReturnType; return {}; } -CanQualType getLikeReturnType(QualType RT) { - if (!RT.isNull() && RT->isPointerType()) { - return RT->getPointeeType() - ->getCanonicalTypeUnqualified() - .getUnqualifiedType(); - } - return {}; -} - -CanQualType valueLikeReturnType(QualType RT) { - if (!RT.isNull() && RT->isReferenceType()) { - return RT.getNonReferenceType() - ->getCanonicalTypeUnqualified() - .getUnqualifiedType(); - } - return {}; -} QualType findReturnType(const CXXRecordDecl &RD, StringRef MethodName) { for (const auto *MD : RD.methods()) { >From 7d62ff07957fc1b59c12c2af315f221e048b2827 Mon Sep 17 00:00:00 2001 From: Florian Mayer <fma...@google.com> Date: Thu, 27 Mar 2025 19:58:43 -0700 Subject: [PATCH 3/5] fmt Created using spr 1.3.4 --- .../SmartPointerAccessorCaching.cpp | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp index 95125ab5cb799..e4384caf0fb18 100644 --- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp +++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp @@ -93,39 +93,37 @@ QualType findReturnType(const CXXRecordDecl &RD, StringRef MethodName) { // its own anonymous namespace instead of in clang::dataflow. namespace { +using clang::dataflow::findReturnType; +using clang::dataflow::getLikeReturnType; +using clang::dataflow::pointerLikeReturnType; +using clang::dataflow::valueLikeReturnType; + AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithGetLike, clang::StringRef, MethodName) { - auto RT = clang::dataflow::pointerLikeReturnType(Node); + auto RT = pointerLikeReturnType(Node); if (RT.isNull()) return false; - return clang::dataflow::getLikeReturnType( - clang::dataflow::findReturnType(Node, MethodName)) == RT; + return getLikeReturnType(findReturnType(Node, MethodName)) == RT; } AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithValueLike, clang::StringRef, MethodName) { - auto RT = clang::dataflow::pointerLikeReturnType(Node); + auto RT = pointerLikeReturnType(Node); if (RT.isNull()) return false; - return clang::dataflow::valueLikeReturnType( - clang::dataflow::findReturnType(Node, MethodName)) == RT; + return valueLikeReturnType(findReturnType(Node, MethodName)) == RT; } AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) { - auto RT = clang::dataflow::pointerLikeReturnType(Node); + auto RT = pointerLikeReturnType(Node); if (RT.isNull()) return false; - if (clang::dataflow::getLikeReturnType( - clang::dataflow::findReturnType(Node, "get")) == RT) - return true; - if (clang::dataflow::valueLikeReturnType( - clang::dataflow::findReturnType(Node, "value")) == RT) - return true; - return false; + return getLikeReturnType(findReturnType(Node, "get")) == RT || + valueLikeReturnType(findReturnType(Node, "value")) == RT; } AST_MATCHER(clang::CXXRecordDecl, pointerClass) { - return !clang::dataflow::pointerLikeReturnType(Node).isNull(); + return !pointerLikeReturnType(Node).isNull(); } } // namespace >From aab1363d72231cd775f82c1aaca9cca01a54df5f Mon Sep 17 00:00:00 2001 From: Florian Mayer <fma...@google.com> Date: Thu, 27 Mar 2025 20:00:13 -0700 Subject: [PATCH 4/5] fmt Created using spr 1.3.4 --- .../lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp index e4384caf0fb18..3d82d57280716 100644 --- a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp +++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp @@ -79,9 +79,8 @@ QualType findReturnType(const CXXRecordDecl &RD, StringRef MethodName) { MD->getOverloadedOperator() != OO_None) continue; clang::IdentifierInfo *II = MD->getIdentifier(); - if (II && II->isStr(MethodName)) { + if (II && II->isStr(MethodName)) return MD->getReturnType(); - } } return {}; } >From 9839bc69c6b33155dba13b0bc50c9859641ac107 Mon Sep 17 00:00:00 2001 From: Florian Mayer <fma...@google.com> Date: Thu, 27 Mar 2025 21:00:28 -0700 Subject: [PATCH 5/5] test Created using spr 1.3.4 --- .../FlowSensitive/SmartPointerAccessorCachingTest.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp index 34f3b016d58fa..2c316249b8f6d 100644 --- a/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/SmartPointerAccessorCachingTest.cpp @@ -377,15 +377,19 @@ TEST(SmartPointerAccessorCachingTest, Renamed) { EXPECT_TRUE(matches(Decls, "int target(std::unique_ptr<S> P) { return P.Get()->i; }", isSmartPointerLikeGetMethodCall("Get"))); + EXPECT_TRUE( + matches(Decls, "int target(UniquePtrAlias<S> P) { return P.Get()->i; }", + isSmartPointerLikeGetMethodCall("Get"))); EXPECT_TRUE( matches(Decls, "int target(std::unique_ptr<S> P) { return P.Value().i; }", isSmartPointerLikeValueMethodCall("Value"))); + EXPECT_TRUE( + matches(Decls, "int target(UniquePtrAlias<S> P) { return P.Value().i; }", + isSmartPointerLikeValueMethodCall("Value"))); EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }", isPointerLikeOperatorArrow())); - EXPECT_TRUE(matches(Decls, "int target(UniquePtrAlias<S> P) { return P->i; }", - isPointerLikeOperatorArrow())); } } // namespace _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits