https://github.com/ziqingluo-90 updated 
https://github.com/llvm/llvm-project/pull/219041

>From d9d269025d4aad3e97a1cd94520804417ed96943 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <[email protected]>
Date: Tue, 25 Aug 2026 17:47:02 -0700
Subject: [PATCH] [SSAF] Flatten 'UnsafeBufferReachableAnalysisResult' to a
 plain set

Previously, an 'UnsafeBufferReachableAnalysisResult' was organized as
a map from contributors to their mutually exclusive
sub-results. Because this extra layer of contributor information
proved unnecessary, this commit flattens the result into a plain set.

The source transformation expects the result to be a plain set, so
this is a prerequisite step for
rdar://185840466
---
 .../UnsafeBufferUsageAnalysis.h               |  3 ++-
 .../UnsafeBufferUsageAnalysis.cpp             | 20 +++++++++----------
 .../Transformations/CppBoundedBuffers.cpp     | 11 ++++------
 ...achable-excludes-type-constrained-main.cpp |  3 ---
 ...e-excludes-type-constrained-new-delete.cpp | 16 +++++----------
 .../CppBoundedBuffersTest.cpp                 |  4 +---
 .../UnsafeBufferReachableAnalysisTest.cpp     |  5 +----
 7 files changed, 23 insertions(+), 39 deletions(-)

diff --git 
a/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
 
b/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
index aa19c8a7e945e..d677ec4834664 100644
--- 
a/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
+++ 
b/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
@@ -54,7 +54,8 @@ struct UnsafeBufferReachableAnalysisResult final : 
AnalysisResult {
     return AnalysisName(UnsafeBufferReachableAnalysisResultName.str());
   }
 
-  std::map<EntityId, EntityPointerLevelSet> Reachables;
+  /// Whole-program set of pointers (EPLs) reachable from unsafe buffer usage.
+  EntityPointerLevelSet Reachables;
 };
 
 } // namespace clang::ssaf
diff --git 
a/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
 
b/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
index 4fc6d058de368..eed4925a2b298 100644
--- 
a/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
+++ 
b/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
@@ -8,7 +8,10 @@
 // UnsafeBufferUsageAnalysis is a noop analysis.
 //
 // UnsafeBufferUsageAnalysisResult is a map from EntityIds to
-// EntityPointerLevelSets
+// EntityPointerLevelSets.
+//
+// UnsafeBufferReachableAnalysisResult is a flat set of EntityPointerLevels
+// reachable from unsafe buffer usage.
 
//===----------------------------------------------------------------------===//
 
 #include 
"clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h"
@@ -98,7 +101,7 @@ json::Object serializeUnsafeBufferReachableAnalysisResult(
   json::Object Result;
 
   Result[UnsafeBufferReachableAnalysisResultName] =
-      entityPointerLevelMapToJSON(R.Reachables, IdToJSON);
+      entityPointerLevelSetToJSON(R.Reachables, IdToJSON);
   return Result;
 }
 
@@ -113,7 +116,7 @@ deserializeUnsafeBufferReachableAnalysisResult(
         Obj, "an object with a key %s",
         UnsafeBufferReachableAnalysisResultName.data());
 
-  auto Reachables = entityPointerLevelMapFromJSON(*Content, IdFromJSON);
+  auto Reachables = entityPointerLevelSetFromJSON(*Content, IdFromJSON);
 
   if (!Reachables)
     return Reachables.takeError();
@@ -173,7 +176,7 @@ class UnsafeBufferReachableAnalysis
       auto R = SubGraph.getDestNodes(*EPL);
 
       for (const auto &Dst : R) {
-        auto [It, Inserted] = getResult().Reachables[Id].insert(Dst);
+        auto [It, Inserted] = getResult().Reachables.insert(Dst);
         if (Inserted)
           WorkList.push_back(&*It);
       }
@@ -187,9 +190,8 @@ class UnsafeBufferReachableAnalysis
     // Simple DFS:
     std::vector<EPLPtr> Worklist;
 
-    for (auto &[Id, EPLs] : Reachables)
-      for (auto &EPL : EPLs)
-        Worklist.push_back(&EPL);
+    for (auto &EPL : Reachables)
+      Worklist.push_back(&EPL);
 
     while (!Worklist.empty()) {
       EPLPtr Node = Worklist.back();
@@ -233,9 +235,7 @@ class UnsafeBufferReachableAnalysis
     for (auto &[Contributor, EPLs] : UnsafePtrs) {
       auto FilteredRange = llvm::make_filter_range(EPLs, HasNoTypeConstraint);
 
-      if (!FilteredRange.empty())
-        getResult().Reachables[Contributor].insert(FilteredRange.begin(),
-                                                   FilteredRange.end());
+      getResult().Reachables.insert(FilteredRange.begin(), 
FilteredRange.end());
     }
     return llvm::Error::success();
   }
diff --git 
a/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
 
