clang 23.0.0git
TUSummaryEncoding.cpp
Go to the documentation of this file.
1//===- TUSummaryEncoding.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
13
14namespace clang::ssaf {
15
16//----------------------------------------------------------------------------
17// JSONEntitySummaryEncoding
18//----------------------------------------------------------------------------
19
20namespace {
21
22class JSONEntitySummaryEncoding final : public EntitySummaryEncoding {
23 friend JSONFormat;
24
25public:
26 void
27 patch(const std::map<EntityId, EntityId> &EntityResolutionTable) override {
28 ErrorBuilder::fatal("will be implemented in the future");
29 }
30
31private:
32 explicit JSONEntitySummaryEncoding(llvm::json::Value Data)
33 : Data(std::move(Data)) {}
34
35 llvm::json::Value Data;
36};
37
38} // namespace
39
40//----------------------------------------------------------------------------
41// EncodingDataMapEntry
42//----------------------------------------------------------------------------
43
44llvm::Expected<std::pair<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
45JSONFormat::encodingDataMapEntryFromJSON(
46 const Object &EntityDataMapEntryObject) const {
47 const Value *EntityIdIntValue = EntityDataMapEntryObject.get("entity_id");
48 if (!EntityIdIntValue) {
49 return ErrorBuilder::create(std::errc::invalid_argument,
51 "EntityId", "entity_id",
52 "number (unsigned 64-bit integer)")
53 .build();
54 }
55
56 const std::optional<uint64_t> OptEntityIdInt =
57 EntityIdIntValue->getAsUINT64();
58 if (!OptEntityIdInt) {
59 return ErrorBuilder::create(std::errc::invalid_argument,
61 "EntityId", "entity_id",
62 "number (unsigned 64-bit integer)")
63 .build();
64 }
65
66 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
67
68 const Object *OptEntitySummaryObject =
69 EntityDataMapEntryObject.getObject("entity_summary");
70 if (!OptEntitySummaryObject) {
71 return ErrorBuilder::create(std::errc::invalid_argument,
73 "EntitySummary", "entity_summary", "object")
74 .build();
75 }
76
77 std::unique_ptr<EntitySummaryEncoding> Encoding(
78 new JSONEntitySummaryEncoding(Value(Object(*OptEntitySummaryObject))));
79
80 return std::make_pair(std::move(EI), std::move(Encoding));
81}
82
83Object JSONFormat::encodingDataMapEntryToJSON(
84 EntityId EI, const std::unique_ptr<EntitySummaryEncoding> &Encoding) const {
85 Object Entry;
86 Entry["entity_id"] = entityIdToJSON(EI);
87
88 // All EntitySummaryEncoding objects stored in a TUSummaryEncoding read by
89 // JSONFormat are JSONEntitySummaryEncoding instances, since
90 // encodingDataMapEntryFromJSON is the only place that creates them.
91 auto *JSONEncoding = static_cast<JSONEntitySummaryEncoding *>(Encoding.get());
92 Entry["entity_summary"] = JSONEncoding->Data;
93
94 return Entry;
95}
96
97//----------------------------------------------------------------------------
98// EncodingDataMap
99//----------------------------------------------------------------------------
100
101llvm::Expected<std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
102JSONFormat::encodingDataMapFromJSON(const Array &EntityDataArray) const {
103 std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>> EncodingDataMap;
104
105 for (const auto &[Index, EntityDataMapEntryValue] :
106 llvm::enumerate(EntityDataArray)) {
107
108 const Object *OptEntityDataMapEntryObject =
109 EntityDataMapEntryValue.getAsObject();
110 if (!OptEntityDataMapEntryObject) {
111 return ErrorBuilder::create(std::errc::invalid_argument,
113 "EntitySummary entry", Index, "object")
114 .build();
115 }
116
117 auto ExpectedEntry =
118 encodingDataMapEntryFromJSON(*OptEntityDataMapEntryObject);
119 if (!ExpectedEntry) {
120 return ErrorBuilder::wrap(ExpectedEntry.takeError())
121 .context(ErrorMessages::ReadingFromIndex, "EntitySummary entry",
122 Index)
123 .build();
124 }
125
126 auto [DataIt, DataInserted] =
127 EncodingDataMap.insert(std::move(*ExpectedEntry));
128 if (!DataInserted) {
129 return ErrorBuilder::create(std::errc::invalid_argument,
131 "EntitySummary entry", Index, DataIt->first)
132 .build();
133 }
134 }
135
136 return std::move(EncodingDataMap);
137}
138
139Array JSONFormat::encodingDataMapToJSON(
140 const std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>
141 &EncodingDataMap) const {
142 Array Result;
143 Result.reserve(EncodingDataMap.size());
144
145 for (const auto &[EI, Encoding] : EncodingDataMap) {
146 Result.push_back(encodingDataMapEntryToJSON(EI, Encoding));
147 }
148
149 return Result;
150}
151
152//----------------------------------------------------------------------------
153// EncodingSummaryDataMapEntry
154//----------------------------------------------------------------------------
155
156llvm::Expected<std::pair<
157 SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>>
158JSONFormat::encodingSummaryDataMapEntryFromJSON(
159 const Object &SummaryDataMapEntryObject) const {
160 std::optional<llvm::StringRef> OptSummaryNameStr =
161 SummaryDataMapEntryObject.getString("summary_name");
162 if (!OptSummaryNameStr) {
163 return ErrorBuilder::create(std::errc::invalid_argument,
165 "SummaryName", "summary_name", "string")
166 .build();
167 }
168
169 SummaryName SN = summaryNameFromJSON(*OptSummaryNameStr);
170
171 const Array *OptEntityDataArray =
172 SummaryDataMapEntryObject.getArray("summary_data");
173 if (!OptEntityDataArray) {
174 return ErrorBuilder::create(std::errc::invalid_argument,
176 "EntitySummary entries", "summary_data",
177 "array")
178 .build();
179 }
180
181 auto ExpectedEncodingDataMap = encodingDataMapFromJSON(*OptEntityDataArray);
182 if (!ExpectedEncodingDataMap)
183 return ErrorBuilder::wrap(ExpectedEncodingDataMap.takeError())
184 .context(ErrorMessages::ReadingFromField, "EntitySummary entries",
185 "summary_data")
186 .build();
187
188 return std::make_pair(std::move(SN), std::move(*ExpectedEncodingDataMap));
189}
190
191Object JSONFormat::encodingSummaryDataMapEntryToJSON(
192 const SummaryName &SN,
193 const std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>
194 &EncodingMap) const {
195 Object Result;
196
197 Result["summary_name"] = summaryNameToJSON(SN);
198 Result["summary_data"] = encodingDataMapToJSON(EncodingMap);
199
200 return Result;
201}
202
203//----------------------------------------------------------------------------
204// EncodingSummaryDataMap
205//----------------------------------------------------------------------------
206
207llvm::Expected<std::map<
208 SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>>
209JSONFormat::encodingSummaryDataMapFromJSON(
210 const Array &SummaryDataArray) const {
211 std::map<SummaryName,
212 std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
213 EncodingSummaryDataMap;
214
215 for (const auto &[Index, SummaryDataMapEntryValue] :
216 llvm::enumerate(SummaryDataArray)) {
217
218 const Object *OptSummaryDataMapEntryObject =
219 SummaryDataMapEntryValue.getAsObject();
220 if (!OptSummaryDataMapEntryObject) {
221 return ErrorBuilder::create(std::errc::invalid_argument,
223 "SummaryData entry", Index, "object")
224 .build();
225 }
226
227 auto ExpectedEntry =
228 encodingSummaryDataMapEntryFromJSON(*OptSummaryDataMapEntryObject);
229 if (!ExpectedEntry) {
230 return ErrorBuilder::wrap(ExpectedEntry.takeError())
231 .context(ErrorMessages::ReadingFromIndex, "SummaryData entry", Index)
232 .build();
233 }
234
235 auto [SummaryIt, SummaryInserted] =
236 EncodingSummaryDataMap.emplace(std::move(*ExpectedEntry));
237 if (!SummaryInserted) {
238 return ErrorBuilder::create(std::errc::invalid_argument,
240 "SummaryData entry", Index, SummaryIt->first)
241 .build();
242 }
243 }
244
245 return std::move(EncodingSummaryDataMap);
246}
247
248Array JSONFormat::encodingSummaryDataMapToJSON(
249 const std::map<SummaryName,
250 std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
251 &EncodingSummaryDataMap) const {
252 Array Result;
253 Result.reserve(EncodingSummaryDataMap.size());
254
255 for (const auto &[SN, EncodingMap] : EncodingSummaryDataMap) {
256 Result.push_back(encodingSummaryDataMapEntryToJSON(SN, EncodingMap));
257 }
258
259 return Result;
260}
261
262//----------------------------------------------------------------------------
263// TUSummaryEncoding
264//----------------------------------------------------------------------------
265
266llvm::Expected<TUSummaryEncoding>
268 auto ExpectedJSON = readJSON(Path);
269 if (!ExpectedJSON) {
270 return ErrorBuilder::wrap(ExpectedJSON.takeError())
271 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
272 .build();
273 }
274
275 Object *RootObjectPtr = ExpectedJSON->getAsObject();
276 if (!RootObjectPtr) {
277 return ErrorBuilder::create(std::errc::invalid_argument,
279 "object")
280 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
281 .build();
282 }
283
284 const Object &RootObject = *RootObjectPtr;
285
286 const Object *TUNamespaceObject = RootObject.getObject("tu_namespace");
287 if (!TUNamespaceObject) {
288 return ErrorBuilder::create(std::errc::invalid_argument,
290 "BuildNamespace", "tu_namespace", "object")
291 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
292 .build();
293 }
294
295 auto ExpectedTUNamespace = buildNamespaceFromJSON(*TUNamespaceObject);
296 if (!ExpectedTUNamespace) {
297 return ErrorBuilder::wrap(ExpectedTUNamespace.takeError())
298 .context(ErrorMessages::ReadingFromField, "BuildNamespace",
299 "tu_namespace")
300 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
301 .build();
302 }
303
304 TUSummaryEncoding Encoding(std::move(*ExpectedTUNamespace));
305
306 {
307 const Array *IdTableArray = RootObject.getArray("id_table");
308 if (!IdTableArray) {
309 return ErrorBuilder::create(std::errc::invalid_argument,
311 "IdTable", "id_table", "array")
312 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
313 .build();
314 }
315
316 auto ExpectedIdTable = entityIdTableFromJSON(*IdTableArray);
317 if (!ExpectedIdTable) {
318 return ErrorBuilder::wrap(ExpectedIdTable.takeError())
319 .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
320 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
321 .build();
322 }
323
324 getIdTable(Encoding) = std::move(*ExpectedIdTable);
325 }
326
327 {
328 const Array *LinkageTableArray = RootObject.getArray("linkage_table");
329 if (!LinkageTableArray) {
330 return ErrorBuilder::create(std::errc::invalid_argument,
332 "LinkageTable", "linkage_table", "array")
333 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
334 .build();
335 }
336
337 auto ExpectedIdRange =
338 llvm::make_second_range(getEntities(getIdTable(Encoding)));
339 std::set<EntityId> ExpectedIds(ExpectedIdRange.begin(),
340 ExpectedIdRange.end());
341
342 // Move ExpectedIds in since linkageTableFromJSON consumes it to verify
343 // that the linkage table contains exactly the ids present in the IdTable.
344 auto ExpectedLinkageTable =
345 linkageTableFromJSON(*LinkageTableArray, std::move(ExpectedIds));
346 if (!ExpectedLinkageTable) {
347 return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
349 "linkage_table")
350 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
351 .build();
352 }
353
354 getLinkageTable(Encoding) = std::move(*ExpectedLinkageTable);
355 }
356
357 {
358 const Array *SummaryDataArray = RootObject.getArray("data");
359 if (!SummaryDataArray) {
360 return ErrorBuilder::create(std::errc::invalid_argument,
362 "SummaryData entries", "data", "array")
363 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
364 .build();
365 }
366
367 auto ExpectedEncodingSummaryDataMap =
368 encodingSummaryDataMapFromJSON(*SummaryDataArray);
369 if (!ExpectedEncodingSummaryDataMap) {
370 return ErrorBuilder::wrap(ExpectedEncodingSummaryDataMap.takeError())
371 .context(ErrorMessages::ReadingFromField, "SummaryData entries",
372 "data")
373 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
374 .build();
375 }
376
377 getData(Encoding) = std::move(*ExpectedEncodingSummaryDataMap);
378 }
379
380 return std::move(Encoding);
381}
382
383llvm::Error
385 llvm::StringRef Path) {
386 Object RootObject;
387
388 RootObject["tu_namespace"] =
389 buildNamespaceToJSON(getTUNamespace(SummaryEncoding));
390
391 RootObject["id_table"] = entityIdTableToJSON(getIdTable(SummaryEncoding));
392
393 RootObject["linkage_table"] =
394 linkageTableToJSON(getLinkageTable(SummaryEncoding));
395
396 RootObject["data"] = encodingSummaryDataMapToJSON(getData(SummaryEncoding));
397
398 if (auto Error = writeJSON(std::move(RootObject), Path)) {
399 return ErrorBuilder::wrap(std::move(Error))
400 .context(ErrorMessages::WritingToFile, "TUSummary", Path)
401 .build();
402 }
403
404 return llvm::Error::success();
405}
406
407} // namespace clang::ssaf
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
Represents EntitySummary data in its serialized, format-specific encoding.
static ErrorBuilder create(std::error_code EC, const char *Fmt, Args &&...ArgVals)
Create an ErrorBuilder with an error code and formatted message.
static void fatal(const char *Fmt, Args &&...ArgVals)
Report a fatal error with formatted message and terminate execution.
ErrorBuilder & context(const char *Msg)
Add context information as a plain string.
llvm::Error build() const
Build and return the final error.
static ErrorBuilder wrap(llvm::Error E)
Wrap an existing error and optionally add context.
llvm::Expected< TUSummaryEncoding > readTUSummaryEncoding(llvm::StringRef Path) override
llvm::Error writeTUSummaryEncoding(const TUSummaryEncoding &SummaryEncoding, llvm::StringRef Path) override
Uniquely identifies an analysis summary.
Definition SummaryName.h:22
Represents a translation unit summary in its serialized encoding.
constexpr const char * ReadingFromFile
constexpr const char * ReadingFromField
constexpr const char * FailedToReadObjectAtIndex
constexpr const char * FailedToReadObjectAtField
constexpr const char * WritingToFile
constexpr const char * ReadingFromIndex
constexpr const char * FailedInsertionOnDuplication
constexpr const char * FailedToReadObject
SummaryName summaryNameFromJSON(llvm::StringRef SummaryNameStr)
llvm::StringRef summaryNameToJSON(const SummaryName &SN)
llvm::json::Array Array
llvm::Error writeJSON(Value &&Value, llvm::StringRef Path)
llvm::json::Value Value
llvm::json::Object Object
llvm::Expected< Value > readJSON(llvm::StringRef Path)
@ Result
The result type of a method or function.
Definition TypeBase.h:905