1//===- PointerFlowFormat.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlowFormat.h"
10#include "SSAFAnalysesCommon.h"
11#include "clang/ScalableStaticAnalysis/Analyses/EntityPointerLevel/EntityPointerLevelFormat.h"
12#include "clang/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlow.h"
13#include "clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h"
14#include "llvm/ADT/iterator_range.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/JSON.h"
17
18using namespace clang;
19using namespace ssaf;
20using Object = llvm::json::Object;
21using Array = llvm::json::Array;
22using Value = llvm::json::Value;
23
24namespace {
25constexpr const char *const PointerFlowKey = "PointerFlow";
26} // namespace
27
28// Writes an EdgeSet as an array of arrays of EntityPointerLevels:
29// [
30// [ [src-node], [dest-node], [dest-node], ...],
31// [ [src-node], [dest-node], [dest-node], ...],
32// ...
33// ]
34Array clang::ssaf::edgeSetToJSON(
35 llvm::iterator_range<EdgeSet::const_iterator> Edges,
36 JSONFormat::EntityIdToJSONFn EntityId2JSON) {
37 Array EdgesData;
38
39 for (const auto &[LHS, RHSSet] : Edges) {
40 Array EdgeEntry;
41 EdgeEntry.push_back(E: entityPointerLevelToJSON(EPL: LHS, EntityId2JSON));
42 for (const auto &RHS : RHSSet)
43 EdgeEntry.push_back(E: entityPointerLevelToJSON(EPL: RHS, EntityId2JSON));
44 EdgesData.push_back(E: Value(std::move(EdgeEntry)));
45 }
46 return EdgesData;
47}
48
49llvm::Expected<EdgeSet>
50clang::ssaf::edgeSetFromJSON(const Array &EdgesData,
51 JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
52 EdgeSet Edges;
53
54 for (const auto &EdgesEntryData : EdgesData) {
55 const auto *EPLArray = EdgesEntryData.getAsArray();
56
57 if (!EPLArray || EPLArray->size() <= 1)
58 return makeSawButExpectedError(
59 Saw: EdgesEntryData, Expected: "a JSON array of EntityPointerLevels with a size "
60 "greater than 1: [src, dest, dest, ...]");
61
62 auto SrcEPL =
63 entityPointerLevelFromJSON(EPLData: *EPLArray->begin(), EntityIdFromJSON);
64
65 if (!SrcEPL)
66 return SrcEPL.takeError();
67 for (const auto &EPLData :
68 llvm::make_range(x: EPLArray->begin() + 1, y: EPLArray->end())) {
69 auto EPL = entityPointerLevelFromJSON(EPLData, EntityIdFromJSON);
70 if (!EPL)
71 return EPL.takeError();
72 Edges[*SrcEPL].insert(x: *EPL);
73 }
74 }
75 return Edges;
76}
77
78static llvm::json::Object
79summaryToJSON(const EntitySummary &ES,
80 JSONFormat::EntityIdToJSONFn EntityId2JSON) {
81 Object Data;
82 Data[PointerFlowKey] = Value(
83 edgeSetToJSON(Edges: getEdges(static_cast<const PointerFlowEntitySummary &>(ES)),
84 EntityId2JSON));
85 return Data;
86}
87
88static llvm::Expected<std::unique_ptr<EntitySummary>>
89summaryFromJSON(const Object &Data, EntityIdTable &,
90 JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
91 const Value *EdgesData = Data.get(K: PointerFlowKey);
92
93 if (!EdgesData)
94 return makeSawButExpectedError(
95 Saw: Object(Data), Expected: "a JSON object with the key: %s", ExpectedArgs: PointerFlowKey);
96
97 const auto *EdgesDataAsArr = EdgesData->getAsArray();
98
99 if (!EdgesDataAsArr)
100 return makeSawButExpectedError(
101 Saw: *EdgesData, Expected: "a JSON array of array of EntityPointerLevels");
102
103 auto Edges = edgeSetFromJSON(EdgesData: *EdgesDataAsArr, EntityIdFromJSON);
104
105 if (!Edges)
106 return Edges.takeError();
107 return std::make_unique<PointerFlowEntitySummary>(
108 args: buildPointerFlowEntitySummary(Edges: std::move(*Edges)));
109}
110
111namespace {
112struct PointerFlowJSONFormatInfo final : JSONFormat::FormatInfo {
113 PointerFlowJSONFormatInfo()
114 : JSONFormat::FormatInfo(PointerFlowEntitySummary::summaryName(),
115 summaryToJSON, summaryFromJSON) {}
116};
117} // namespace
118
119static llvm::Registry<JSONFormat::FormatInfo>::Add<PointerFlowJSONFormatInfo>
120 RegisterPointerFlowJSONFormatInfo(
121 "PointerFlow", "JSON Format info for PointerFlowEntitySummary");
122
123namespace clang::ssaf {
124// NOLINTNEXTLINE(misc-use-internal-linkage)
125volatile int PointerFlowJSONFormatAnchorSource = 0;
126} // namespace clang::ssaf
127