clang 23.0.0git
TUSummary.cpp
Go to the documentation of this file.
1//===- TUSummary.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
12
13namespace clang::ssaf {
14
15//----------------------------------------------------------------------------
16// EntitySummary
17//----------------------------------------------------------------------------
18
19llvm::Expected<std::unique_ptr<EntitySummary>>
20JSONFormat::entitySummaryFromJSON(const SummaryName &SN,
21 const Object &EntitySummaryObject,
22 EntityIdTable &IdTable) const {
23 auto InfoIt = FormatInfos.find(SN);
24 if (InfoIt == FormatInfos.end()) {
26 std::errc::invalid_argument,
28 .build();
29 }
30
31 const auto &InfoEntry = InfoIt->second;
32 assert(InfoEntry.ForSummary == SN);
33
34 EntityIdConverter Converter(*this);
35 return InfoEntry.Deserialize(EntitySummaryObject, IdTable, Converter);
36}
37
38llvm::Expected<Object>
39JSONFormat::entitySummaryToJSON(const SummaryName &SN,
40 const EntitySummary &ES) const {
41 auto InfoIt = FormatInfos.find(SN);
42 if (InfoIt == FormatInfos.end()) {
44 std::errc::invalid_argument,
46 .build();
47 }
48
49 const auto &InfoEntry = InfoIt->second;
50 assert(InfoEntry.ForSummary == SN);
51
52 EntityIdConverter Converter(*this);
53 return InfoEntry.Serialize(ES, Converter);
54}
55
56//----------------------------------------------------------------------------
57// EntityDataMapEntry
58//----------------------------------------------------------------------------
59
60llvm::Expected<std::pair<EntityId, std::unique_ptr<EntitySummary>>>
61JSONFormat::entityDataMapEntryFromJSON(const Object &EntityDataMapEntryObject,
62 const SummaryName &SN,
63 EntityIdTable &IdTable) const {
64
65 const Value *EntityIdIntValue = EntityDataMapEntryObject.get("entity_id");
66 if (!EntityIdIntValue) {
67 return ErrorBuilder::create(std::errc::invalid_argument,
69 "EntityId", "entity_id",
70 "number (unsigned 64-bit integer)")
71 .build();
72 }
73
74 const std::optional<uint64_t> OptEntityIdInt =
75 EntityIdIntValue->getAsUINT64();
76 if (!OptEntityIdInt) {
77 return ErrorBuilder::create(std::errc::invalid_argument,
79 "EntityId", "entity_id",
80 "number (unsigned 64-bit integer)")
81 .build();
82 }
83
84 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
85
86 const Object *OptEntitySummaryObject =
87 EntityDataMapEntryObject.getObject("entity_summary");
88 if (!OptEntitySummaryObject) {
89 return ErrorBuilder::create(std::errc::invalid_argument,
91 "EntitySummary", "entity_summary", "object")
92 .build();
93 }
94
95 auto ExpectedEntitySummary =
96 entitySummaryFromJSON(SN, *OptEntitySummaryObject, IdTable);
97 if (!ExpectedEntitySummary) {
98 return ErrorBuilder::wrap(ExpectedEntitySummary.takeError())
100 "entity_summary")
101 .build();
102 }
103
104 if (*ExpectedEntitySummary == nullptr) {
106 std::errc::invalid_argument,
108 .build();
109 }
110
111 auto ActualSN = (*ExpectedEntitySummary)->getSummaryName();
112 if (SN != ActualSN) {
114 std::errc::invalid_argument,
115 ErrorMessages::
116 FailedToDeserializeEntitySummaryMismatchedSummaryName,
117 SN, ActualSN)
118 .build();
119 }
120
121 return std::make_pair(std::move(EI), std::move(*ExpectedEntitySummary));
122}
123
124llvm::Expected<Object> JSONFormat::entityDataMapEntryToJSON(
125 const EntityId EI, const std::unique_ptr<EntitySummary> &EntitySummary,
126 const SummaryName &SN) const {
127 Object Entry;
128
129 Entry["entity_id"] = entityIdToJSON(EI);
130
131 if (!EntitySummary) {
134 }
135
136 const auto ActualSN = EntitySummary->getSummaryName();
137 if (SN != ActualSN) {
140 ActualSN);
141 }
142
143 auto ExpectedEntitySummaryObject = entitySummaryToJSON(SN, *EntitySummary);
144 if (!ExpectedEntitySummaryObject) {
145 return ErrorBuilder::wrap(ExpectedEntitySummaryObject.takeError())
146 .context(ErrorMessages::WritingToField, "EntitySummary",
147 "entity_summary")
148 .build();
149 }
150
151 Entry["entity_summary"] = std::move(*ExpectedEntitySummaryObject);
152
153 return Entry;
154}
155
156//----------------------------------------------------------------------------
157// EntityDataMap
158//----------------------------------------------------------------------------
159
160llvm::Expected<std::map<EntityId, std::unique_ptr<EntitySummary>>>
161JSONFormat::entityDataMapFromJSON(const SummaryName &SN,
162 const Array &EntityDataArray,
163 EntityIdTable &IdTable) const {
164 std::map<EntityId, std::unique_ptr<EntitySummary>> EntityDataMap;
165
166 for (const auto &[Index, EntityDataMapEntryValue] :
167 llvm::enumerate(EntityDataArray)) {
168
169 const Object *OptEntityDataMapEntryObject =
170 EntityDataMapEntryValue.getAsObject();
171 if (!OptEntityDataMapEntryObject) {
172 return ErrorBuilder::create(std::errc::invalid_argument,
174 "EntitySummary entry", Index, "object")
175 .build();
176 }
177
178 auto ExpectedEntityDataMapEntry =
179 entityDataMapEntryFromJSON(*OptEntityDataMapEntryObject, SN, IdTable);
180 if (!ExpectedEntityDataMapEntry) {
181 return ErrorBuilder::wrap(ExpectedEntityDataMapEntry.takeError())
182 .context(ErrorMessages::ReadingFromIndex, "EntitySummary entry",
183 Index)
184 .build();
185 }
186
187 auto [DataIt, DataInserted] =
188 EntityDataMap.insert(std::move(*ExpectedEntityDataMapEntry));
189 if (!DataInserted) {
190 return ErrorBuilder::create(std::errc::invalid_argument,
192 "EntitySummary entry", Index, DataIt->first)
193 .build();
194 }
195 }
196
197 return std::move(EntityDataMap);
198}
199
200llvm::Expected<Array> JSONFormat::entityDataMapToJSON(
201 const SummaryName &SN,
202 const std::map<EntityId, std::unique_ptr<EntitySummary>> &EntityDataMap)
203 const {
204 Array Result;
205 Result.reserve(EntityDataMap.size());
206
207 for (const auto &[Index, EntityDataMapEntry] :
208 llvm::enumerate(EntityDataMap)) {
209 const auto &[EntityId, EntitySummary] = EntityDataMapEntry;
210
211 auto ExpectedEntityDataMapEntryObject =
212 entityDataMapEntryToJSON(EntityId, EntitySummary, SN);
213
214 if (!ExpectedEntityDataMapEntryObject) {
215 return ErrorBuilder::wrap(ExpectedEntityDataMapEntryObject.takeError())
216 .context(ErrorMessages::WritingToIndex, "EntitySummary entry", Index)
217 .build();
218 }
219
220 Result.push_back(std::move(*ExpectedEntityDataMapEntryObject));
221 }
222
223 return Result;
224}
225
226//----------------------------------------------------------------------------
227// SummaryDataMapEntry
228//----------------------------------------------------------------------------
229
230llvm::Expected<
231 std::pair<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
232JSONFormat::summaryDataMapEntryFromJSON(const Object &SummaryDataMapEntryObject,
233 EntityIdTable &IdTable) const {
234
235 std::optional<llvm::StringRef> OptSummaryNameStr =
236 SummaryDataMapEntryObject.getString("summary_name");
237 if (!OptSummaryNameStr) {
238 return ErrorBuilder::create(std::errc::invalid_argument,
240 "SummaryName", "summary_name", "string")
241 .build();
242 }
243
244 SummaryName SN = summaryNameFromJSON(*OptSummaryNameStr);
245
246 const Array *OptEntityDataArray =
247 SummaryDataMapEntryObject.getArray("summary_data");
248 if (!OptEntityDataArray) {
249 return ErrorBuilder::create(std::errc::invalid_argument,
251 "EntitySummary entries", "summary_data",
252 "array")
253 .build();
254 }
255
256 auto ExpectedEntityDataMap =
257 entityDataMapFromJSON(SN, *OptEntityDataArray, IdTable);
258 if (!ExpectedEntityDataMap)
259 return ErrorBuilder::wrap(ExpectedEntityDataMap.takeError())
260 .context(ErrorMessages::ReadingFromField, "EntitySummary entries",
261 "summary_data")
262 .build();
263
264 return std::make_pair(std::move(SN), std::move(*ExpectedEntityDataMap));
265}
266
267llvm::Expected<Object> JSONFormat::summaryDataMapEntryToJSON(
268 const SummaryName &SN,
269 const std::map<EntityId, std::unique_ptr<EntitySummary>> &SD) const {
270 Object Result;
271
272 Result["summary_name"] = summaryNameToJSON(SN);
273
274 auto ExpectedSummaryDataArray = entityDataMapToJSON(SN, SD);
275 if (!ExpectedSummaryDataArray) {
276 return ErrorBuilder::wrap(ExpectedSummaryDataArray.takeError())
277 .context(ErrorMessages::WritingToField, "EntitySummary entries",
278 "summary_data")
279 .build();
280 }
281
282 Result["summary_data"] = std::move(*ExpectedSummaryDataArray);
283
284 return Result;
285}
286
287//----------------------------------------------------------------------------
288// SummaryDataMap
289//----------------------------------------------------------------------------
290
291llvm::Expected<
292 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
293JSONFormat::summaryDataMapFromJSON(const Array &SummaryDataArray,
294 EntityIdTable &IdTable) const {
295 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>
296 SummaryDataMap;
297
298 for (const auto &[Index, SummaryDataMapEntryValue] :
299 llvm::enumerate(SummaryDataArray)) {
300
301 const Object *OptSummaryDataMapEntryObject =
302 SummaryDataMapEntryValue.getAsObject();
303 if (!OptSummaryDataMapEntryObject) {
304 return ErrorBuilder::create(std::errc::invalid_argument,
306 "SummaryData entry", Index, "object")
307 .build();
308 }
309
310 auto ExpectedSummaryDataMapEntry =
311 summaryDataMapEntryFromJSON(*OptSummaryDataMapEntryObject, IdTable);
312 if (!ExpectedSummaryDataMapEntry) {
313 return ErrorBuilder::wrap(ExpectedSummaryDataMapEntry.takeError())
314 .context(ErrorMessages::ReadingFromIndex, "SummaryData entry", Index)
315 .build();
316 }
317
318 auto [SummaryIt, SummaryInserted] =
319 SummaryDataMap.emplace(std::move(*ExpectedSummaryDataMapEntry));
320 if (!SummaryInserted) {
321 return ErrorBuilder::create(std::errc::invalid_argument,
323 "SummaryData entry", Index, SummaryIt->first)
324 .build();
325 }
326 }
327
328 return std::move(SummaryDataMap);
329}
330
331llvm::Expected<Array> JSONFormat::summaryDataMapToJSON(
332 const std::map<SummaryName,
333 std::map<EntityId, std::unique_ptr<EntitySummary>>>
334 &SummaryDataMap) const {
335 Array Result;
336 Result.reserve(SummaryDataMap.size());
337
338 for (const auto &[Index, SummaryDataMapEntry] :
339 llvm::enumerate(SummaryDataMap)) {
340 const auto &[SummaryName, DataMap] = SummaryDataMapEntry;
341
342 auto ExpectedSummaryDataMapObject =
343 summaryDataMapEntryToJSON(SummaryName, DataMap);
344 if (!ExpectedSummaryDataMapObject) {
345 return ErrorBuilder::wrap(ExpectedSummaryDataMapObject.takeError())
346 .context(ErrorMessages::WritingToIndex, "SummaryData entry", Index)
347 .build();
348 }
349
350 Result.push_back(std::move(*ExpectedSummaryDataMapObject));
351 }
352
353 return std::move(Result);
354}
355
356//----------------------------------------------------------------------------
357// TUSummary
358//----------------------------------------------------------------------------
359
361 auto ExpectedJSON = readJSON(Path);
362 if (!ExpectedJSON) {
363 return ErrorBuilder::wrap(ExpectedJSON.takeError())
364 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
365 .build();
366 }
367
368 Object *RootObjectPtr = ExpectedJSON->getAsObject();
369 if (!RootObjectPtr) {
370 return ErrorBuilder::create(std::errc::invalid_argument,
372 "object")
373 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
374 .build();
375 }
376
377 const Object &RootObject = *RootObjectPtr;
378
379 const Object *TUNamespaceObject = RootObject.getObject("tu_namespace");
380 if (!TUNamespaceObject) {
381 return ErrorBuilder::create(std::errc::invalid_argument,
383 "BuildNamespace", "tu_namespace", "object")
384 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
385 .build();
386 }
387
388 auto ExpectedTUNamespace = buildNamespaceFromJSON(*TUNamespaceObject);
389 if (!ExpectedTUNamespace) {
390 return ErrorBuilder::wrap(ExpectedTUNamespace.takeError())
391 .context(ErrorMessages::ReadingFromField, "BuildNamespace",
392 "tu_namespace")
393 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
394 .build();
395 }
396
397 TUSummary Summary(std::move(*ExpectedTUNamespace));
398
399 {
400 const Array *IdTableArray = RootObject.getArray("id_table");
401 if (!IdTableArray) {
402 return ErrorBuilder::create(std::errc::invalid_argument,
404 "IdTable", "id_table", "array")
405 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
406 .build();
407 }
408
409 auto ExpectedIdTable = entityIdTableFromJSON(*IdTableArray);
410 if (!ExpectedIdTable) {
411 return ErrorBuilder::wrap(ExpectedIdTable.takeError())
412 .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
413 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
414 .build();
415 }
416
417 getIdTable(Summary) = std::move(*ExpectedIdTable);
418 }
419
420 {
421 const Array *LinkageTableArray = RootObject.getArray("linkage_table");
422 if (!LinkageTableArray) {
423 return ErrorBuilder::create(std::errc::invalid_argument,
425 "LinkageTable", "linkage_table", "array")
426 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
427 .build();
428 }
429
430 auto ExpectedIdRange =
431 llvm::make_second_range(getEntities(getIdTable(Summary)));
432 std::set<EntityId> ExpectedIds(ExpectedIdRange.begin(),
433 ExpectedIdRange.end());
434
435 // Move ExpectedIds in since linkageTableFromJSON consumes it to verify
436 // that the linkage table contains exactly the ids present in the IdTable.
437 auto ExpectedLinkageTable =
438 linkageTableFromJSON(*LinkageTableArray, std::move(ExpectedIds));
439 if (!ExpectedLinkageTable) {
440 return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
442 "linkage_table")
443 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
444 .build();
445 }
446
447 getLinkageTable(Summary) = std::move(*ExpectedLinkageTable);
448 }
449
450 {
451 const Array *SummaryDataArray = RootObject.getArray("data");
452 if (!SummaryDataArray) {
453 return ErrorBuilder::create(std::errc::invalid_argument,
455 "SummaryData entries", "data", "array")
456 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
457 .build();
458 }
459
460 auto ExpectedSummaryDataMap =
461 summaryDataMapFromJSON(*SummaryDataArray, getIdTable(Summary));
462 if (!ExpectedSummaryDataMap) {
463 return ErrorBuilder::wrap(ExpectedSummaryDataMap.takeError())
464 .context(ErrorMessages::ReadingFromField, "SummaryData entries",
465 "data")
466 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
467 .build();
468 }
469
470 getData(Summary) = std::move(*ExpectedSummaryDataMap);
471 }
472
473 return std::move(Summary);
474}
475
477 llvm::StringRef Path) {
478 Object RootObject;
479
480 RootObject["tu_namespace"] = buildNamespaceToJSON(getTUNamespace(S));
481
482 RootObject["id_table"] = entityIdTableToJSON(getIdTable(S));
483
484 RootObject["linkage_table"] = linkageTableToJSON(getLinkageTable(S));
485
486 auto ExpectedDataObject = summaryDataMapToJSON(getData(S));
487 if (!ExpectedDataObject) {
488 return ErrorBuilder::wrap(ExpectedDataObject.takeError())
489 .context(ErrorMessages::WritingToFile, "TUSummary", Path)
490 .build();
491 }
492
493 RootObject["data"] = std::move(*ExpectedDataObject);
494
495 if (auto Error = writeJSON(std::move(RootObject), Path)) {
496 return ErrorBuilder::wrap(std::move(Error))
497 .context(ErrorMessages::WritingToFile, "TUSummary", Path)
498 .build();
499 }
500
501 return llvm::Error::success();
502}
503
504} // namespace clang::ssaf
Manages entity name interning and provides efficient EntityId handles.
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
Base class for analysis-specific summary data.
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< TUSummary > readTUSummary(llvm::StringRef Path) override
llvm::Error writeTUSummary(const TUSummary &Summary, llvm::StringRef Path) override
Uniquely identifies an analysis summary.
Definition SummaryName.h:22
Data extracted for a given translation unit and for a given set of analyses.
Definition TUSummary.h:24
constexpr const char * FailedToSerializeEntitySummaryMismatchedSummaryName
constexpr const char * ReadingFromFile
constexpr const char * ReadingFromField
constexpr const char * FailedToReadObjectAtIndex
constexpr const char * FailedToDeserializeEntitySummaryNoFormatInfo
constexpr const char * FailedToReadObjectAtField
constexpr const char * WritingToFile
constexpr const char * ReadingFromIndex
constexpr const char * WritingToField
constexpr const char * FailedInsertionOnDuplication
constexpr const char * FailedToSerializeEntitySummaryMissingData
constexpr const char * FailedToDeserializeEntitySummaryMissingData
constexpr const char * FailedToReadObject
constexpr const char * FailedToSerializeEntitySummaryNoFormatInfo
constexpr const char * WritingToIndex
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