clang 23.0.0git
JSONFormat.cpp
Go to the documentation of this file.
4
5#include "llvm/ADT/StringExtras.h"
6#include "llvm/Support/FileSystem.h"
7#include "llvm/Support/FormatVariadic.h"
8#include "llvm/Support/JSON.h"
9#include "llvm/Support/MemoryBuffer.h"
10#include "llvm/Support/Path.h"
11#include "llvm/Support/Registry.h"
12
13using namespace clang::ssaf;
14
15using Array = llvm::json::Array;
16using Object = llvm::json::Object;
17using Value = llvm::json::Value;
18
19LLVM_INSTANTIATE_REGISTRY(llvm::Registry<JSONFormat::FormatInfo>)
20
21//----------------------------------------------------------------------------
22// File Format Constant
23//----------------------------------------------------------------------------
24
25namespace {
26
27constexpr const char *JSONFormatFileExtension = ".json";
28
29}
30
31//----------------------------------------------------------------------------
32// Error Message Constants
33//----------------------------------------------------------------------------
34
35namespace {
36
37namespace ErrorMessages {
38
39constexpr const char *FailedToReadFile = "failed to read file '{0}': {1}";
40constexpr const char *FailedToWriteFile = "failed to write file '{0}': {1}";
41constexpr const char *FileNotFound = "file does not exist";
42constexpr const char *FileIsDirectory = "path is a directory, not a file";
43constexpr const char *FileIsNotJSON = "file does not end with '{0}' extension";
44constexpr const char *FileExists = "file already exists";
45constexpr const char *ParentDirectoryNotFound =
46 "parent directory does not exist";
47
48constexpr const char *ReadingFromField = "reading {0} from field '{1}'";
49constexpr const char *WritingToField = "writing {0} to field '{1}'";
50constexpr const char *ReadingFromIndex = "reading {0} from index '{1}'";
51constexpr const char *WritingToIndex = "writing {0} to index '{1}'";
52constexpr const char *ReadingFromFile = "reading {0} from file '{1}'";
53constexpr const char *WritingToFile = "writing {0} to file '{1}'";
54
55constexpr const char *FailedInsertionOnDuplication =
56 "failed to insert {0} at index '{1}': encountered duplicate {2} '{3}'";
57
58constexpr const char *FailedToReadObject =
59 "failed to read {0}: expected JSON {1}";
60constexpr const char *FailedToReadObjectAtField =
61 "failed to read {0} from field '{1}': expected JSON {2}";
62constexpr const char *FailedToReadObjectAtIndex =
63 "failed to read {0} from index '{1}': expected JSON {2}";
64
65constexpr const char *FailedToDeserializeEntitySummary =
66 "failed to deserialize EntitySummary: no FormatInfo registered for summary "
67 "'{0}'";
68constexpr const char *FailedToSerializeEntitySummary =
69 "failed to serialize EntitySummary: no FormatInfo registered for summary "
70 "'{0}'";
71
72constexpr const char *InvalidBuildNamespaceKind =
73 "invalid 'kind' BuildNamespaceKind value '{0}'";
74
75} // namespace ErrorMessages
76
77} // namespace
78
79//----------------------------------------------------------------------------
80// JSON Reader and Writer
81//----------------------------------------------------------------------------
82
83namespace {
84
85llvm::Expected<Value> readJSON(llvm::StringRef Path) {
86 if (!llvm::sys::fs::exists(Path)) {
87 return ErrorBuilder::create(std::errc::no_such_file_or_directory,
88 ErrorMessages::FailedToReadFile, Path,
89 ErrorMessages::FileNotFound)
90 .build();
91 }
92
93 if (llvm::sys::fs::is_directory(Path)) {
94 return ErrorBuilder::create(std::errc::is_a_directory,
95 ErrorMessages::FailedToReadFile, Path,
96 ErrorMessages::FileIsDirectory)
97 .build();
98 }
99
100 if (!Path.ends_with_insensitive(JSONFormatFileExtension)) {
101 return ErrorBuilder::create(std::errc::invalid_argument,
102 ErrorMessages::FailedToReadFile, Path,
103 llvm::formatv(ErrorMessages::FileIsNotJSON,
104 JSONFormatFileExtension))
105 .build();
106 }
107
108 auto BufferOrError = llvm::MemoryBuffer::getFile(Path);
109 if (!BufferOrError) {
110 const std::error_code EC = BufferOrError.getError();
111 return ErrorBuilder::create(EC, ErrorMessages::FailedToReadFile, Path,
112 EC.message())
113 .build();
114 }
115
116 return llvm::json::parse(BufferOrError.get()->getBuffer());
117}
118
119llvm::Error writeJSON(Value &&Value, llvm::StringRef Path) {
120 if (llvm::sys::fs::exists(Path)) {
121 return ErrorBuilder::create(std::errc::file_exists,
122 ErrorMessages::FailedToWriteFile, Path,
123 ErrorMessages::FileExists)
124 .build();
125 }
126
127 llvm::StringRef Dir = llvm::sys::path::parent_path(Path);
128 if (!Dir.empty() && !llvm::sys::fs::is_directory(Dir)) {
129 return ErrorBuilder::create(std::errc::no_such_file_or_directory,
130 ErrorMessages::FailedToWriteFile, Path,
131 ErrorMessages::ParentDirectoryNotFound)
132 .build();
133 }
134
135 if (!Path.ends_with_insensitive(JSONFormatFileExtension)) {
136 return ErrorBuilder::create(std::errc::invalid_argument,
137 ErrorMessages::FailedToWriteFile, Path,
138 llvm::formatv(ErrorMessages::FileIsNotJSON,
139 JSONFormatFileExtension))
140 .build();
141 }
142
143 std::error_code EC;
144 llvm::raw_fd_ostream OutStream(Path, EC, llvm::sys::fs::OF_Text);
145
146 if (EC) {
147 return ErrorBuilder::create(EC, ErrorMessages::FailedToWriteFile, Path,
148 EC.message())
149 .build();
150 }
151
152 OutStream << llvm::formatv("{0:2}\n", Value);
153 OutStream.flush();
154
155 if (OutStream.has_error()) {
156 return ErrorBuilder::create(OutStream.error(),
157 ErrorMessages::FailedToWriteFile, Path,
158 OutStream.error().message())
159 .build();
160 }
161
162 return llvm::Error::success();
163}
164
165} // namespace
166
167//----------------------------------------------------------------------------
168// JSONFormat Static Methods
169//----------------------------------------------------------------------------
170
171std::map<SummaryName, JSONFormat::FormatInfo> JSONFormat::initFormatInfos() {
172 std::map<SummaryName, FormatInfo> FormatInfos;
173 for (const auto &FormatInfoEntry : llvm::Registry<FormatInfo>::entries()) {
174 std::unique_ptr<FormatInfo> Info = FormatInfoEntry.instantiate();
175 bool Inserted = FormatInfos.try_emplace(Info->ForSummary, *Info).second;
176 if (!Inserted) {
177 llvm::report_fatal_error(
178 "FormatInfo is already registered for summary: " +
179 Info->ForSummary.str());
180 }
181 }
182 return FormatInfos;
183}
184
185//----------------------------------------------------------------------------
186// SummaryName
187//----------------------------------------------------------------------------
188
189namespace {
190
191SummaryName summaryNameFromJSON(llvm::StringRef SummaryNameStr) {
192 return SummaryName(SummaryNameStr.str());
193}
194
195llvm::StringRef summaryNameToJSON(const SummaryName &SN) { return SN.str(); }
196
197} // namespace
198
199//----------------------------------------------------------------------------
200// EntityId
201//----------------------------------------------------------------------------
202
203EntityId JSONFormat::entityIdFromJSON(const uint64_t EntityIdIndex) const {
204 return makeEntityId(static_cast<size_t>(EntityIdIndex));
205}
206
207uint64_t JSONFormat::entityIdToJSON(EntityId EI) const {
208 return static_cast<uint64_t>(getIndex(EI));
209}
210
211//----------------------------------------------------------------------------
212// BuildNamespaceKind
213//----------------------------------------------------------------------------
214
215llvm::Expected<BuildNamespaceKind> JSONFormat::buildNamespaceKindFromJSON(
216 llvm::StringRef BuildNamespaceKindStr) const {
217 auto OptBuildNamespaceKind = parseBuildNamespaceKind(BuildNamespaceKindStr);
218 if (!OptBuildNamespaceKind) {
219 return ErrorBuilder::create(std::errc::invalid_argument,
220 ErrorMessages::InvalidBuildNamespaceKind,
221 BuildNamespaceKindStr)
222 .build();
223 }
224
225 return *OptBuildNamespaceKind;
226}
227
228namespace {
229
230llvm::StringRef buildNamespaceKindToJSON(BuildNamespaceKind BNK) {
231 return toString(BNK);
232}
233
234} // namespace
235
236//----------------------------------------------------------------------------
237// BuildNamespace
238//----------------------------------------------------------------------------
239
240llvm::Expected<BuildNamespace>
241JSONFormat::buildNamespaceFromJSON(const Object &BuildNamespaceObject) const {
242 auto OptBuildNamespaceKindStr = BuildNamespaceObject.getString("kind");
243 if (!OptBuildNamespaceKindStr) {
244 return ErrorBuilder::create(std::errc::invalid_argument,
245 ErrorMessages::FailedToReadObjectAtField,
246 "BuildNamespaceKind", "kind", "string")
247 .build();
248 }
249
250 auto ExpectedKind = buildNamespaceKindFromJSON(*OptBuildNamespaceKindStr);
251 if (!ExpectedKind)
252 return ErrorBuilder::wrap(ExpectedKind.takeError())
253 .context(ErrorMessages::ReadingFromField, "BuildNamespaceKind", "kind")
254 .build();
255
256 auto OptNameStr = BuildNamespaceObject.getString("name");
257 if (!OptNameStr) {
258 return ErrorBuilder::create(std::errc::invalid_argument,
259 ErrorMessages::FailedToReadObjectAtField,
260 "BuildNamespaceName", "name", "string")
261 .build();
262 }
263
264 return {BuildNamespace(*ExpectedKind, *OptNameStr)};
265}
266
267Object JSONFormat::buildNamespaceToJSON(const BuildNamespace &BN) const {
268 Object Result;
269 Result["kind"] = buildNamespaceKindToJSON(getKind(BN));
270 Result["name"] = getName(BN);
271 return Result;
272}
273
274//----------------------------------------------------------------------------
275// NestedBuildNamespace
276//----------------------------------------------------------------------------
277
278llvm::Expected<NestedBuildNamespace> JSONFormat::nestedBuildNamespaceFromJSON(
279 const Array &NestedBuildNamespaceArray) const {
280 std::vector<BuildNamespace> Namespaces;
281
282 size_t NamespaceCount = NestedBuildNamespaceArray.size();
283 Namespaces.reserve(NamespaceCount);
284
285 for (const auto &[Index, BuildNamespaceValue] :
286 llvm::enumerate(NestedBuildNamespaceArray)) {
287
288 const Object *BuildNamespaceObject = BuildNamespaceValue.getAsObject();
289 if (!BuildNamespaceObject) {
290 return ErrorBuilder::create(std::errc::invalid_argument,
291 ErrorMessages::FailedToReadObjectAtIndex,
292 "BuildNamespace", Index, "object")
293 .build();
294 }
295
296 auto ExpectedBuildNamespace = buildNamespaceFromJSON(*BuildNamespaceObject);
297 if (!ExpectedBuildNamespace) {
298 return ErrorBuilder::wrap(ExpectedBuildNamespace.takeError())
299 .context(ErrorMessages::ReadingFromIndex, "BuildNamespace", Index)
300 .build();
301 }
302
303 Namespaces.push_back(std::move(*ExpectedBuildNamespace));
304 }
305
306 return NestedBuildNamespace(std::move(Namespaces));
307}
308
309Array JSONFormat::nestedBuildNamespaceToJSON(
310 const NestedBuildNamespace &NBN) const {
311 Array Result;
312 const auto &Namespaces = getNamespaces(NBN);
313 Result.reserve(Namespaces.size());
314
315 for (const auto &BN : Namespaces) {
316 Result.push_back(buildNamespaceToJSON(BN));
317 }
318
319 return Result;
320}
321
322//----------------------------------------------------------------------------
323// EntityName
324//----------------------------------------------------------------------------
325
326llvm::Expected<EntityName>
327JSONFormat::entityNameFromJSON(const Object &EntityNameObject) const {
328 const auto OptUSR = EntityNameObject.getString("usr");
329 if (!OptUSR) {
330 return ErrorBuilder::create(std::errc::invalid_argument,
331 ErrorMessages::FailedToReadObjectAtField, "USR",
332 "usr", "string")
333 .build();
334 }
335
336 const auto OptSuffix = EntityNameObject.getString("suffix");
337 if (!OptSuffix) {
338 return ErrorBuilder::create(std::errc::invalid_argument,
339 ErrorMessages::FailedToReadObjectAtField,
340 "Suffix", "suffix", "string")
341 .build();
342 }
343
344 const Array *OptNamespaceArray = EntityNameObject.getArray("namespace");
345 if (!OptNamespaceArray) {
346 return ErrorBuilder::create(std::errc::invalid_argument,
347 ErrorMessages::FailedToReadObjectAtField,
348 "NestedBuildNamespace", "namespace", "array")
349 .build();
350 }
351
352 auto ExpectedNamespace = nestedBuildNamespaceFromJSON(*OptNamespaceArray);
353 if (!ExpectedNamespace) {
354 return ErrorBuilder::wrap(ExpectedNamespace.takeError())
355 .context(ErrorMessages::ReadingFromField, "NestedBuildNamespace",
356 "namespace")
357 .build();
358 }
359
360 return EntityName{*OptUSR, *OptSuffix, std::move(*ExpectedNamespace)};
361}
362
363Object JSONFormat::entityNameToJSON(const EntityName &EN) const {
364 Object Result;
365 Result["usr"] = getUSR(EN);
366 Result["suffix"] = getSuffix(EN);
367 Result["namespace"] = nestedBuildNamespaceToJSON(getNamespace(EN));
368 return Result;
369}
370
371//----------------------------------------------------------------------------
372// EntityIdTableEntry
373//----------------------------------------------------------------------------
374
375llvm::Expected<std::pair<EntityName, EntityId>>
376JSONFormat::entityIdTableEntryFromJSON(
377 const Object &EntityIdTableEntryObject) const {
378
379 const Object *OptEntityNameObject =
380 EntityIdTableEntryObject.getObject("name");
381 if (!OptEntityNameObject) {
382 return ErrorBuilder::create(std::errc::invalid_argument,
383 ErrorMessages::FailedToReadObjectAtField,
384 "EntityName", "name", "object")
385 .build();
386 }
387
388 auto ExpectedEntityName = entityNameFromJSON(*OptEntityNameObject);
389 if (!ExpectedEntityName) {
390 return ErrorBuilder::wrap(ExpectedEntityName.takeError())
391 .context(ErrorMessages::ReadingFromField, "EntityName", "name")
392 .build();
393 }
394
395 const Value *EntityIdIntValue = EntityIdTableEntryObject.get("id");
396 if (!EntityIdIntValue) {
397 return ErrorBuilder::create(std::errc::invalid_argument,
398 ErrorMessages::FailedToReadObjectAtField,
399 "EntityId", "id",
400 "number (unsigned 64-bit integer)")
401 .build();
402 }
403
404 const std::optional<uint64_t> OptEntityIdInt =
405 EntityIdIntValue->getAsUINT64();
406 if (!OptEntityIdInt) {
407 return ErrorBuilder::create(std::errc::invalid_argument,
408 ErrorMessages::FailedToReadObjectAtField,
409 "EntityId", "id",
410 "number (unsigned 64-bit integer)")
411 .build();
412 }
413
414 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
415
416 return std::make_pair(std::move(*ExpectedEntityName), std::move(EI));
417}
418
419Object JSONFormat::entityIdTableEntryToJSON(const EntityName &EN,
420 EntityId EI) const {
421 Object Entry;
422 Entry["id"] = entityIdToJSON(EI);
423 Entry["name"] = entityNameToJSON(EN);
424 return Entry;
425}
426
427//----------------------------------------------------------------------------
428// EntityIdTable
429//----------------------------------------------------------------------------
430
431llvm::Expected<EntityIdTable>
432JSONFormat::entityIdTableFromJSON(const Array &EntityIdTableArray) const {
433 EntityIdTable IdTable;
434 std::map<EntityName, EntityId> &Entities = getEntities(IdTable);
435
436 for (const auto &[Index, EntityIdTableEntryValue] :
437 llvm::enumerate(EntityIdTableArray)) {
438
439 const Object *OptEntityIdTableEntryObject =
440 EntityIdTableEntryValue.getAsObject();
441 if (!OptEntityIdTableEntryObject) {
442 return ErrorBuilder::create(std::errc::invalid_argument,
443 ErrorMessages::FailedToReadObjectAtIndex,
444 "EntityIdTable entry", Index, "object")
445 .build();
446 }
447
448 auto ExpectedEntityIdTableEntry =
449 entityIdTableEntryFromJSON(*OptEntityIdTableEntryObject);
450 if (!ExpectedEntityIdTableEntry)
451 return ErrorBuilder::wrap(ExpectedEntityIdTableEntry.takeError())
452 .context(ErrorMessages::ReadingFromIndex, "EntityIdTable entry",
453 Index)
454 .build();
455
456 auto [EntityIt, EntityInserted] =
457 Entities.emplace(std::move(*ExpectedEntityIdTableEntry));
458 if (!EntityInserted) {
459 return ErrorBuilder::create(std::errc::invalid_argument,
460 ErrorMessages::FailedInsertionOnDuplication,
461 "EntityIdTable entry", Index, "EntityId",
462 getIndex(EntityIt->second))
463 .build();
464 }
465 }
466
467 return IdTable;
468}
469
470Array JSONFormat::entityIdTableToJSON(const EntityIdTable &IdTable) const {
471 Array EntityIdTableArray;
472 const auto &Entities = getEntities(IdTable);
473 EntityIdTableArray.reserve(Entities.size());
474
475 for (const auto &[EntityName, EntityId] : Entities) {
476 EntityIdTableArray.push_back(
477 entityIdTableEntryToJSON(EntityName, EntityId));
478 }
479
480 return EntityIdTableArray;
481}
482
483//----------------------------------------------------------------------------
484// EntitySummary
485//----------------------------------------------------------------------------
486
487llvm::Expected<std::unique_ptr<EntitySummary>>
488JSONFormat::entitySummaryFromJSON(const SummaryName &SN,
489 const Object &EntitySummaryObject,
490 EntityIdTable &IdTable) const {
491 auto InfoIt = FormatInfos.find(SN);
492 if (InfoIt == FormatInfos.end()) {
493 return ErrorBuilder::create(std::errc::invalid_argument,
494 ErrorMessages::FailedToDeserializeEntitySummary,
495 SN.str())
496 .build();
497 }
498
499 const auto &InfoEntry = InfoIt->second;
500 assert(InfoEntry.ForSummary == SN);
501
502 EntityIdConverter Converter(*this);
503 return InfoEntry.Deserialize(EntitySummaryObject, IdTable, Converter);
504}
505
506llvm::Expected<Object>
507JSONFormat::entitySummaryToJSON(const SummaryName &SN,
508 const EntitySummary &ES) const {
509 auto InfoIt = FormatInfos.find(SN);
510 if (InfoIt == FormatInfos.end()) {
511 return ErrorBuilder::create(std::errc::invalid_argument,
512 ErrorMessages::FailedToSerializeEntitySummary,
513 SN.str())
514 .build();
515 }
516
517 const auto &InfoEntry = InfoIt->second;
518 assert(InfoEntry.ForSummary == SN);
519
520 EntityIdConverter Converter(*this);
521 return InfoEntry.Serialize(ES, Converter);
522}
523
524//----------------------------------------------------------------------------
525// EntityDataMapEntry
526//----------------------------------------------------------------------------
527
528llvm::Expected<std::pair<EntityId, std::unique_ptr<EntitySummary>>>
529JSONFormat::entityDataMapEntryFromJSON(const Object &EntityDataMapEntryObject,
530 const SummaryName &SN,
531 EntityIdTable &IdTable) const {
532
533 const Value *EntityIdIntValue = EntityDataMapEntryObject.get("entity_id");
534 if (!EntityIdIntValue) {
535 return ErrorBuilder::create(std::errc::invalid_argument,
536 ErrorMessages::FailedToReadObjectAtField,
537 "EntityId", "entity_id",
538 "number (unsigned 64-bit integer)")
539 .build();
540 }
541
542 const std::optional<uint64_t> OptEntityIdInt =
543 EntityIdIntValue->getAsUINT64();
544 if (!OptEntityIdInt) {
545 return ErrorBuilder::create(std::errc::invalid_argument,
546 ErrorMessages::FailedToReadObjectAtField,
547 "EntityId", "entity_id", "integer")
548 .build();
549 }
550
551 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
552
553 const Object *OptEntitySummaryObject =
554 EntityDataMapEntryObject.getObject("entity_summary");
555 if (!OptEntitySummaryObject) {
556 return ErrorBuilder::create(std::errc::invalid_argument,
557 ErrorMessages::FailedToReadObjectAtField,
558 "EntitySummary", "entity_summary", "object")
559 .build();
560 }
561
562 auto ExpectedEntitySummary =
563 entitySummaryFromJSON(SN, *OptEntitySummaryObject, IdTable);
564 if (!ExpectedEntitySummary) {
565 return ErrorBuilder::wrap(ExpectedEntitySummary.takeError())
566 .context(ErrorMessages::ReadingFromField, "EntitySummary",
567 "entity_summary")
568 .build();
569 }
570
571 return std::make_pair(std::move(EI), std::move(*ExpectedEntitySummary));
572}
573
574//----------------------------------------------------------------------------
575// EntityDataMap
576//----------------------------------------------------------------------------
577
578llvm::Expected<std::map<EntityId, std::unique_ptr<EntitySummary>>>
579JSONFormat::entityDataMapFromJSON(const SummaryName &SN,
580 const Array &EntityDataArray,
581 EntityIdTable &IdTable) const {
582 std::map<EntityId, std::unique_ptr<EntitySummary>> EntityDataMap;
583
584 for (const auto &[Index, EntityDataMapEntryValue] :
585 llvm::enumerate(EntityDataArray)) {
586
587 const Object *OptEntityDataMapEntryObject =
588 EntityDataMapEntryValue.getAsObject();
589 if (!OptEntityDataMapEntryObject) {
590 return ErrorBuilder::create(std::errc::invalid_argument,
591 ErrorMessages::FailedToReadObjectAtIndex,
592 "EntitySummary entry", Index, "object")
593 .build();
594 }
595
596 auto ExpectedEntityDataMapEntry =
597 entityDataMapEntryFromJSON(*OptEntityDataMapEntryObject, SN, IdTable);
598 if (!ExpectedEntityDataMapEntry)
599 return ErrorBuilder::wrap(ExpectedEntityDataMapEntry.takeError())
600 .context(ErrorMessages::ReadingFromIndex, "EntitySummary entry",
601 Index)
602 .build();
603
604 auto [DataIt, DataInserted] =
605 EntityDataMap.insert(std::move(*ExpectedEntityDataMapEntry));
606 if (!DataInserted) {
607 return ErrorBuilder::create(std::errc::invalid_argument,
608 ErrorMessages::FailedInsertionOnDuplication,
609 "EntitySummary entry", Index, "EntityId",
610 getIndex(DataIt->first))
611 .build();
612 }
613 }
614
615 return std::move(EntityDataMap);
616}
617
618llvm::Expected<Array> JSONFormat::entityDataMapToJSON(
619 const SummaryName &SN,
620 const std::map<EntityId, std::unique_ptr<EntitySummary>> &EntityDataMap)
621 const {
622 Array Result;
623 Result.reserve(EntityDataMap.size());
624
625 for (const auto &[Index, EntityDataMapEntry] :
626 llvm::enumerate(EntityDataMap)) {
627 const auto &[EntityId, EntitySummary] = EntityDataMapEntry;
628
629 Object Entry;
630
631 Entry["entity_id"] = entityIdToJSON(EntityId);
632
633 auto ExpectedEntitySummaryObject = entitySummaryToJSON(SN, *EntitySummary);
634 if (!ExpectedEntitySummaryObject) {
635 return ErrorBuilder::wrap(ExpectedEntitySummaryObject.takeError())
636 .context(ErrorMessages::WritingToIndex, "EntitySummary entry", Index)
637 .build();
638 }
639
640 Entry["entity_summary"] = std::move(*ExpectedEntitySummaryObject);
641
642 Result.push_back(std::move(Entry));
643 }
644
645 return Result;
646}
647
648//----------------------------------------------------------------------------
649// SummaryDataMapEntry
650//----------------------------------------------------------------------------
651
652llvm::Expected<
653 std::pair<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
654JSONFormat::summaryDataMapEntryFromJSON(const Object &SummaryDataMapEntryObject,
655 EntityIdTable &IdTable) const {
656
657 std::optional<llvm::StringRef> OptSummaryNameStr =
658 SummaryDataMapEntryObject.getString("summary_name");
659 if (!OptSummaryNameStr) {
660 return ErrorBuilder::create(std::errc::invalid_argument,
661 ErrorMessages::FailedToReadObjectAtField,
662 "SummaryName", "summary_name", "string")
663 .build();
664 }
665
666 SummaryName SN = summaryNameFromJSON(*OptSummaryNameStr);
667
668 const Array *OptEntityDataArray =
669 SummaryDataMapEntryObject.getArray("summary_data");
670 if (!OptEntityDataArray) {
671 return ErrorBuilder::create(std::errc::invalid_argument,
672 ErrorMessages::FailedToReadObjectAtField,
673 "EntitySummary entries", "summary_data",
674 "array")
675 .build();
676 }
677
678 auto ExpectedEntityDataMap =
679 entityDataMapFromJSON(SN, *OptEntityDataArray, IdTable);
680 if (!ExpectedEntityDataMap)
681 return ErrorBuilder::wrap(ExpectedEntityDataMap.takeError())
682 .context(ErrorMessages::ReadingFromField, "EntitySummary entries",
683 "summary_data")
684 .build();
685
686 return std::make_pair(std::move(SN), std::move(*ExpectedEntityDataMap));
687}
688
689llvm::Expected<Object> JSONFormat::summaryDataMapEntryToJSON(
690 const SummaryName &SN,
691 const std::map<EntityId, std::unique_ptr<EntitySummary>> &SD) const {
692 Object Result;
693
694 Result["summary_name"] = summaryNameToJSON(SN);
695
696 auto ExpectedSummaryDataArray = entityDataMapToJSON(SN, SD);
697 if (!ExpectedSummaryDataArray) {
698 return ErrorBuilder::wrap(ExpectedSummaryDataArray.takeError())
699 .context(ErrorMessages::WritingToField, "EntitySummary entries",
700 "summary_data")
701 .build();
702 }
703
704 Result["summary_data"] = std::move(*ExpectedSummaryDataArray);
705
706 return Result;
707}
708
709//----------------------------------------------------------------------------
710// SummaryDataMap
711//----------------------------------------------------------------------------
712
713llvm::Expected<
714 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
715JSONFormat::summaryDataMapFromJSON(const Array &SummaryDataArray,
716 EntityIdTable &IdTable) const {
717 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>
718 SummaryDataMap;
719
720 for (const auto &[Index, SummaryDataMapEntryValue] :
721 llvm::enumerate(SummaryDataArray)) {
722
723 const Object *OptSummaryDataMapEntryObject =
724 SummaryDataMapEntryValue.getAsObject();
725 if (!OptSummaryDataMapEntryObject) {
726 return ErrorBuilder::create(std::errc::invalid_argument,
727 ErrorMessages::FailedToReadObjectAtIndex,
728 "SummaryData entry", Index, "object")
729 .build();
730 }
731
732 auto ExpectedSummaryDataMapEntry =
733 summaryDataMapEntryFromJSON(*OptSummaryDataMapEntryObject, IdTable);
734 if (!ExpectedSummaryDataMapEntry) {
735 return ErrorBuilder::wrap(ExpectedSummaryDataMapEntry.takeError())
736 .context(ErrorMessages::ReadingFromIndex, "SummaryData entry", Index)
737 .build();
738 }
739
740 auto [SummaryIt, SummaryInserted] =
741 SummaryDataMap.emplace(std::move(*ExpectedSummaryDataMapEntry));
742 if (!SummaryInserted) {
743 return ErrorBuilder::create(std::errc::invalid_argument,
744 ErrorMessages::FailedInsertionOnDuplication,
745 "SummaryData entry", Index, "SummaryName",
746 SummaryIt->first.str())
747 .build();
748 }
749 }
750
751 return std::move(SummaryDataMap);
752}
753
754llvm::Expected<Array> JSONFormat::summaryDataMapToJSON(
755 const std::map<SummaryName,
756 std::map<EntityId, std::unique_ptr<EntitySummary>>>
757 &SummaryDataMap) const {
758 Array Result;
759 Result.reserve(SummaryDataMap.size());
760
761 for (const auto &[Index, SummaryDataMapEntry] :
762 llvm::enumerate(SummaryDataMap)) {
763 const auto &[SummaryName, DataMap] = SummaryDataMapEntry;
764
765 auto ExpectedSummaryDataMapObject =
766 summaryDataMapEntryToJSON(SummaryName, DataMap);
767 if (!ExpectedSummaryDataMapObject) {
768 return ErrorBuilder::wrap(ExpectedSummaryDataMapObject.takeError())
769 .context(ErrorMessages::WritingToIndex, "SummaryData entry", Index)
770 .build();
771 }
772
773 Result.push_back(std::move(*ExpectedSummaryDataMapObject));
774 }
775
776 return std::move(Result);
777}
778
779//----------------------------------------------------------------------------
780// TUSummary
781//----------------------------------------------------------------------------
782
784 auto ExpectedJSON = readJSON(Path);
785 if (!ExpectedJSON) {
786 return ErrorBuilder::wrap(ExpectedJSON.takeError())
787 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
788 .build();
789 }
790
791 Object *RootObjectPtr = ExpectedJSON->getAsObject();
792 if (!RootObjectPtr) {
793 return ErrorBuilder::create(std::errc::invalid_argument,
794 ErrorMessages::FailedToReadObject, "TUSummary",
795 "object")
796 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
797 .build();
798 }
799
800 const Object &RootObject = *RootObjectPtr;
801
802 const Object *TUNamespaceObject = RootObject.getObject("tu_namespace");
803 if (!TUNamespaceObject) {
804 return ErrorBuilder::create(std::errc::invalid_argument,
805 ErrorMessages::FailedToReadObjectAtField,
806 "BuildNamespace", "tu_namespace", "object")
807 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
808 .build();
809 }
810
811 auto ExpectedTUNamespace = buildNamespaceFromJSON(*TUNamespaceObject);
812 if (!ExpectedTUNamespace) {
813 return ErrorBuilder::wrap(ExpectedTUNamespace.takeError())
814 .context(ErrorMessages::ReadingFromField, "BuildNamespace",
815 "tu_namespace")
816 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
817 .build();
818 }
819
820 TUSummary Summary(std::move(*ExpectedTUNamespace));
821
822 {
823 const Array *IdTableArray = RootObject.getArray("id_table");
824 if (!IdTableArray) {
825 return ErrorBuilder::create(std::errc::invalid_argument,
826 ErrorMessages::FailedToReadObjectAtField,
827 "IdTable", "id_table", "array")
828 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
829 .build();
830 }
831
832 auto ExpectedIdTable = entityIdTableFromJSON(*IdTableArray);
833 if (!ExpectedIdTable) {
834 return ErrorBuilder::wrap(ExpectedIdTable.takeError())
835 .context(ErrorMessages::ReadingFromField, "IdTable", "id_table")
836 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
837 .build();
838 }
839
840 getIdTable(Summary) = std::move(*ExpectedIdTable);
841 }
842
843 {
844 const Array *SummaryDataArray = RootObject.getArray("data");
845 if (!SummaryDataArray) {
846 return ErrorBuilder::create(std::errc::invalid_argument,
847 ErrorMessages::FailedToReadObjectAtField,
848 "SummaryData entries", "data", "array")
849 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
850 .build();
851 }
852
853 auto ExpectedSummaryDataMap =
854 summaryDataMapFromJSON(*SummaryDataArray, getIdTable(Summary));
855 if (!ExpectedSummaryDataMap) {
856 return ErrorBuilder::wrap(ExpectedSummaryDataMap.takeError())
857 .context(ErrorMessages::ReadingFromField, "SummaryData entries",
858 "data")
859 .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
860 .build();
861 }
862
863 getData(Summary) = std::move(*ExpectedSummaryDataMap);
864 }
865
866 return std::move(Summary);
867}
868
870 llvm::StringRef Path) {
871 Object RootObject;
872
873 RootObject["tu_namespace"] = buildNamespaceToJSON(getTUNamespace(S));
874
875 RootObject["id_table"] = entityIdTableToJSON(getIdTable(S));
876
877 auto ExpectedDataObject = summaryDataMapToJSON(getData(S));
878 if (!ExpectedDataObject) {
879 return ErrorBuilder::wrap(ExpectedDataObject.takeError())
880 .context(ErrorMessages::WritingToFile, "TUSummary", Path)
881 .build();
882 }
883
884 RootObject["data"] = std::move(*ExpectedDataObject);
885
886 if (auto Error = writeJSON(std::move(RootObject), Path)) {
887 return ErrorBuilder::wrap(std::move(Error))
888 .context(ErrorMessages::WritingToFile, "TUSummary", Path)
889 .build();
890 }
891
892 return llvm::Error::success();
893}
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
static Decl::Kind getKind(const Decl *D)
static std::string getUSR(const Decl *D)
llvm::json::Object Object
llvm::json::Array Array
Represents a single namespace in the build process.
Manages entity name interning and provides efficient EntityId handles.
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
Uniquely identifies an entity in a program.
Definition EntityName.h:28
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.
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
Represents a hierarchical sequence of build namespaces.
EntityId makeEntityId(const size_t Index) const
Uniquely identifies an analysis summary.
Definition SummaryName.h:22
llvm::StringRef str() const
Explicit conversion to the underlying string representation.
Definition SummaryName.h:31
Data extracted for a given translation unit and for a given set of analyses.
Definition TUSummary.h:24
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
std::optional< BuildNamespaceKind > parseBuildNamespaceKind(llvm::StringRef Str)
llvm::StringRef toString(BuildNamespaceKind BNK)
@ Result
The result type of a method or function.
Definition TypeBase.h:905
unsigned long uint64_t