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
24ssaf::PointerFlowEntitySummary
25ssaf::buildPointerFlowEntitySummary(EdgeSet Edges);
26
27llvm::iterator_range<EdgeSet::const_iterator>
28ssaf::getEdges(const PointerFlowEntitySummary &Sum);
29
30namespace {
31constexpr const char *const PointerFlowKey = "PointerFlow";
32} // namespace
33
34// Writes an EdgeSet as an array of arrays of EntityPointerLevels:
35// [
36// [ [src-node], [dest-node], [dest-node], ...],
37// [ [src-node], [dest-node], [dest-node], ...],
38// ...
39// ]
40Array clang::ssaf::edgeSetToJSON(
41 llvm::iterator_range<EdgeSet::const_iterator> Edges,
42 JSONFormat::EntityIdToJSONFn EntityId2JSON) {
43 Array EdgesData;
44
45 for (const auto &[LHS, RHSSet] : Edges) {
46 Array EdgeEntry;
47 EdgeEntry.push_back(E: entityPointerLevelToJSON(EPL: LHS, EntityId2JSON));
48 for (const auto &RHS : RHSSet)
49 EdgeEntry.push_back(E: entityPointerLevelToJSON(EPL: RHS, EntityId2JSON));
50 EdgesData.push_back(E: Value(std::move(EdgeEntry)));
51 }
52 return EdgesData;
53}
54
55llvm::Expected<EdgeSet>
56clang::ssaf::edgeSetFromJSON(const Array &EdgesData,
57 JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
58 EdgeSet Edges;
59
60 for (const auto &EdgesEntryData : EdgesData) {
61 const auto *EPLArray = EdgesEntryData.getAsArray();
62
63 if (!EPLArray || EPLArray->size() <= 1)
64 return makeSawButExpectedError(
65 Saw: EdgesEntryData, Expected: "a JSON array of EntityPointerLevels with a size "
66 "greater than 1: [src, dest, dest, ...]");
67
68 auto SrcEPL =
69 entityPointerLevelFromJSON(EPLData: *EPLArray->begin(), EntityIdFromJSON);
70
71 if (!SrcEPL)
72 return SrcEPL.takeError();
73 for (const auto &EPLData :
74 llvm::make_range(x: EPLArray->begin() + 1, y: EPLArray->end())) {
75 auto EPL = entityPointerLevelFromJSON(EPLData, EntityIdFromJSON);
76 if (!EPL)
77 return EPL.takeError();
78 Edges[*SrcEPL].insert(x: *EPL);
79 }
80 }
81 return Edges;
82}
83
84static llvm::json::Object
85summaryToJSON(const EntitySummary &ES,
86 JSONFormat::EntityIdToJSONFn EntityId2JSON) {
87 Object Data;
88 Data[PointerFlowKey] = Value(
89 edgeSetToJSON(Edges: getEdges(Sum: static_cast<const PointerFlowEntitySummary &>(ES)),
90 EntityId2JSON));
91 return Data;
92}
93
94static llvm::Expected<std::unique_ptr<EntitySummary>>
95summaryFromJSON(const Object &Data, EntityIdTable &,
96 JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
97 const Value *EdgesData = Data.get(K: PointerFlowKey);
98
99 if (!EdgesData)
100 return makeSawButExpectedError(
101 Saw: Object(Data), Expected: "a JSON object with the key: %s", ExpectedArgs: PointerFlowKey);
102
103 const auto *EdgesDataAsArr = EdgesData->getAsArray();
104
105 if (!EdgesDataAsArr)
106 return makeSawButExpectedError(
107 Saw: *EdgesData, Expected: "a JSON array of array of EntityPointerLevels");
108
109 auto Edges = edgeSetFromJSON(EdgesData: *EdgesDataAsArr, EntityIdFromJSON);
110
111 if (!Edges)
112 return Edges.takeError();
113 return std::make_unique<PointerFlowEntitySummary>(
114 args: buildPointerFlowEntitySummary(Edges: std::move(*Edges)));
115}
116
117namespace {
118struct PointerFlowJSONFormatInfo final : JSONFormat::FormatInfo {
119 PointerFlowJSONFormatInfo()
120 : JSONFormat::FormatInfo(PointerFlowEntitySummary::summaryName(),
121 summaryToJSON, summaryFromJSON) {}
122};
123} // namespace
124
125static llvm::Registry<JSONFormat::FormatInfo>::Add<PointerFlowJSONFormatInfo>
126 RegisterPointerFlowJSONFormatInfo(
127 "PointerFlow", "JSON Format info for PointerFlowEntitySummary");
128
129namespace clang::ssaf {
130// NOLINTNEXTLINE(misc-use-internal-linkage)
131volatile int PointerFlowJSONFormatAnchorSource = 0;
132} // namespace clang::ssaf
133