1//===- WPASuite.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 "JSONFormatImpl.h"
10
11#include "clang/ScalableStaticAnalysis/Core/WholeProgramAnalysis/WPASuite.h"
12
13namespace clang::ssaf {
14
15//----------------------------------------------------------------------------
16// AnalysisResultMapEntry
17//----------------------------------------------------------------------------
18
19llvm::Expected<std::pair<AnalysisName, std::unique_ptr<AnalysisResult>>>
20JSONFormat::analysisResultMapEntryFromJSON(const Object &Entry) const {
21 auto OptName = Entry.getString(K: "analysis_name");
22 if (!OptName) {
23 return ErrorBuilder::create(EC: std::errc::invalid_argument,
24 Fmt: ErrorMessages::FailedToReadObjectAtField,
25 ArgVals: "AnalysisName", ArgVals: "analysis_name", ArgVals: "string")
26 .build();
27 }
28
29 AnalysisName Name = analysisNameFromJSON(AnalysisNameStr: *OptName);
30
31 auto ExpectedCodec = AnalysisResultRegistry::instantiate(Name);
32 if (!ExpectedCodec) {
33 return ExpectedCodec.takeError();
34 }
35
36 const Object *ResultObj = Entry.getObject(K: "result");
37 if (!ResultObj) {
38 return ErrorBuilder::create(EC: std::errc::invalid_argument,
39 Fmt: ErrorMessages::FailedToReadObjectAtField,
40 ArgVals: "AnalysisResult", ArgVals: "result", ArgVals: "object")
41 .build();
42 }
43
44 auto ExpectedResult =
45 (*ExpectedCodec)->deserialize(*ResultObj, &entityIdFromJSONObject);
46 if (!ExpectedResult) {
47 return ExpectedResult.takeError();
48 }
49
50 return std::make_pair(x: std::move(Name), y: std::move(*ExpectedResult));
51}
52
53llvm::Expected<Object> JSONFormat::analysisResultMapEntryToJSON(
54 const AnalysisName &Name,
55 const std::unique_ptr<AnalysisResult> &Result) const {
56 auto ExpectedCodec = AnalysisResultRegistry::instantiate(Name);
57 if (!ExpectedCodec) {
58 return ExpectedCodec.takeError();
59 }
60
61 Object Entry;
62 Entry["analysis_name"] = analysisNameToJSON(AN: Name);
63 Entry["result"] = (*ExpectedCodec)->serialize(*Result, &entityIdToJSONObject);
64 return Entry;
65}
66
67//----------------------------------------------------------------------------
68// AnalysisResultMap
69//----------------------------------------------------------------------------
70
71llvm::Expected<std::map<AnalysisName, std::unique_ptr<AnalysisResult>>>
72JSONFormat::analysisResultMapFromJSON(const Array &ResultsArray) const {
73 std::map<AnalysisName, std::unique_ptr<AnalysisResult>> Results;
74
75 auto AsObject = [](const Value &V) { return V.getAsObject(); };
76 auto ObjectsRange = llvm::map_range(C: ResultsArray, F: AsObject);
77
78 for (auto [I, Entry] : enumerate(First&: ObjectsRange)) {
79 if (!Entry) {
80 return ErrorBuilder::create(EC: std::errc::invalid_argument,
81 Fmt: ErrorMessages::FailedToReadObjectAtIndex,
82 ArgVals: "WPA result entry", ArgVals&: I, ArgVals: "object")
83 .build();
84 }
85
86 auto ExpectedPair = analysisResultMapEntryFromJSON(Entry: *Entry);
87 if (!ExpectedPair) {
88 return ErrorBuilder::wrap(E: ExpectedPair.takeError())
89 .context(Fmt: ErrorMessages::ReadingFromIndex, ArgVals: "WPA result entry", ArgVals&: I)
90 .build();
91 }
92
93 auto [Name, Result] = std::move(*ExpectedPair);
94 bool Inserted = Results.try_emplace(k: Name, args: std::move(Result)).second;
95 if (!Inserted) {
96 return ErrorBuilder::create(EC: std::errc::invalid_argument,
97 Fmt: ErrorMessages::FailedInsertionOnDuplication,
98 ArgVals: "WPA result", ArgVals&: I, ArgVals&: Name)
99 .build();
100 }
101 }
102 return std::move(Results);
103}
104
105llvm::Expected<Array> JSONFormat::analysisResultMapToJSON(
106 const std::map<AnalysisName, std::unique_ptr<AnalysisResult>> &Data) const {
107 Array Results;
108 for (const auto &[Name, Result] : Data) {
109 auto ExpectedEntry = analysisResultMapEntryToJSON(Name, Result);
110 if (!ExpectedEntry) {
111 return ExpectedEntry.takeError();
112 }
113 Results.push_back(E: std::move(*ExpectedEntry));
114 }
115 return Results;
116}
117
118//----------------------------------------------------------------------------
119// WPASuite
120//----------------------------------------------------------------------------
121
122llvm::Expected<WPASuite> JSONFormat::readWPASuite(llvm::StringRef Path) {
123 auto ExpectedJSON = readJSON(Path);
124 if (!ExpectedJSON) {
125 return ErrorBuilder::wrap(E: ExpectedJSON.takeError())
126 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "WPASuite", ArgVals&: Path)
127 .build();
128 }
129
130 Object *RootObjectPtr = ExpectedJSON->getAsObject();
131 if (!RootObjectPtr) {
132 return ErrorBuilder::create(EC: std::errc::invalid_argument,
133 Fmt: ErrorMessages::FailedToReadObject, ArgVals: "WPASuite",
134 ArgVals: "object")
135 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "WPASuite", ArgVals&: Path)
136 .build();
137 }
138
139 if (auto Err = checkSummaryType(RootObject: *RootObjectPtr, ExpectedType: JSONTypeValueWPASuite)) {
140 return ErrorBuilder::wrap(E: std::move(Err))
141 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "WPASuite", ArgVals&: Path)
142 .build();
143 }
144
145 auto ExpectedSuite = readWPASuiteFromObject(Root: *RootObjectPtr);
146 if (!ExpectedSuite) {
147 return ErrorBuilder::wrap(E: ExpectedSuite.takeError())
148 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "WPASuite", ArgVals&: Path)
149 .build();
150 }
151
152 return std::move(*ExpectedSuite);
153}
154
155llvm::Expected<WPASuite>
156JSONFormat::readWPASuiteFromObject(const Object &RootObject) {
157 WPASuite Suite = makeWPASuite();
158
159 {
160 const Array *IdTableArray = RootObject.getArray(K: "id_table");
161 if (!IdTableArray) {
162 return ErrorBuilder::create(EC: std::errc::invalid_argument,
163 Fmt: ErrorMessages::FailedToReadObjectAtField,
164 ArgVals: "IdTable", ArgVals: "id_table", ArgVals: "array")
165 .build();
166 }
167
168 auto ExpectedIdTable = luEntityIdTableFromJSON(EntityIdTableArray: *IdTableArray);
169 if (!ExpectedIdTable) {
170 return ErrorBuilder::wrap(E: ExpectedIdTable.takeError())
171 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "IdTable", ArgVals: "id_table")
172 .build();
173 }
174
175 getIdTable(X&: Suite) = std::move(*ExpectedIdTable);
176 }
177
178 {
179 const Array *ResultsArray = RootObject.getArray(K: "results");
180 if (!ResultsArray) {
181 return ErrorBuilder::create(EC: std::errc::invalid_argument,
182 Fmt: ErrorMessages::FailedToReadObjectAtField,
183 ArgVals: "WPA results", ArgVals: "results", ArgVals: "array")
184 .build();
185 }
186
187 auto ExpectedResultsMap = analysisResultMapFromJSON(ResultsArray: *ResultsArray);
188 if (!ExpectedResultsMap) {
189 return ErrorBuilder::wrap(E: ExpectedResultsMap.takeError())
190 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "WPA results", ArgVals: "results")
191 .build();
192 }
193
194 getData(X&: Suite) = std::move(*ExpectedResultsMap);
195 }
196
197 return std::move(Suite);
198}
199
200llvm::Error JSONFormat::writeWPASuite(const WPASuite &Suite,
201 llvm::StringRef Path) {
202 Object RootObject;
203
204 RootObject[JSONTypeKey] = JSONTypeValueWPASuite;
205
206 RootObject["id_table"] = luEntityIdTableToJSON(IdTable: getIdTable(X: Suite));
207
208 auto ExpectedResults = analysisResultMapToJSON(Data: getData(X: Suite));
209 if (!ExpectedResults) {
210 return ErrorBuilder::wrap(E: ExpectedResults.takeError())
211 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "WPASuite", ArgVals&: Path)
212 .build();
213 }
214
215 RootObject["results"] = std::move(*ExpectedResults);
216
217 if (auto Error = writeJSON(V: std::move(RootObject), Path)) {
218 return ErrorBuilder::wrap(E: std::move(Error))
219 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "WPASuite", ArgVals&: Path)
220 .build();
221 }
222
223 return llvm::Error::success();
224}
225
226} // namespace clang::ssaf
227