Author: Ziqing Luo
Date: 2026-04-07T11:19:59-07:00
New Revision: 4913bd5588ada1dfd0e5a822b016d99b8196ca43

URL: 
https://github.com/llvm/llvm-project/commit/4913bd5588ada1dfd0e5a822b016d99b8196ca43
DIFF: 
https://github.com/llvm/llvm-project/commit/4913bd5588ada1dfd0e5a822b016d99b8196ca43.diff

LOG: [ssaf][UnsafeBufferUsage] Add JSON serialization for UnsafeBufferUsage 
(#187156)

Implemented and registered a JSONFormat::FormatInfo for
UnsafeBufferUsage analysis

rdar://171920065

---------

Co-authored-by: Balázs Benics <[email protected]>

Added: 
    
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
    
clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
    
clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
    
clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
    clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
    clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
    clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test

Modified: 
    
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
    clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
    clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
    clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
    clang/test/Analysis/Scalable/ssaf-format/list.test
    
clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
index c0a4c2f76ab48..4e217c2eb87ef 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
@@ -12,6 +12,8 @@
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
 #include <set>
 
 namespace clang::ssaf {
@@ -37,7 +39,9 @@ class EntityPointerLevel {
   EntityId Entity;
   unsigned PointerLevel;
 
+  friend class UnsafeBufferUsageEntitySummary;
   friend class UnsafeBufferUsageTUSummaryExtractor;
+  friend EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
 
   EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
       : Entity(Entity), PointerLevel(PointerLevel) {}
@@ -86,20 +90,30 @@ class UnsafeBufferUsageEntitySummary final : public 
EntitySummary {
   const EntityPointerLevelSet UnsafeBuffers;
 
   friend class UnsafeBufferUsageTUSummaryExtractor;
+  friend UnsafeBufferUsageEntitySummary
+      buildUnsafeBufferUsageEntitySummary(EntityPointerLevelSet);
+  friend llvm::iterator_range<EntityPointerLevelSet::const_iterator>
+  getUnsafeBuffers(const UnsafeBufferUsageEntitySummary &);
 
   UnsafeBufferUsageEntitySummary(EntityPointerLevelSet UnsafeBuffers)
       : EntitySummary(), UnsafeBuffers(std::move(UnsafeBuffers)) {}
 
 public:
-  SummaryName getSummaryName() const override {
-    return SummaryName{"UnsafeBufferUsage"};
-  };
+  static constexpr llvm::StringLiteral Name = "UnsafeBufferUsage";
+
+  SummaryName getSummaryName() const override { return summaryName(); };
 
   bool operator==(const EntityPointerLevelSet &Other) const {
     return UnsafeBuffers == Other;
   }
 
+  bool operator==(const UnsafeBufferUsageEntitySummary &Other) const {
+    return UnsafeBuffers == Other.UnsafeBuffers;
+  }
+
   bool empty() const { return UnsafeBuffers.empty(); }
+
+  static SummaryName summaryName() { return SummaryName{Name.str()}; }
 };
 } // namespace clang::ssaf
 

diff  --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
new file mode 100644
index 0000000000000..6a2d1161246f2
--- /dev/null
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
@@ -0,0 +1,29 @@
+//===- UnsafeBufferUsageTest.h ----------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions and data structures that help UnsafeBufferUsage unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef 
LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGETEST_H
+#define 
LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGETEST_H
+
+#include 
"clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
+#include "llvm/Support/Error.h"
+
+namespace clang::ssaf {
+
+llvm::Expected<std::unique_ptr<EntitySummary>> serializeDeserializeRoundTrip(
+    const UnsafeBufferUsageEntitySummary &S,
+    std::function<uint64_t(EntityId)> IdToIntFn,
+    std::function<llvm::Expected<EntityId>(uint64_t)> IdFromIntFn);
+
+} // namespace clang::ssaf
+
+#endif // 
LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGETEST_H

diff  --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h 
b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
index 1dc50c9c58dd8..2030dc8a12030 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
@@ -32,6 +32,10 @@ extern volatile int SSAFAnalysisRegistryAnchorSource;
 [[maybe_unused]] static int SSAFAnalysisRegistryAnchorDestination =
     SSAFAnalysisRegistryAnchorSource;
 
+extern volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource;
+[[maybe_unused]] static int UnsafeBufferUsageSSAFJSONFormatAnchorDestination =
+    UnsafeBufferUsageSSAFJSONFormatAnchorSource;
+
 // This anchor is used to force the linker to link the CallGraphExtractor.
 extern volatile int CallGraphExtractorAnchorSource;
 [[maybe_unused]] static int CallGraphExtractorAnchorDestination =

diff  --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
index df8079a7d375d..926b610aa8dee 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
@@ -2,9 +2,10 @@ set(LLVM_LINK_COMPONENTS
   Support
   )
 
-add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
+add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses 
   CallGraph/CallGraphExtractor.cpp
   CallGraph/CallGraphJSONFormat.cpp
+  UnsafeBufferUsage/UnsafeBufferUsage.cpp
   UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
 
   LINK_LIBS

diff  --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
new file mode 100644
index 0000000000000..d325e8df79c20
--- /dev/null
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
@@ -0,0 +1,123 @@
+//===- UnsafeBufferUsage.cpp 
----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include 
"clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include 
"clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include 
"clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/JSON.h"
+#include <cstdint>
+
+using namespace clang;
+using namespace ssaf;
+using Array = llvm::json::Array;
+using Object = llvm::json::Object;
+
+static constexpr llvm::StringLiteral SummarySerializationKey = "UnsafeBuffers";
+
+EntityPointerLevel ssaf::buildEntityPointerLevel(EntityId Id, unsigned PtrLv) {
+  return EntityPointerLevel(Id, PtrLv);
+}
+
+UnsafeBufferUsageEntitySummary
+ssaf::buildUnsafeBufferUsageEntitySummary(EntityPointerLevelSet UnsafeBuffers) 
{
+  return UnsafeBufferUsageEntitySummary(std::move(UnsafeBuffers));
+}
+
+llvm::iterator_range<EntityPointerLevelSet::const_iterator>
+ssaf::getUnsafeBuffers(const UnsafeBufferUsageEntitySummary &S) {
+  return llvm::make_range(S.UnsafeBuffers.begin(), S.UnsafeBuffers.end());
+}
+
+static Object serialize(const EntitySummary &S,
+                        JSONFormat::EntityIdToJSONFn Fn) {
+  const auto &SS = static_cast<const UnsafeBufferUsageEntitySummary &>(S);
+  Array UnsafeBuffersData;
+
+  for (const auto &EPL : getUnsafeBuffers(SS))
+    UnsafeBuffersData.push_back(
+        Array{Fn(EPL.getEntity()), EPL.getPointerLevel()});
+  return Object{{SummarySerializationKey.data(), 
std::move(UnsafeBuffersData)}};
+}
+
+static llvm::Expected<std::unique_ptr<EntitySummary>>
+deserializeImpl(const Object &Data, JSONFormat::EntityIdFromJSONFn Fn) {
+  const Array *UnsafeBuffersData =
+      Data.getArray(SummarySerializationKey.data());
+
+  if (!UnsafeBuffersData)
+    return llvm::createStringError("expected a json::Object with a key %s",
+                                   SummarySerializationKey.data());
+
+  EntityPointerLevelSet EPLs;
+
+  for (const auto &EltData : *UnsafeBuffersData) {
+    const Array *EltDataAsArr = EltData.getAsArray();
+
+    if (!EltDataAsArr || EltDataAsArr->size() != 2)
+      return llvm::createStringError("expected a json::Array of size 2");
+
+    const Object *IdData = (*EltDataAsArr)[0].getAsObject();
+    std::optional<uint64_t> PtrLvData = (*EltDataAsArr)[1].getAsInteger();
+
+    if (!IdData || !PtrLvData)
+      return llvm::createStringError("expected a json::Value of integer type");
+
+    llvm::Expected<EntityId> Id = Fn(*IdData);
+
+    if (!Id)
+      return Id.takeError();
+    EPLs.insert(buildEntityPointerLevel(Id.get(), *PtrLvData));
+  }
+  return std::make_unique<UnsafeBufferUsageEntitySummary>(
+      buildUnsafeBufferUsageEntitySummary(std::move(EPLs)));
+}
+
+static llvm::Expected<std::unique_ptr<EntitySummary>>
+deserialize(const Object &Data, EntityIdTable &,
+            JSONFormat::EntityIdFromJSONFn Fn) {
+  return deserializeImpl(Data, Fn);
+}
+
+struct UnsafeBufferUsageJSONFormatInfo : JSONFormat::FormatInfo {
+  UnsafeBufferUsageJSONFormatInfo()
+      : JSONFormat::FormatInfo(UnsafeBufferUsageEntitySummary::summaryName(),
+                               serialize, deserialize) {}
+};
+
+static llvm::Registry<JSONFormat::FormatInfo>::Add<
+    UnsafeBufferUsageJSONFormatInfo>
+    RegisterUnsafeBufferUsageJSONFormatInfo(
+        UnsafeBufferUsageEntitySummary::Name,
+        "JSON Format info for UnsafeBufferUsageEntitySummary");
+
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource = 0;
+
+// For unit test:
+llvm::Expected<std::unique_ptr<EntitySummary>>
+ssaf::serializeDeserializeRoundTrip(
+    const UnsafeBufferUsageEntitySummary &S,
+    std::function<uint64_t(EntityId)> IdToIntFn,
+    std::function<llvm::Expected<EntityId>(uint64_t)> IdFromIntFn) {
+
+  auto IdToJson = [&IdToIntFn](EntityId Id) -> Object {
+    return Object({{"@", IdToIntFn(Id)}});
+  };
+  auto IdFromJson =
+      [&IdFromIntFn](const Object &O) -> llvm::Expected<EntityId> {
+    const auto *Int = O.get("@");
+
+    if (Int && Int->getAsUINT64())
+      return IdFromIntFn(*Int->getAsUINT64());
+    return llvm::createStringError("failed to get EntityId from Object");
+  };
+
+  return deserializeImpl(serialize(S, IdToJson), IdFromJson);
+}

diff  --git a/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt 
b/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
index b90d9c0ded1a9..3da1558810572 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangScalableStaticAnalysisFrameworkFrontend
   clangAST
   clangBasic
   clangFrontend
+  clangScalableStaticAnalysisFrameworkAnalyses
   clangScalableStaticAnalysisFrameworkCore
   clangSema
   )

diff  --git 
a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
new file mode 100644
index 0000000000000..10d8c9457aaeb
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
@@ -0,0 +1,53 @@
+{
+  "data": [
+    {
+      "summary_data": [
+        {
+          "entity_id": 2,
+          "entity_summary": {
+            "UnsafeBuffers": [
+              42
+            ]
+          }
+        }
+      ],
+      "summary_name": "UnsafeBufferUsage"
+    }
+  ],
+  "id_table": [
+    {
+      "id": 2,
+      "name": {
+        "namespace": [],
+        "suffix": "",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    },
+    {
+      "id": 0,
+      "name": {
+        "namespace": [],
+        "suffix": "1",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "External"
+      }
+    },
+    {
+      "id": 2,
+      "linkage": {
+        "type": "Internal"
+      }
+    }
+  ],
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "Mock.cpp"
+  }
+}

diff  --git 
a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
new file mode 100644
index 0000000000000..6b59ff39e6913
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
@@ -0,0 +1,58 @@
+{
+  "data": [
+    {
+      "summary_data": [
+        {
+          "entity_id": 2,
+          "entity_summary": {
+            "UnsafeBuffers": [
+              [
+                {
+                  "@": 0
+                },
+                "not-an-integer"
+              ]
+            ]
+          }
+        }
+      ],
+      "summary_name": "UnsafeBufferUsage"
+    }
+  ],
+  "id_table": [
+    {
+      "id": 2,
+      "name": {
+        "namespace": [],
+        "suffix": "",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    },
+    {
+      "id": 0,
+      "name": {
+        "namespace": [],
+        "suffix": "1",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "External"
+      }
+    },
+    {
+      "id": 2,
+      "linkage": {
+        "type": "Internal"
+      }
+    }
+  ],
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "Mock.cpp"
+  }
+}

diff  --git 
a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
new file mode 100644
index 0000000000000..555070ce3e660
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
@@ -0,0 +1,58 @@
+{
+  "data": [
+    {
+      "summary_data": [
+        {
+          "entity_id": 2,
+          "entity_summary": {
+            "NotUnsafeBuffers": [
+              [
+                {
+                  "@": 0
+                },
+                1
+              ]
+            ]
+          }
+        }
+      ],
+      "summary_name": "UnsafeBufferUsage"
+    }
+  ],
+  "id_table": [
+    {
+      "id": 2,
+      "name": {
+        "namespace": [],
+        "suffix": "",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    },
+    {
+      "id": 0,
+      "name": {
+        "namespace": [],
+        "suffix": "1",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "External"
+      }
+    },
+    {
+      "id": 2,
+      "linkage": {
+        "type": "Internal"
+      }
+    }
+  ],
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "Mock.cpp"
+  }
+}

diff  --git 
a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
new file mode 100644
index 0000000000000..382b294ccc7bd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
@@ -0,0 +1,108 @@
+{
+  "data": [
+    {
+      "summary_data": [
+        {
+          "entity_id": 2,
+          "entity_summary": {
+            "UnsafeBuffers": [
+              [
+                {
+                  "@": 0
+                },
+                1
+              ],
+              [
+                {
+                  "@": 0
+                },
+                2
+              ],
+              [
+                {
+                  "@": 0
+                },
+                3
+              ],
+              [
+                {
+                  "@": 1
+                },
+                1
+              ],
+              [
+                {
+                  "@": 1
+                },
+                2
+              ],
+              [
+                {
+                  "@": 1
+                },
+                3
+              ],
+              [
+                {
+                  "@": 1
+                },
+                4
+              ]
+            ]
+          }
+        }
+      ],
+      "summary_name": "UnsafeBufferUsage"
+    }
+  ],
+  "id_table": [
+    {
+      "id": 2,
+      "name": {
+        "namespace": [],
+        "suffix": "",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    },
+    {
+      "id": 0,
+      "name": {
+        "namespace": [],
+        "suffix": "1",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    },
+    {
+      "id": 1,
+      "name": {
+        "namespace": [],
+        "suffix": "2",
+        "usr": "c:@F@foo#***I#*S0_#I#"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "External"
+      }
+    },
+    {
+      "id": 1,
+      "linkage": {
+        "type": "Internal"
+      }
+    },
+    {
+      "id": 2,
+      "linkage": {
+        "type": "Internal"
+      }
+    }
+  ],
+  "tu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "Mock.cpp"
+  }
+}

diff  --git 
a/clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test
new file mode 100644
index 0000000000000..6a12949f3bbb4
--- /dev/null
+++ 
b/clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t.json
+// RUN: clang-ssaf-format -type=tu  %S/Inputs/tu-summary.json -o %t.json
+// RUN: 
diff  %S/Inputs/tu-summary.json %t.json
+
+// Negative tests:
+
+// RUN: not clang-ssaf-format -type=tu %S/Inputs/tu-summary-no-key.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-KEY
+// CHECK-NO-KEY: expected a json::Object with a key UnsafeBuffers
+
+
+// RUN: not clang-ssaf-format -type=tu %S/Inputs/tu-summary-bad-element.json 
2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-BAD-ELEMENT
+// CHECK-BAD-ELEMENT: expected a json::Array of size 2
+
+// RUN: not clang-ssaf-format -type=tu %S/Inputs/tu-summary-bad-ptr-level.json 
2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-BAD-PTR-LEVEL
+// CHECK-BAD-PTR-LEVEL: expected a json::Value of integer type

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/list.test 
b/clang/test/Analysis/Scalable/ssaf-format/list.test
index ffc1624c5872a..82811a97c40c5 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/list.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/list.test
@@ -7,4 +7,5 @@
 // CHECK-EMPTY:
 // CHECK-DAG: [[NthFormat:[0-9]+]]. json - JSON serialization format
 // CHECK-DAG:     Analyses:
-// CHECK-DAG:         [[NthFormat]].[[MthSummary:[0-9]+]]. CallGraph - JSON 
Format info for CallGraph summary
+// CHECK-DAG:         [[NthFormat]].{{[0-9]+}}. CallGraph - JSON Format info 
for CallGraph summary
+// CHECK-DAG:         [[NthFormat]].{{[0-9]+}}. UnsafeBufferUsage - JSON 
Format info for UnsafeBufferUsageEntitySummary

diff  --git 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
index 3555f5196a7b9..51d422c1921af 100644
--- 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
@@ -7,17 +7,25 @@
 
//===----------------------------------------------------------------------===//
 
 #include 
"clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "TestFixture.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/Frontend/ASTUnit.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h"
+#include 
"clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Testing/Support/Error.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include <memory>
+#include <optional>
 
 using namespace clang;
 using namespace ssaf;
@@ -58,7 +66,7 @@ const FunctionDecl *findFnByName(StringRef Name, ASTContext 
&Ctx) {
 constexpr inline auto buildEntityPointerLevel =
     UnsafeBufferUsageTUSummaryExtractor::buildEntityPointerLevel;
 
-class UnsafeBufferUsageTest : public testing::Test {
+class UnsafeBufferUsageTest : public TestFixture {
 protected:
   TUSummary TUSum;
   TUSummaryBuilder Builder;
@@ -184,6 +192,52 @@ TEST_F(UnsafeBufferUsageTest, 
UnsafeBufferUsageEntityPointerLevelSetTest) {
   EXPECT_THAT(getSubsetOf(Set, E3), UnorderedElementsAre(P5));
 }
 
+//////////////////////////////////////////////////////////////
+//   (De-)Serialization Tests                               //
+//////////////////////////////////////////////////////////////
+
+TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageSerializeTest) {
+  auto Sum = setUpTest(R"cpp(
+    void foo(int ***p, int ****q, int x) {
+      p[5][5][5];
+      q[5][5][5][5];
+    }
+  )cpp",
+                       "foo");
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U},
+                                     {"p", 2U},
+                                     {"p", 3U},
+                                     {"q", 1U},
+                                     {"q", 2U},
+                                     {"q", 3U},
+                                     {"q", 4U}}));
+
+  std::function<uint64_t(EntityId)> IdToIntFn = [](EntityId Id) -> uint64_t {
+    return getIndex(Id);
+  };
+  std::function<llvm::Expected<EntityId>(uint64_t)> IdFromIntFn =
+      [this](uint64_t Int) -> llvm::Expected<EntityId> {
+    std::optional<EntityId> Result = std::nullopt;
+
+    getIdTable(TUSum).forEach([&Int, &Result](const EntityName &, EntityId Id) 
{
+      if (getIndex(Id) == Int)
+        Result = Id;
+    });
+    if (Result)
+      return *Result;
+    return llvm::createStringError("failed to convert %d to an EntityId", Int);
+  };
+
+  auto RoundTripResult =
+      serializeDeserializeRoundTrip(*Sum, IdToIntFn, IdFromIntFn);
+
+  EXPECT_THAT_ERROR(RoundTripResult.takeError(), llvm::Succeeded());
+  ASSERT_NE(*RoundTripResult, nullptr);
+  EXPECT_EQ(*Sum, *static_cast<const UnsafeBufferUsageEntitySummary *>(
+                      RoundTripResult->get()));
+}
+
 //////////////////////////////////////////////////////////////
 //                   Extractor Tests                        //
 //////////////////////////////////////////////////////////////


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

Reply via email to