llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-ssaf

Author: Balázs Benics (steakhal)

<details>
<summary>Changes</summary>

rdar://170258016

---
Full diff: https://github.com/llvm/llvm-project/pull/189681.diff


10 Files Affected:

- (modified) 
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h
 (+2-1) 
- (modified) 
clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h 
(+5) 
- (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt 
(+1) 
- (modified) 
clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
 (+2-1) 
- (added) 
clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphJSONFormat.cpp
 (+142) 
- (modified) 
clang/lib/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendAction.cpp
 (+4) 
- (added) clang/test/Analysis/Scalable/call-graph.cpp (+20) 
- (modified) clang/test/Analysis/Scalable/ssaf-format/list.test (+4-3) 
- (modified) 
clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp
 (+5-3) 
- (modified) 
llvm/utils/gn/secondary/clang/lib/ScalableStaticAnalysisFramework/Analyses/BUILD.gn
 (+1) 


``````````diff
diff --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h
index ad70218d01614..8056b1001a216 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h
@@ -30,8 +30,9 @@ struct CallGraphSummary final : public EntitySummary {
     unsigned Column;
   };
 
+  static constexpr llvm::StringLiteral Name = "CallGraph";
   SummaryName getSummaryName() const override {
-    return SummaryName("CallGraph");
+    return SummaryName(Name.str());
   }
 
   /// Represents the location of the function.
diff --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h 
b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
index 707573ce34e46..1dc50c9c58dd8 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
@@ -37,4 +37,9 @@ extern volatile int CallGraphExtractorAnchorSource;
 [[maybe_unused]] static int CallGraphExtractorAnchorDestination =
     CallGraphExtractorAnchorSource;
 
+// This anchor is used to force the linker to link the CallGraph JSON format.
+extern volatile int CallGraphJSONFormatAnchorSource;
+[[maybe_unused]] static int CallGraphJSONFormatAnchorDestination =
+    CallGraphJSONFormatAnchorSource;
+
 #endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SSAFBUILTINFORCELINKER_H
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
index 2dcce40f886dd..df8079a7d375d 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
   CallGraph/CallGraphExtractor.cpp
+  CallGraph/CallGraphJSONFormat.cpp
   UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
 
   LINK_LIBS
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
index b2cd2e40f33b5..1dbed7e0b0d8a 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
@@ -98,7 +98,8 @@ void CallGraphExtractor::handleCallGraphNode(const ASTContext 
&Ctx,
 }
 
 static TUSummaryExtractorRegistry::Add<CallGraphExtractor>
-    RegisterExtractor("CallGraph", "Extracts static call-graph information");
+    RegisterExtractor(CallGraphSummary::Name,
+                      "Extracts static call-graph information");
 
 // This anchor is used to force the linker to link in the generated object file
 // and thus register the CallGraphExtractor.
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphJSONFormat.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphJSONFormat.cpp
new file mode 100644
index 0000000000000..33da0ab0bd205
--- /dev/null
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphJSONFormat.cpp
@@ -0,0 +1,142 @@
+//===- CallGraphJSONFormat.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/CallGraph/CallGraphSummary.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include 
"clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/JSON.h"
+#include <memory>
+
+using namespace llvm;
+using namespace clang;
+using namespace ssaf;
+
+static json::Object serialize(const EntitySummary &Summary,
+                              JSONFormat::EntityIdToJSONFn ToJSON) {
+  const auto &S = static_cast<const CallGraphSummary &>(Summary);
+
+  json::Array DirectCalleesArray;
+  DirectCalleesArray.reserve(S.DirectCallees.size());
+  append_range(DirectCalleesArray, map_range(S.DirectCallees, ToJSON));
+
+  json::Array VirtualCalleesArray;
+  VirtualCalleesArray.reserve(S.VirtualCallees.size());
+  append_range(VirtualCalleesArray, map_range(S.VirtualCallees, ToJSON));
+
+  return json::Object{
+      {"pretty_name", json::Value(S.PrettyName)},
+      {"direct_callees", std::move(DirectCalleesArray)},
+      {"virtual_callees", std::move(VirtualCalleesArray)},
+      {"def",
+       json::Object{
+           {"file", json::Value(S.Definition.File)},
+           {"line", json::Value(S.Definition.Line)},
+           {"col", json::Value(S.Definition.Column)},
+       }},
+  };
+}
+
+static Expected<std::unique_ptr<EntitySummary>>
+deserialize(const json::Object &Obj, EntityIdTable &IdTable,
+            JSONFormat::EntityIdFromJSONFn FromJSON) {
+  auto Result = std::make_unique<CallGraphSummary>();
+
+  auto PrettyName = Obj.getString("pretty_name");
+  if (!PrettyName) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'pretty_name'");
+  }
+  Result->PrettyName = PrettyName->str();
+
+  const json::Array *CalleesArray = Obj.getArray("direct_callees");
+  if (!CalleesArray) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'direct_callees'");
+  }
+  for (const auto &[Index, Value] : llvm::enumerate(*CalleesArray)) {
+    const json::Object *CalleeObj = Value.getAsObject();
+    if (!CalleeObj) {
+      return createStringError(
+          inconvertibleErrorCode(),
+          "direct_callees element at index %zu is not a JSON object", Index);
+    }
+    auto ExpectedId = FromJSON(*CalleeObj);
+    if (!ExpectedId) {
+      return createStringError(
+          inconvertibleErrorCode(),
+          "invalid entity id in direct_callees at index %zu: %s", Index,
+          toString(ExpectedId.takeError()).c_str());
+    }
+    Result->DirectCallees.insert(*ExpectedId);
+  }
+
+  const json::Array *VirtualCalleesArray = Obj.getArray("virtual_callees");
+  if (!VirtualCalleesArray) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'virtual_callees'");
+  }
+  for (const auto &[Index, Value] : llvm::enumerate(*VirtualCalleesArray)) {
+    const json::Object *CalleeObj = Value.getAsObject();
+    if (!CalleeObj) {
+      return createStringError(
+          inconvertibleErrorCode(),
+          "virtual_callees element at index %zu is not a JSON object", Index);
+    }
+    auto ExpectedId = FromJSON(*CalleeObj);
+    if (!ExpectedId) {
+      return createStringError(
+          inconvertibleErrorCode(),
+          "invalid entity id in virtual_callees at index %zu: %s", Index,
+          toString(ExpectedId.takeError()).c_str());
+    }
+    Result->VirtualCallees.insert(*ExpectedId);
+  }
+
+  const json::Object *DefObj = Obj.getObject("def");
+  if (!DefObj) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'def'");
+  }
+  auto File = DefObj->getString("file");
+  if (!File) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'def.file'");
+  }
+  auto Line = DefObj->getInteger("line");
+  if (!Line) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'def.line'");
+  }
+  auto Col = DefObj->getInteger("col");
+  if (!Col) {
+    return createStringError(inconvertibleErrorCode(),
+                             "missing or invalid field 'def.col'");
+  }
+  Result->Definition = {File->str(), static_cast<unsigned>(*Line),
+                        static_cast<unsigned>(*Col)};
+
+  return std::move(Result);
+}
+
+namespace {
+struct CallGraphJSONFormatInfo final : JSONFormat::FormatInfo {
+  CallGraphJSONFormatInfo()
+      : JSONFormat::FormatInfo(SummaryName(CallGraphSummary::Name.str()),
+                               serialize, deserialize) {}
+};
+} // namespace
+
+static llvm::Registry<JSONFormat::FormatInfo>::Add<CallGraphJSONFormatInfo>
+    RegisterFormatInfo(CallGraphSummary::Name,
+                       "JSON Format info for CallGraph summary");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSON format for CallGraphSummary.
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int CallGraphJSONFormatAnchorSource = 0;
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendAction.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendAction.cpp
index 9a75b20fa548b..d4bf8d4a63fa4 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendAction.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendAction.cpp
@@ -17,6 +17,7 @@
 #include 
"clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/IOSandbox.h"
 #include "llvm/Support/Path.h"
 #include <memory>
 #include <string>
@@ -150,6 +151,9 @@ void TUSummaryRunner::HandleTranslationUnit(ASTContext 
&Ctx) {
   // First, invoke the Summary Extractors.
   MultiplexConsumer::HandleTranslationUnit(Ctx);
 
+  // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
+  llvm::sys::sandbox::ScopedSetting Guard = 
llvm::sys::sandbox::scopedDisable();
+
   // Then serialize the result.
   if (auto Err = Format->writeTUSummary(Summary, Opts.SSAFTUSummaryFile)) {
     Ctx.getDiagnostics().Report(diag::warn_ssaf_write_tu_summary_failed)
diff --git a/clang/test/Analysis/Scalable/call-graph.cpp 
b/clang/test/Analysis/Scalable/call-graph.cpp
new file mode 100644
index 0000000000000..b6e7ce91ee8c7
--- /dev/null
+++ b/clang/test/Analysis/Scalable/call-graph.cpp
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t.summary.json
+// RUN: %clang_cc1 -fsyntax-only %s \
+// RUN:   --ssaf-extract-summaries=CallGraph \
+// RUN:   --ssaf-tu-summary-file=%t.summary.json
+
+// Check that the JSON validation passes.
+// TODO: Enable the next line once the LinkageTable is populated.
+// R U N: clang-ssaf-format --type=tu %t.summary.json
+
+// Check that the JSON has plausible content irrespective of the order of the 
fields.
+// RUN: FileCheck %s --match-full-lines --input-file=%t.summary.json
+//   CHECK-DAG: "direct_callees": [
+//   CHECK-DAG: "pretty_name": "example()",
+//   CHECK-DAG: "virtual_callees": []
+//   CHECK-DAG: "summary_name": "CallGraph"
+
+void no_body();
+void example() {
+  no_body();
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/list.test 
b/clang/test/Analysis/Scalable/ssaf-format/list.test
index a21d1543915f7..ffc1624c5872a 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/list.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/list.test
@@ -1,9 +1,10 @@
 // Test clang-ssaf-format --list output without any loaded plugins.
 
 // RUN: clang-ssaf-format --list \
-// RUN:   | FileCheck %s
+// RUN:   | FileCheck %s --match-full-lines
 
 // CHECK: Registered serialization formats:
 // CHECK-EMPTY:
-// CHECK-NEXT:   1. json - JSON serialization format
-// CHECK-NEXT:      Analyses: (none)
+// 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
diff --git 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp
 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp
index 9e0b9e6e256a4..2557c7a62479e 100644
--- 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp
@@ -120,6 +120,8 @@ template <typename... Matchers> auto hasSummaryThat(const 
Matchers &...Ms) {
 // Test fixture
 // ============================================================================
 
+static const SummaryName CallGraphName{CallGraphSummary::Name.str()};
+
 struct CallGraphExtractorTest : ssaf::TestFixture {
   TUSummary Summary =
       BuildNamespace(BuildNamespaceKind::CompilationUnit, "Mock.cpp");
@@ -129,7 +131,7 @@ struct CallGraphExtractorTest : ssaf::TestFixture {
   /// This will update the \c AST \c Builder and \c Summary data members.
   void runExtractor(StringRef Code, ArrayRef<std::string> Args = {}) {
     AST = tooling::buildASTFromCodeWithArgs(Code, Args);
-    auto Consumer = makeTUSummaryExtractor("CallGraph", Builder);
+    auto Consumer = makeTUSummaryExtractor(CallGraphName.str(), Builder);
     Consumer->HandleTranslationUnit(AST->getASTContext());
   }
 
@@ -207,7 +209,7 @@ CallGraphExtractorTest::findSummary(llvm::StringRef FnName) 
const {
   }
   EntityId ID = It->second;
   auto &Data = getData(Summary);
-  auto SummaryIt = Data.find(SummaryName("CallGraph"));
+  auto SummaryIt = Data.find(CallGraphName);
   if (SummaryIt == Data.end())
     return llvm::createStringError("There is no 'CallGraph' summary");
   auto EntityIt = SummaryIt->second.find(ID);
@@ -343,7 +345,7 @@ TEST_F(CallGraphExtractorTest, DeclarationsOnlyNoSummary) {
   )cpp");
 
   // No summary for functions without definitions.
-  EXPECT_FALSE(llvm::is_contained(getData(Summary), SummaryName("CallGraph")));
+  EXPECT_FALSE(llvm::is_contained(getData(Summary), CallGraphName));
 }
 
 TEST_F(CallGraphExtractorTest, DuplicateCallees) {
diff --git 
a/llvm/utils/gn/secondary/clang/lib/ScalableStaticAnalysisFramework/Analyses/BUILD.gn
 
b/llvm/utils/gn/secondary/clang/lib/ScalableStaticAnalysisFramework/Analyses/BUILD.gn
index ac62574ad8534..1450d8866b71f 100644
--- 
a/llvm/utils/gn/secondary/clang/lib/ScalableStaticAnalysisFramework/Analyses/BUILD.gn
+++ 
b/llvm/utils/gn/secondary/clang/lib/ScalableStaticAnalysisFramework/Analyses/BUILD.gn
@@ -10,6 +10,7 @@ static_library("Analyses") {
   ]
   sources = [
     "CallGraph/CallGraphExtractor.cpp",
+    "CallGraph/CallGraphJSONFormat.cpp",
     "UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp",
   ]
 }

``````````

</details>


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

Reply via email to