https://github.com/ziqingluo-90 created 
https://github.com/llvm/llvm-project/pull/203633

Decls of reference-to-pointer/array types are now treated the same as those of 
pointer/array type.

rdar://179173940

>From 00b39efd86ec25b128d624ed0f99c3d6bab738b6 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <[email protected]>
Date: Fri, 12 Jun 2026 12:37:45 -0700
Subject: [PATCH] [SSAF][PointerFlow] Recognize reference-to-pointer/array
 Decls

Decls of reference-to-pointer/array types are now treated the same as
those of pointer/array type.

rdar://179173940
---
 .../Analyses/SSAFAnalysesCommon.h             |  9 ++-
 .../PointerFlow/lref-to-rref-cast.test        | 40 ++++++++++++
 .../Analyses/PointerFlow/PointerFlowTest.cpp  | 64 ++++++++++++++++++-
 3 files changed, 110 insertions(+), 3 deletions(-)
 create mode 100644 
clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test

diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
index 63755304ea3c9..144bab532d4bf 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
@@ -42,11 +42,18 @@ llvm::Error makeSawButExpectedError(const JSONTy &Saw, 
llvm::StringRef Expected,
   return llvm::createStringError(Fmt.c_str(), SawStr.c_str(), ExpectedArgs...);
 }
 
-template <typename DeclOrExpr> bool hasPtrOrArrType(const DeclOrExpr *E) {
+///\return true iff expression `E` has pointer or array type.
+inline bool hasPtrOrArrType(const Expr *E) {
   return llvm::isa<clang::PointerType, clang::ArrayType>(
       E->getType().getCanonicalType());
 }
 
+///\return true iff Decl `D` has (reference-to) pointer or array type.
+inline bool hasPtrOrArrType(const ValueDecl *D) {
+  return llvm::isa<clang::PointerType, clang::ArrayType>(
+      D->getType().getNonReferenceType().getCanonicalType());
+}
+
 llvm::Error makeEntityNameErr(clang::ASTContext &Ctx,
                               const clang::NamedDecl *D);
 
diff --git a/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test 
b/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test
new file mode 100644
index 0000000000000..195a4d47ae54a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test
@@ -0,0 +1,40 @@
+// Test that entities representing references-to-pointers are
+// connected through 'fake_move' (my fake 'std::move').
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: split-file %s %t
+
+// Extract per-TU PointerFlow + UnsafeBufferUsage summaries.
+// RUN: %clang_cc1 -fsyntax-only %t/tu.cpp \
+// RUN:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
+// RUN:   --ssaf-tu-summary-file=%t/tu.summary.json
+
+// Link into a single LU summary.
+// RUN: clang-ssaf-linker %t/tu.summary.json -o %t/lu.json
+
+// RUN: clang-ssaf-analyzer %t/lu.json -o %t/wpa.json \
+// RUN:   -a UnsafeBufferReachableAnalysisResult
+
+//--- tu.cpp
+constexpr int* &&fake_move(int* &arg) noexcept { //FIXME: after #198927, we 
can use template
+  return static_cast<int* &&>(arg);
+}
+
+void foo(int *p) {
+  int *&&rp = fake_move(p);
+  rp[5] = 0;
+}
+
+// Check that unsafe buffer propagates from 'rp' to 'p' by ensuring
+// that both 'rp' and 'p' are in the reachable set.
+
+// RUN: FileCheck %s --input-file=%t/wpa.json
+
+// CHECK-DAG: "id": 
[[RP_ID:[0-9]+]],{{([^]]|[[:space:]])+\],[[:space:]]+"suffix": 
"",[[:space:]]+"usr": "[^"]*}}@rp"
+// CHECK-DAG: "id": 
[[P_ID:[0-9]+]],{{([^]]|[[:space:]])+\],[[:space:]]+"suffix": 
"1",[[:space:]]+"usr": }}"c:@F@foo#*I#"
+
+// CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
+// CHECK-DAG: {{\{[[:space:]]+}}"@": 
[[RP_ID]]{{[[:space:]]+\},[[:space:]]+1[[:space:]]+\]}}
+// CHECK-DAG: {{\{[[:space:]]+}}"@": 
[[P_ID]]{{[[:space:]]+\},[[:space:]]+1[[:space:]]+\]}}
+// CHECK: "analysis_name"
+
diff --git 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
index bff9dc10bfc1f..c1f5416718c4c 100644
--- 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
@@ -13,9 +13,7 @@
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Frontend/ASTUnit.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
@@ -1193,4 +1191,66 @@ TEST_F(PointerFlowTest, CXXConstructExprArrayInit) {
   ASSERT_NE(Sum, nullptr);
   EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"q", 1U}, {"arr", 1U}}}));
 }
+
+//////////////////////////////////////////////////////////////
+//          Reference-to-pointer Tests                      //
+//////////////////////////////////////////////////////////////
+
+TEST_F(PointerFlowTest, ArgToRefParam) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void callee(int *&rp);
+    void caller(int *p) {
+      callee(p);
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("caller");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, ArgToRefParamLevel2) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void callee(int **&rp);
+    void caller(int **pp) {
+      callee(pp);
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("caller");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"pp", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, InitRefPtr) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo(int *p) {
+      int *&rp = p;
+      int * const & crp = p;
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"p", 1U}},
+                                       {{"crp", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, ReturnRefPtr) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    int *& f();
+    int *& foo() {
+      return f();
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"foo", 1U, true}, {"f", 1U, true}}}));
+}
+
 } // namespace

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to