b/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
index 180d5e9f9c7d4..4f0d1c0065084 100644
--- 
a/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
+++ 
b/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
@@ -211,12 +211,11 @@ using ReturnLevels = std::map<const FunctionDecl *, 
Levels>;
 /// Reverse index from the whole-program reachability result onto entity names,
 /// so a declaration in this TU can look up its reachable pointer levels.
 class ReachabilityMap {
-  const std::map<EntityId, EntityPointerLevelSet> &Reachables;
+  const EntityPointerLevelSet &Reachables;
   std::map<EntityName, EntityId> NameToId;
 
 public:
-  ReachabilityMap(const WPASuite &Suite,
-                  const std::map<EntityId, EntityPointerLevelSet> &Reachables)
+  ReachabilityMap(const WPASuite &Suite, const EntityPointerLevelSet 
&Reachables)
       : Reachables(Reachables) {
     Suite.getIdTable().forEach([this](const EntityName &Name, EntityId Id) {
       NameToId.emplace(Name, Id);
@@ -230,10 +229,8 @@ class ReachabilityMap {
     auto NameIt = NameToId.find(*Name);
     if (NameIt == NameToId.end())
       return Levels;
-    auto ReachIt = Reachables.find(NameIt->second);
-    if (ReachIt == Reachables.end())
-      return Levels;
-    for (const EntityPointerLevel &EPL : ReachIt->second)
+    auto [Begin, End] = Reachables.equal_range(NameIt->second);
+    for (const EntityPointerLevel &EPL : llvm::make_range(Begin, End))
       Levels.insert(EPL.getPointerLevel());
     return Levels;
   }
diff --git 
a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
 
b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
index 91449e2511aa2..094f74c82fc90 100644
--- 
a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
+++ 
b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
@@ -46,9 +46,6 @@ void foo(int *q) {
 
 // In the reachable result 'q' is present but 'argv' is not.
 // CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
-
-// 'foo' contributes unsafe pointer 'q'.
-// CHECK: "@": [[CONTRIBUTOR_FOO]]$WS},$WS[
 // CHECK: "@": [[Q_ID]]$PTR_L1
 // CHECK-NOT: "@":
 
diff --git 
a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
 
b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
index 22df8ad075ef9..6902a384a67f5 100644
--- 
a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
+++ 
b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
@@ -87,20 +87,14 @@ void bar() {
 
 // CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
 
-// 'bar' contributes unsafe pointer 'y' but not 'x':
-// CHECK: "@": [[CONTRIBUTOR_BAR]]$WS},$WS[
-// CHECK: "@": [[BAR_Y]]$PTR_L1
-// CHECK-NOT: "@": [[BAR_X]]$PTR_L1
-
-// 'foo' contributes unsafe pointers 'q' and 'r':
-// CHECK: "@": [[CONTRIBUTOR_FOO]]$WS},$WS[
+// 'bar' contributes 'y' but not 'x'; 'foo' contributes 'q' and 'r'; 'operator
+// delete' contributes 'delete_local'. None of the type-constrained pointers
+// appear.
+// CHECK-DAG: "@": [[BAR_Y]]$PTR_L1
 // CHECK-DAG: "@": [[FOO_Q]]$PTR_L1
 // CHECK-DAG: "@": [[FOO_R]]$PTR_L1
-// CHECK-NOT: "@":
-
-// 'operator delete' contributes unsafe pointer 'delete_local':
-// CHECK: "@": [[CONTRIBUTOR_DELETE]]$WS},$WS[
 // CHECK-DAG: "@": [[DELETE_LOCAL]]$PTR_L1
+// CHECK-NOT: "@": [[BAR_X]]$PTR_L1
 
 // The type-constrained pointers never appear in the reachable result:
 // CHECK-NOT: "@": [[NEW_RET]]$WS
diff --git 
a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
 
b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
index 5f44260612404..3e1c512b9c3a3 100644
--- 
a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
@@ -100,10 +100,8 @@ class CppBoundedBuffersTest : public TestFixture {
     if (!Name || Levels.empty())
       return;
     EntityId Id = getIdTable(Suite).getId(*Name);
-    EntityPointerLevelSet Set;
     for (unsigned Level : Levels)
-      Set.insert(buildEntityPointerLevel(Id, Level));
-    Result.Reachables[Id] = std::move(Set);
+      Result.Reachables.insert(buildEntityPointerLevel(Id, Level));
   }
 
   // Parses \p Code, lets \p Mark populate the reachable result, runs the
diff --git 
a/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
 
b/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
index b057b6b1ed5bf..aec1cd993343d 100644
--- 
a/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
@@ -150,10 +150,7 @@ class UnsafeBufferReachableAnalysisTest : public 
TestFixture {
       ADD_FAILURE_AT(__FILE__, Line) << llvm::toString(ROrErr.takeError());
       return std::nullopt;
     }
-    EntityPointerLevelSet Result;
-    for (const auto &[Id, EPLs] : ROrErr->Reachables)
-      Result.insert(EPLs.begin(), EPLs.end());
-    return Result;
+    return ROrErr->Reachables;
   }
 
   using Node = std::pair<char, unsigned>;

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

Reply via email to