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

Reply via email to