clang 23.0.0git
JSONFormatImpl.cpp
Go to the documentation of this file.
1//===- JSONFormatImpl.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#include "llvm/Support/Registry.h"
13
14// NOLINTNEXTLINE(misc-use-internal-linkage)
17
18static clang::ssaf::SerializationFormatRegistry::Add<clang::ssaf::JSONFormat>
19 RegisterJSONFormat("json", "JSON serialization format");
20
21namespace clang::ssaf {
22
23//----------------------------------------------------------------------------
24// JSON Reader and Writer
25//----------------------------------------------------------------------------
26
27llvm::Expected<Value> readJSON(llvm::StringRef Path) {
28 if (!llvm::sys::fs::exists(Path)) {
29 return ErrorBuilder::create(std::errc::no_such_file_or_directory,
32 .build();
33 }
34
35 if (llvm::sys::fs::is_directory(Path)) {
36 return ErrorBuilder::create(std::errc::is_a_directory,
39 .build();
40 }
41
42 if (!Path.ends_with(JSONFormatFileExtension)) {
43 return ErrorBuilder::create(std::errc::invalid_argument,
45 llvm::formatv(ErrorMessages::FileIsNotJSON,
47 .build();
48 }
49
50 auto BufferOrError = llvm::MemoryBuffer::getFile(Path);
51 if (!BufferOrError) {
52 const std::error_code EC = BufferOrError.getError();
54 EC.message())
55 .build();
56 }
57
58 return llvm::json::parse(BufferOrError.get()->getBuffer());
59}
60
61llvm::Error writeJSON(Value &&V, llvm::StringRef Path) {
62 if (llvm::sys::fs::exists(Path)) {
63 return ErrorBuilder::create(std::errc::file_exists,
66 .build();
67 }
68
69 llvm::StringRef Dir = llvm::sys::path::parent_path(Path);
70 if (!Dir.empty() && !llvm::sys::fs::is_directory(Dir)) {
71 return ErrorBuilder::create(std::errc::no_such_file_or_directory,
74 .build();
75 }
76
77 if (!Path.ends_with(JSONFormatFileExtension)) {
78 return ErrorBuilder::create(std::errc::invalid_argument,
80 llvm::formatv(ErrorMessages::FileIsNotJSON,
82 .build();
83 }
84
85 std::error_code EC;
86 llvm::raw_fd_ostream OutStream(Path, EC, llvm::sys::fs::OF_Text);
87
88 if (EC) {
90 EC.message())
91 .build();
92 }
93
94 OutStream << llvm::formatv("{0:2}\n", V);
95 OutStream.flush();
96
97 // This path handles post-write stream errors (e.g. ENOSPC after buffered
98 // writes). It is difficult to exercise in unit tests so it is intentionally
99 // left without test coverage.
100 if (OutStream.has_error()) {
101 return ErrorBuilder::create(OutStream.error(),
103 OutStream.error().message())
104 .build();
105 }
106
107 return llvm::Error::success();
108}
109
110//----------------------------------------------------------------------------
111// JSONFormat Static Methods
112//----------------------------------------------------------------------------
113
114std::map<SummaryName, JSONFormat::FormatInfo> JSONFormat::initFormatInfos() {
115 std::map<SummaryName, FormatInfo> FormatInfos;
116 for (const auto &FormatInfoEntry : llvm::Registry<FormatInfo>::entries()) {
117 std::unique_ptr<FormatInfo> Info = FormatInfoEntry.instantiate();
118 bool Inserted = FormatInfos.try_emplace(Info->ForSummary, *Info).second;
119 if (!Inserted) {
120 llvm::report_fatal_error(
121 "FormatInfo is already registered for summary: " +
122 Info->ForSummary.str());
123 }
124 }
125 return FormatInfos;
126}
127
129 llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) const {
130 for (const auto &Entry : llvm::Registry<FormatInfo>::entries())
131 Callback(Entry.getName(), Entry.getDesc());
132}
133
134//----------------------------------------------------------------------------
135// SummaryName
136//----------------------------------------------------------------------------
137
138SummaryName summaryNameFromJSON(llvm::StringRef SummaryNameStr) {
139 return SummaryName(SummaryNameStr.str());
140}
141
142llvm::StringRef summaryNameToJSON(const SummaryName &SN) { return SN.str(); }
143
144//----------------------------------------------------------------------------
145// EntityId
146//----------------------------------------------------------------------------
147
148EntityId JSONFormat::entityIdFromJSON(const uint64_t EntityIdIndex) const {
149 return makeEntityId(static_cast<size_t>(EntityIdIndex));
150}
151
152uint64_t JSONFormat::entityIdToJSON(EntityId EI) const {
153 return static_cast<uint64_t>(getIndex(EI));
154}
155
156llvm::Expected<EntityId>
157JSONFormat::entityIdFromJSONObject(const Object &EntityIdObject) {
158 if (EntityIdObject.size() != 1) {
159 return ErrorBuilder::create(std::errc::invalid_argument,
162 .build();
163 }
164
165 const llvm::json::Value *AtVal = EntityIdObject.get(JSONEntityIdKey);
166 if (!AtVal) {
167 return ErrorBuilder::create(std::errc::invalid_argument,
170 .build();
171 }
172
173 std::optional<uint64_t> OptEntityIdIndex = AtVal->getAsUINT64();
174 if (!OptEntityIdIndex) {
175 return ErrorBuilder::create(std::errc::invalid_argument,
178 .build();
179 }
180
181 return makeEntityId(static_cast<size_t>(*OptEntityIdIndex));
182}
183
184Object JSONFormat::entityIdToJSONObject(EntityId EI) {
185 Object Result;
186 Result[JSONEntityIdKey] = static_cast<uint64_t>(getIndex(EI));
187 return Result;
188}
189
190//----------------------------------------------------------------------------
191// BuildNamespaceKind
192//----------------------------------------------------------------------------
193
194llvm::Expected<BuildNamespaceKind>
195buildNamespaceKindFromJSON(llvm::StringRef BuildNamespaceKindStr) {
196 auto OptBuildNamespaceKind =
197 buildNamespaceKindFromString(BuildNamespaceKindStr);
198 if (!OptBuildNamespaceKind) {
199 return ErrorBuilder::create(std::errc::invalid_argument,
201 BuildNamespaceKindStr)
202 .build();
203 }
204 return *OptBuildNamespaceKind;
205}
206
207// Provided for consistency with respect to rest of the codebase.
209 return buildNamespaceKindToString(BNK);
210}
211
212//----------------------------------------------------------------------------
213// BuildNamespace
214//----------------------------------------------------------------------------
215
217JSONFormat::buildNamespaceFromJSON(const Object &BuildNamespaceObject) const {
218 auto OptBuildNamespaceKindStr = BuildNamespaceObject.getString("kind");
219 if (!OptBuildNamespaceKindStr) {
220 return ErrorBuilder::create(std::errc::invalid_argument,
222 "BuildNamespaceKind", "kind", "string")
223 .build();
224 }
225
226 auto ExpectedKind = buildNamespaceKindFromJSON(*OptBuildNamespaceKindStr);
227 if (!ExpectedKind) {
228 return ErrorBuilder::wrap(ExpectedKind.takeError())
229 .context(ErrorMessages::ReadingFromField, "BuildNamespaceKind", "kind")
230 .build();
231 }
232
233 auto OptNameStr = BuildNamespaceObject.getString("name");
234 if (!OptNameStr) {
235 return ErrorBuilder::create(std::errc::invalid_argument,
237 "BuildNamespaceName", "name", "string")
238 .build();
239 }
240
241 return {BuildNamespace(*ExpectedKind, *OptNameStr)};
242}
243
244Object JSONFormat::buildNamespaceToJSON(const BuildNamespace &BN) const {
245 Object Result;
247 Result["name"] = getName(BN);
248 return Result;
249}
250
251//----------------------------------------------------------------------------
252// NestedBuildNamespace
253//----------------------------------------------------------------------------
254
255llvm::Expected<NestedBuildNamespace> JSONFormat::nestedBuildNamespaceFromJSON(
256 const Array &NestedBuildNamespaceArray) const {
257 std::vector<BuildNamespace> Namespaces;
258
259 size_t NamespaceCount = NestedBuildNamespaceArray.size();
260 Namespaces.reserve(NamespaceCount);
261
262 for (const auto &[Index, BuildNamespaceValue] :
263 llvm::enumerate(NestedBuildNamespaceArray)) {
264 const Object *BuildNamespaceObject = BuildNamespaceValue.getAsObject();
265 if (!BuildNamespaceObject) {
266 return ErrorBuilder::create(std::errc::invalid_argument,
268 "BuildNamespace", Index, "object")
269 .build();
270 }
271
272 auto ExpectedBuildNamespace = buildNamespaceFromJSON(*BuildNamespaceObject);
273 if (!ExpectedBuildNamespace) {
274 return ErrorBuilder::wrap(ExpectedBuildNamespace.takeError())
275 .context(ErrorMessages::ReadingFromIndex, "BuildNamespace", Index)
276 .build();
277 }
278
279 Namespaces.push_back(std::move(*ExpectedBuildNamespace));
280 }
281
282 return NestedBuildNamespace(std::move(Namespaces));
283}
284
285Array JSONFormat::nestedBuildNamespaceToJSON(
286 const NestedBuildNamespace &NBN) const {
287 Array Result;
288 const auto &Namespaces = getNamespaces(NBN);
289 Result.reserve(Namespaces.size());
290
291 for (const auto &BN : Namespaces) {
292 Result.push_back(buildNamespaceToJSON(BN));
293 }
294
295 return Result;
296}
297
298//----------------------------------------------------------------------------
299// EntityName
300//----------------------------------------------------------------------------
301
302llvm::Expected<EntityName>
303JSONFormat::entityNameFromJSON(const Object &EntityNameObject) const {
304 const auto OptUSR = EntityNameObject.getString("usr");
305 if (!OptUSR) {
306 return ErrorBuilder::create(std::errc::invalid_argument,
308 "usr", "string")
309 .build();
310 }
311
312 const auto OptSuffix = EntityNameObject.getString("suffix");
313 if (!OptSuffix) {
314 return ErrorBuilder::create(std::errc::invalid_argument,
316 "Suffix", "suffix", "string")
317 .build();
318 }
319
320 const Array *OptNamespaceArray = EntityNameObject.getArray("namespace");
321 if (!OptNamespaceArray) {
322 return ErrorBuilder::create(std::errc::invalid_argument,
324 "NestedBuildNamespace", "namespace", "array")
325 .build();
326 }
327
328 auto ExpectedNamespace = nestedBuildNamespaceFromJSON(*OptNamespaceArray);
329 if (!ExpectedNamespace) {
330 return ErrorBuilder::wrap(ExpectedNamespace.takeError())
331 .context(ErrorMessages::ReadingFromField, "NestedBuildNamespace",
332 "namespace")
333 .build();
334 }
335
336 return EntityName{*OptUSR, *OptSuffix, std::move(*ExpectedNamespace)};
337}
338
339Object JSONFormat::entityNameToJSON(const EntityName &EN) const {
340 Object Result;
341 Result["usr"] = getUSR(EN);
342 Result["suffix"] = getSuffix(EN);
343 Result["namespace"] = nestedBuildNamespaceToJSON(getNamespace(EN));
344 return Result;
345}
346
347//----------------------------------------------------------------------------
348// EntityLinkageType
349//----------------------------------------------------------------------------
350
351llvm::Expected<EntityLinkageType>
352entityLinkageTypeFromJSON(llvm::StringRef EntityLinkageTypeStr) {
353 auto OptEntityLinkageType = entityLinkageTypeFromString(EntityLinkageTypeStr);
354 if (!OptEntityLinkageType) {
355 return ErrorBuilder::create(std::errc::invalid_argument,
357 EntityLinkageTypeStr)
358 .build();
359 }
360 return *OptEntityLinkageType;
361}
362
363// Provided for consistency with respect to rest of the codebase.
365 return entityLinkageTypeToString(LT);
366}
367
368//----------------------------------------------------------------------------
369// EntityLinkage
370//----------------------------------------------------------------------------
371
373JSONFormat::entityLinkageFromJSON(const Object &EntityLinkageObject) const {
374 auto OptLinkageStr = EntityLinkageObject.getString("type");
375 if (!OptLinkageStr) {
376 return ErrorBuilder::create(std::errc::invalid_argument,
378 "EntityLinkageType", "type", "string")
379 .build();
380 }
381
382 auto ExpectedLinkageType = entityLinkageTypeFromJSON(*OptLinkageStr);
383 if (!ExpectedLinkageType) {
384 return ErrorBuilder::wrap(ExpectedLinkageType.takeError())
385 .context(ErrorMessages::ReadingFromField, "EntityLinkageType", "type")
386 .build();
387 }
388
389 return EntityLinkage(*ExpectedLinkageType);
390}
391
392Object JSONFormat::entityLinkageToJSON(const EntityLinkage &EL) const {
393 Object Result;
394 Result["type"] = entityLinkageTypeToJSON(getLinkage(EL));
395 return Result;
396}
397
398//----------------------------------------------------------------------------
399// EntityIdTableEntry
400//----------------------------------------------------------------------------
401
402llvm::Expected<std::pair<EntityName, EntityId>>
403JSONFormat::entityIdTableEntryFromJSON(
404 const Object &EntityIdTableEntryObject) const {
405
406 const Object *OptEntityNameObject =
407 EntityIdTableEntryObject.getObject("name");
408 if (!OptEntityNameObject) {
409 return ErrorBuilder::create(std::errc::invalid_argument,
411 "EntityName", "name", "object")
412 .build();
413 }
414
415 auto ExpectedEntityName = entityNameFromJSON(*OptEntityNameObject);
416 if (!ExpectedEntityName) {
417 return ErrorBuilder::wrap(ExpectedEntityName.takeError())
418 .context(ErrorMessages::ReadingFromField, "EntityName", "name")
419 .build();
420 }
421
422 const Value *EntityIdIntValue = EntityIdTableEntryObject.get("id");
423 if (!EntityIdIntValue) {
424 return ErrorBuilder::create(std::errc::invalid_argument,
426 "EntityId", "id",
427 "number (unsigned 64-bit integer)")
428 .build();
429 }
430
431 const std::optional<uint64_t> OptEntityIdInt =
432 EntityIdIntValue->getAsUINT64();
433 if (!OptEntityIdInt) {
434 return ErrorBuilder::create(std::errc::invalid_argument,
436 "EntityId", "id",
437 "number (unsigned 64-bit integer)")
438 .build();
439 }
440
441 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
442
443 return std::make_pair(std::move(*ExpectedEntityName), std::move(EI));
444}
445
446Object JSONFormat::entityIdTableEntryToJSON(const EntityName &EN,
447 EntityId EI) const {
448 Object Entry;
449 Entry["id"] = entityIdToJSON(EI);
450 Entry["name"] = entityNameToJSON(EN);
451 return Entry;
452}
453
454//----------------------------------------------------------------------------
455// EntityIdTable
456//----------------------------------------------------------------------------
457
458llvm::Expected<EntityIdTable>
459JSONFormat::entityIdTableFromJSON(const Array &EntityIdTableArray) const {
460 EntityIdTable IdTable;
461 std::map<EntityName, EntityId> &Entities = getEntities(IdTable);
462
463 for (const auto &[Index, EntityIdTableEntryValue] :
464 llvm::enumerate(EntityIdTableArray)) {
465 const Object *OptEntityIdTableEntryObject =
466 EntityIdTableEntryValue.getAsObject();
467 if (!OptEntityIdTableEntryObject) {
468 return ErrorBuilder::create(std::errc::invalid_argument,
470 "EntityIdTable entry", Index, "object")
471 .build();
472 }
473
474 auto ExpectedEntityIdTableEntry =
475 entityIdTableEntryFromJSON(*OptEntityIdTableEntryObject);
476 if (!ExpectedEntityIdTableEntry) {
477 return ErrorBuilder::wrap(ExpectedEntityIdTableEntry.takeError())
478 .context(ErrorMessages::ReadingFromIndex, "EntityIdTable entry",
479 Index)
480 .build();
481 }
482
483 auto [EntityIt, EntityInserted] =
484 Entities.emplace(std::move(*ExpectedEntityIdTableEntry));
485 if (!EntityInserted) {
486 return ErrorBuilder::create(std::errc::invalid_argument,
488 "EntityIdTable entry", Index,
489 EntityIt->second)
490 .build();
491 }
492 }
493
494 return IdTable;
495}
496
497Array JSONFormat::entityIdTableToJSON(const EntityIdTable &IdTable) const {
498 Array EntityIdTableArray;
499 const auto &Entities = getEntities(IdTable);
500 EntityIdTableArray.reserve(Entities.size());
501
502 for (const auto &[EntityName, EntityId] : Entities) {
503 EntityIdTableArray.push_back(
504 entityIdTableEntryToJSON(EntityName, EntityId));
505 }
506
507 return EntityIdTableArray;
508}
509
510//----------------------------------------------------------------------------
511// LinkageTableEntry
512//----------------------------------------------------------------------------
513
514llvm::Expected<std::pair<EntityId, EntityLinkage>>
515JSONFormat::linkageTableEntryFromJSON(
516 const Object &LinkageTableEntryObject) const {
517 const Value *EntityIdIntValue = LinkageTableEntryObject.get("id");
518 if (!EntityIdIntValue) {
519 return ErrorBuilder::create(std::errc::invalid_argument,
521 "EntityId", "id",
522 "number (unsigned 64-bit integer)")
523 .build();
524 }
525
526 const std::optional<uint64_t> OptEntityIdInt =
527 EntityIdIntValue->getAsUINT64();
528 if (!OptEntityIdInt) {
529 return ErrorBuilder::create(std::errc::invalid_argument,
531 "EntityId", "id",
532 "number (unsigned 64-bit integer)")
533 .build();
534 }
535
536 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
537
538 const Object *OptEntityLinkageObject =
539 LinkageTableEntryObject.getObject("linkage");
540 if (!OptEntityLinkageObject) {
541 return ErrorBuilder::create(std::errc::invalid_argument,
543 "EntityLinkage", "linkage", "object")
544 .build();
545 }
546
547 auto ExpectedEntityLinkage = entityLinkageFromJSON(*OptEntityLinkageObject);
548 if (!ExpectedEntityLinkage) {
549 return ErrorBuilder::wrap(ExpectedEntityLinkage.takeError())
550 .context(ErrorMessages::ReadingFromField, "EntityLinkage", "linkage")
551 .build();
552 }
553
554 return std::make_pair(std::move(EI), std::move(*ExpectedEntityLinkage));
555}
556
557Object JSONFormat::linkageTableEntryToJSON(EntityId EI,
558 const EntityLinkage &EL) const {
559 Object Entry;
560 Entry["id"] = entityIdToJSON(EI);
561 Entry["linkage"] = entityLinkageToJSON(EL);
562 return Entry;
563}
564
565//----------------------------------------------------------------------------
566// LinkageTable
567//----------------------------------------------------------------------------
568
569// ExpectedIds is the set of EntityIds from the IdTable that must appear in the
570// linkage table—no more, no fewer. It is taken by value because it is consumed
571// during parsing: each successfully matched id is erased from the set, and any
572// ids remaining at the end are reported as missing.
573llvm::Expected<std::map<EntityId, EntityLinkage>>
574JSONFormat::linkageTableFromJSON(const Array &LinkageTableArray,
575 std::set<EntityId> ExpectedIds) const {
576 std::map<EntityId, EntityLinkage> LinkageTable;
577
578 for (const auto &[Index, LinkageTableEntryValue] :
579 llvm::enumerate(LinkageTableArray)) {
580 const Object *OptLinkageTableEntryObject =
581 LinkageTableEntryValue.getAsObject();
582 if (!OptLinkageTableEntryObject) {
583 return ErrorBuilder::create(std::errc::invalid_argument,
585 "LinkageTable entry", Index, "object")
586 .build();
587 }
588
589 auto ExpectedLinkageTableEntry =
590 linkageTableEntryFromJSON(*OptLinkageTableEntryObject);
591 if (!ExpectedLinkageTableEntry) {
592 return ErrorBuilder::wrap(ExpectedLinkageTableEntry.takeError())
593 .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", Index)
594 .build();
595 }
596
597 const EntityId EI = ExpectedLinkageTableEntry->first;
598
599 auto [It, Inserted] =
600 LinkageTable.insert(std::move(*ExpectedLinkageTableEntry));
601 if (!Inserted) {
602 return ErrorBuilder::create(std::errc::invalid_argument,
604 "LinkageTable entry", Index, It->first)
605 .build();
606 }
607
608 if (ExpectedIds.erase(EI) == 0) {
610 std::errc::invalid_argument,
612 .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", Index)
613 .build();
614 }
615 }
616
617 if (!ExpectedIds.empty()) {
619 std::errc::invalid_argument,
621 *ExpectedIds.begin())
622 .build();
623 }
624
625 return LinkageTable;
626}
627
628Array JSONFormat::linkageTableToJSON(
629 const std::map<EntityId, EntityLinkage> &LinkageTable) const {
630 Array Result;
631 Result.reserve(LinkageTable.size());
632
633 for (const auto &[EI, EL] : LinkageTable) {
634 Result.push_back(linkageTableEntryToJSON(EI, EL));
635 }
636
637 return Result;
638}
639
640//----------------------------------------------------------------------------
641// EntitySummary
642//----------------------------------------------------------------------------
643
644llvm::Expected<std::unique_ptr<EntitySummary>>
645JSONFormat::entitySummaryFromJSON(const SummaryName &SN,
646 const Object &EntitySummaryObject,
647 EntityIdTable &IdTable) const {
648 auto InfoIt = FormatInfos.find(SN);
649 if (InfoIt == FormatInfos.end()) {
651 std::errc::invalid_argument,
653 .build();
654 }
655
656 const auto &InfoEntry = InfoIt->second;
657 assert(InfoEntry.ForSummary == SN);
658
659 return InfoEntry.Deserialize(EntitySummaryObject, IdTable,
660 entityIdFromJSONObject);
661}
662
663llvm::Expected<Object>
664JSONFormat::entitySummaryToJSON(const SummaryName &SN,
665 const EntitySummary &ES) const {
666 auto InfoIt = FormatInfos.find(SN);
667 if (InfoIt == FormatInfos.end()) {
669 std::errc::invalid_argument,
671 .build();
672 }
673
674 const auto &InfoEntry = InfoIt->second;
675 assert(InfoEntry.ForSummary == SN);
676
677 return InfoEntry.Serialize(ES, entityIdToJSONObject);
678}
679
680//----------------------------------------------------------------------------
681// EntityDataMapEntry
682//----------------------------------------------------------------------------
683
684llvm::Expected<std::pair<EntityId, std::unique_ptr<EntitySummary>>>
685JSONFormat::entityDataMapEntryFromJSON(const Object &EntityDataMapEntryObject,
686 const SummaryName &SN,
687 EntityIdTable &IdTable) const {
688
689 const Value *EntityIdIntValue = EntityDataMapEntryObject.get("entity_id");
690 if (!EntityIdIntValue) {
691 return ErrorBuilder::create(std::errc::invalid_argument,
693 "EntityId", "entity_id",
694 "number (unsigned 64-bit integer)")
695 .build();
696 }
697
698 const std::optional<uint64_t> OptEntityIdInt =
699 EntityIdIntValue->getAsUINT64();
700 if (!OptEntityIdInt) {
701 return ErrorBuilder::create(std::errc::invalid_argument,
703 "EntityId", "entity_id",
704 "number (unsigned 64-bit integer)")
705 .build();
706 }
707
708 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
709
710 const Object *OptEntitySummaryObject =
711 EntityDataMapEntryObject.getObject("entity_summary");
712 if (!OptEntitySummaryObject) {
713 return ErrorBuilder::create(std::errc::invalid_argument,
715 "EntitySummary", "entity_summary", "object")
716 .build();
717 }
718
719 auto ExpectedEntitySummary =
720 entitySummaryFromJSON(SN, *OptEntitySummaryObject, IdTable);
721 if (!ExpectedEntitySummary) {
722 return ErrorBuilder::wrap(ExpectedEntitySummary.takeError())
724 "entity_summary")
725 .build();
726 }
727
728 if (*ExpectedEntitySummary == nullptr) {
730 std::errc::invalid_argument,
732 .build();
733 }
734
735 auto ActualSN = (*ExpectedEntitySummary)->getSummaryName();
736 if (SN != ActualSN) {
738 std::errc::invalid_argument,
739 ErrorMessages::
740 FailedToDeserializeEntitySummaryMismatchedSummaryName,
741 SN, ActualSN)
742 .build();
743 }
744
745 return std::make_pair(std::move(EI), std::move(*ExpectedEntitySummary));
746}
747
748llvm::Expected<Object> JSONFormat::entityDataMapEntryToJSON(
749 const EntityId EI, const std::unique_ptr<EntitySummary> &EntitySummary,
750 const SummaryName &SN) const {
751 Object Entry;
752
753 Entry["entity_id"] = entityIdToJSON(EI);
754
755 if (!EntitySummary) {
758 }
759
760 const auto ActualSN = EntitySummary->getSummaryName();
761 if (SN != ActualSN) {
764 ActualSN);
765 }
766
767 auto ExpectedEntitySummaryObject = entitySummaryToJSON(SN, *EntitySummary);
768 if (!ExpectedEntitySummaryObject) {
769 return ErrorBuilder::wrap(ExpectedEntitySummaryObject.takeError())
770 .context(ErrorMessages::WritingToField, "EntitySummary",
771 "entity_summary")
772 .build();
773 }
774
775 Entry["entity_summary"] = std::move(*ExpectedEntitySummaryObject);
776
777 return Entry;
778}
779
780//----------------------------------------------------------------------------
781// EntityDataMap
782//----------------------------------------------------------------------------
783
784llvm::Expected<std::map<EntityId, std::unique_ptr<EntitySummary>>>
785JSONFormat::entityDataMapFromJSON(const SummaryName &SN,
786 const Array &EntityDataArray,
787 EntityIdTable &IdTable) const {
788 std::map<EntityId, std::unique_ptr<EntitySummary>> EntityDataMap;
789
790 for (const auto &[Index, EntityDataMapEntryValue] :
791 llvm::enumerate(EntityDataArray)) {
792 const Object *OptEntityDataMapEntryObject =
793 EntityDataMapEntryValue.getAsObject();
794 if (!OptEntityDataMapEntryObject) {
795 return ErrorBuilder::create(std::errc::invalid_argument,
797 "EntitySummary entry", Index, "object")
798 .build();
799 }
800
801 auto ExpectedEntityDataMapEntry =
802 entityDataMapEntryFromJSON(*OptEntityDataMapEntryObject, SN, IdTable);
803 if (!ExpectedEntityDataMapEntry) {
804 return ErrorBuilder::wrap(ExpectedEntityDataMapEntry.takeError())
805 .context(ErrorMessages::ReadingFromIndex, "EntitySummary entry",
806 Index)
807 .build();
808 }
809
810 auto [DataIt, DataInserted] =
811 EntityDataMap.insert(std::move(*ExpectedEntityDataMapEntry));
812 if (!DataInserted) {
813 return ErrorBuilder::create(std::errc::invalid_argument,
815 "EntitySummary entry", Index, DataIt->first)
816 .build();
817 }
818 }
819
820 return std::move(EntityDataMap);
821}
822
823llvm::Expected<Array> JSONFormat::entityDataMapToJSON(
824 const SummaryName &SN,
825 const std::map<EntityId, std::unique_ptr<EntitySummary>> &EntityDataMap)
826 const {
827 Array Result;
828 Result.reserve(EntityDataMap.size());
829
830 for (const auto &[Index, EntityDataMapEntry] :
831 llvm::enumerate(EntityDataMap)) {
832 const auto &[EntityId, EntitySummary] = EntityDataMapEntry;
833
834 auto ExpectedEntityDataMapEntryObject =
835 entityDataMapEntryToJSON(EntityId, EntitySummary, SN);
836
837 if (!ExpectedEntityDataMapEntryObject) {
838 return ErrorBuilder::wrap(ExpectedEntityDataMapEntryObject.takeError())
839 .context(ErrorMessages::WritingToIndex, "EntitySummary entry", Index)
840 .build();
841 }
842
843 Result.push_back(std::move(*ExpectedEntityDataMapEntryObject));
844 }
845
846 return Result;
847}
848
849//----------------------------------------------------------------------------
850// SummaryDataMapEntry
851//----------------------------------------------------------------------------
852
853llvm::Expected<
854 std::pair<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
855JSONFormat::summaryDataMapEntryFromJSON(const Object &SummaryDataMapEntryObject,
856 EntityIdTable &IdTable) const {
857
858 std::optional<llvm::StringRef> OptSummaryNameStr =
859 SummaryDataMapEntryObject.getString("summary_name");
860 if (!OptSummaryNameStr) {
861 return ErrorBuilder::create(std::errc::invalid_argument,
863 "SummaryName", "summary_name", "string")
864 .build();
865 }
866
867 SummaryName SN = summaryNameFromJSON(*OptSummaryNameStr);
868
869 const Array *OptEntityDataArray =
870 SummaryDataMapEntryObject.getArray("summary_data");
871 if (!OptEntityDataArray) {
872 return ErrorBuilder::create(std::errc::invalid_argument,
874 "EntitySummary entries", "summary_data",
875 "array")
876 .build();
877 }
878
879 auto ExpectedEntityDataMap =
880 entityDataMapFromJSON(SN, *OptEntityDataArray, IdTable);
881 if (!ExpectedEntityDataMap) {
882 return ErrorBuilder::wrap(ExpectedEntityDataMap.takeError())
883 .context(ErrorMessages::ReadingFromField, "EntitySummary entries",
884 "summary_data")
885 .build();
886 }
887
888 return std::make_pair(std::move(SN), std::move(*ExpectedEntityDataMap));
889}
890
891llvm::Expected<Object> JSONFormat::summaryDataMapEntryToJSON(
892 const SummaryName &SN,
893 const std::map<EntityId, std::unique_ptr<EntitySummary>> &SD) const {
894 Object Result;
895
896 Result["summary_name"] = summaryNameToJSON(SN);
897
898 auto ExpectedSummaryDataArray = entityDataMapToJSON(SN, SD);
899 if (!ExpectedSummaryDataArray) {
900 return ErrorBuilder::wrap(ExpectedSummaryDataArray.takeError())
901 .context(ErrorMessages::WritingToField, "EntitySummary entries",
902 "summary_data")
903 .build();
904 }
905
906 Result["summary_data"] = std::move(*ExpectedSummaryDataArray);
907
908 return Result;
909}
910
911//----------------------------------------------------------------------------
912// SummaryDataMap
913//----------------------------------------------------------------------------
914
915llvm::Expected<
916 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
917JSONFormat::summaryDataMapFromJSON(const Array &SummaryDataArray,
918 EntityIdTable &IdTable) const {
919 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>
920 SummaryDataMap;
921
922 for (const auto &[Index, SummaryDataMapEntryValue] :
923 llvm::enumerate(SummaryDataArray)) {
924 const Object *OptSummaryDataMapEntryObject =
925 SummaryDataMapEntryValue.getAsObject();
926 if (!OptSummaryDataMapEntryObject) {
927 return ErrorBuilder::create(std::errc::invalid_argument,
929 "SummaryData entry", Index, "object")
930 .build();
931 }
932
933 auto ExpectedSummaryDataMapEntry =
934 summaryDataMapEntryFromJSON(*OptSummaryDataMapEntryObject, IdTable);
935 if (!ExpectedSummaryDataMapEntry) {
936 return ErrorBuilder::wrap(ExpectedSummaryDataMapEntry.takeError())
937 .context(ErrorMessages::ReadingFromIndex, "SummaryData entry", Index)
938 .build();
939 }
940
941 auto [SummaryIt, SummaryInserted] =
942 SummaryDataMap.emplace(std::move(*ExpectedSummaryDataMapEntry));
943 if (!SummaryInserted) {
944 return ErrorBuilder::create(std::errc::invalid_argument,
946 "SummaryData entry", Index, SummaryIt->first)
947 .build();
948 }
949 }
950
951 return std::move(SummaryDataMap);
952}
953
954llvm::Expected<Array> JSONFormat::summaryDataMapToJSON(
955 const std::map<SummaryName,
956 std::map<EntityId, std::unique_ptr<EntitySummary>>>
957 &SummaryDataMap) const {
958 Array Result;
959 Result.reserve(SummaryDataMap.size());
960
961 for (const auto &[Index, SummaryDataMapEntry] :
962 llvm::enumerate(SummaryDataMap)) {
963 const auto &[SummaryName, DataMap] = SummaryDataMapEntry;
964
965 auto ExpectedSummaryDataMapObject =
966 summaryDataMapEntryToJSON(SummaryName, DataMap);
967 if (!ExpectedSummaryDataMapObject) {
968 return ErrorBuilder::wrap(ExpectedSummaryDataMapObject.takeError())
969 .context(ErrorMessages::WritingToIndex, "SummaryData entry", Index)
970 .build();
971 }
972
973 Result.push_back(std::move(*ExpectedSummaryDataMapObject));
974 }
975
976 return std::move(Result);
977}
978
979//----------------------------------------------------------------------------
980// EncodingDataMapEntry
981//----------------------------------------------------------------------------
982
983llvm::Expected<std::pair<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
984JSONFormat::encodingDataMapEntryFromJSON(
985 const Object &EntityDataMapEntryObject) const {
986 const Value *EntityIdIntValue = EntityDataMapEntryObject.get("entity_id");
987 if (!EntityIdIntValue) {
988 return ErrorBuilder::create(std::errc::invalid_argument,
990 "EntityId", "entity_id",
991 "number (unsigned 64-bit integer)")
992 .build();
993 }
994
995 const std::optional<uint64_t> OptEntityIdInt =
996 EntityIdIntValue->getAsUINT64();
997 if (!OptEntityIdInt) {
998 return ErrorBuilder::create(std::errc::invalid_argument,
1000 "EntityId", "entity_id",
1001 "number (unsigned 64-bit integer)")
1002 .build();
1003 }
1004
1005 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
1006
1007 const Object *OptEntitySummaryObject =
1008 EntityDataMapEntryObject.getObject("entity_summary");
1009 if (!OptEntitySummaryObject) {
1010 return ErrorBuilder::create(std::errc::invalid_argument,
1012 "EntitySummary", "entity_summary", "object")
1013 .build();
1014 }
1015
1016 std::unique_ptr<EntitySummaryEncoding> Encoding(
1017 new JSONEntitySummaryEncoding(Value(Object(*OptEntitySummaryObject))));
1018
1019 return std::make_pair(std::move(EI), std::move(Encoding));
1020}
1021
1022Object JSONFormat::encodingDataMapEntryToJSON(
1023 EntityId EI, const std::unique_ptr<EntitySummaryEncoding> &Encoding) const {
1024 Object Entry;
1025 Entry["entity_id"] = entityIdToJSON(EI);
1026
1027 // All EntitySummaryEncoding objects stored in a TUSummaryEncoding or
1028 // LUSummaryEncoding read by JSONFormat are JSONEntitySummaryEncoding
1029 // instances, since encodingDataMapEntryFromJSON is the only place that
1030 // creates them.
1031 auto *JSONEncoding = static_cast<JSONEntitySummaryEncoding *>(Encoding.get());
1032 Entry["entity_summary"] = JSONEncoding->Data;
1033
1034 return Entry;
1035}
1036
1037//----------------------------------------------------------------------------
1038// EncodingDataMap
1039//----------------------------------------------------------------------------
1040
1041llvm::Expected<std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
1042JSONFormat::encodingDataMapFromJSON(const Array &EntityDataArray) const {
1043 std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>> EncodingDataMap;
1044
1045 for (const auto &[Index, EntityDataMapEntryValue] :
1046 llvm::enumerate(EntityDataArray)) {
1047 const Object *OptEntityDataMapEntryObject =
1048 EntityDataMapEntryValue.getAsObject();
1049 if (!OptEntityDataMapEntryObject) {
1050 return ErrorBuilder::create(std::errc::invalid_argument,
1052 "EntitySummary entry", Index, "object")
1053 .build();
1054 }
1055
1056 auto ExpectedEntry =
1057 encodingDataMapEntryFromJSON(*OptEntityDataMapEntryObject);
1058 if (!ExpectedEntry) {
1059 return ErrorBuilder::wrap(ExpectedEntry.takeError())
1060 .context(ErrorMessages::ReadingFromIndex, "EntitySummary entry",
1061 Index)
1062 .build();
1063 }
1064
1065 auto [DataIt, DataInserted] =
1066 EncodingDataMap.insert(std::move(*ExpectedEntry));
1067 if (!DataInserted) {
1068 return ErrorBuilder::create(std::errc::invalid_argument,
1070 "EntitySummary entry", Index, DataIt->first)
1071 .build();
1072 }
1073 }
1074
1075 return std::move(EncodingDataMap);
1076}
1077
1078Array JSONFormat::encodingDataMapToJSON(
1079 const std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>
1080 &EncodingDataMap) const {
1081 Array Result;
1082 Result.reserve(EncodingDataMap.size());
1083
1084 for (const auto &[EI, Encoding] : EncodingDataMap) {
1085 Result.push_back(encodingDataMapEntryToJSON(EI, Encoding));
1086 }
1087
1088 return Result;
1089}
1090
1091//----------------------------------------------------------------------------
1092// EncodingSummaryDataMapEntry
1093//----------------------------------------------------------------------------
1094
1095llvm::Expected<std::pair<
1096 SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>>
1097JSONFormat::encodingSummaryDataMapEntryFromJSON(
1098 const Object &SummaryDataMapEntryObject) const {
1099 std::optional<llvm::StringRef> OptSummaryNameStr =
1100 SummaryDataMapEntryObject.getString("summary_name");
1101 if (!OptSummaryNameStr) {
1102 return ErrorBuilder::create(std::errc::invalid_argument,
1104 "SummaryName", "summary_name", "string")
1105 .build();
1106 }
1107
1108 SummaryName SN = summaryNameFromJSON(*OptSummaryNameStr);
1109
1110 const Array *OptEntityDataArray =
1111 SummaryDataMapEntryObject.getArray("summary_data");
1112 if (!OptEntityDataArray) {
1113 return ErrorBuilder::create(std::errc::invalid_argument,
1115 "EntitySummary entries", "summary_data",
1116 "array")
1117 .build();
1118 }
1119
1120 auto ExpectedEncodingDataMap = encodingDataMapFromJSON(*OptEntityDataArray);
1121 if (!ExpectedEncodingDataMap) {
1122 return ErrorBuilder::wrap(ExpectedEncodingDataMap.takeError())
1123 .context(ErrorMessages::ReadingFromField, "EntitySummary entries",
1124 "summary_data")
1125 .build();
1126 }
1127
1128 return std::make_pair(std::move(SN), std::move(*ExpectedEncodingDataMap));
1129}
1130
1131Object JSONFormat::encodingSummaryDataMapEntryToJSON(
1132 const SummaryName &SN,
1133 const std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>
1134 &EncodingMap) const {
1135 Object Result;
1136
1137 Result["summary_name"] = summaryNameToJSON(SN);
1138 Result["summary_data"] = encodingDataMapToJSON(EncodingMap);
1139
1140 return Result;
1141}
1142
1143//----------------------------------------------------------------------------
1144// EncodingSummaryDataMap
1145//----------------------------------------------------------------------------
1146
1147llvm::Expected<std::map<
1148 SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>>
1149JSONFormat::encodingSummaryDataMapFromJSON(
1150 const Array &SummaryDataArray) const {
1151 std::map<SummaryName,
1152 std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
1153 EncodingSummaryDataMap;
1154
1155 for (const auto &[Index, SummaryDataMapEntryValue] :
1156 llvm::enumerate(SummaryDataArray)) {
1157 const Object *OptSummaryDataMapEntryObject =
1158 SummaryDataMapEntryValue.getAsObject();
1159 if (!OptSummaryDataMapEntryObject) {
1160 return ErrorBuilder::create(std::errc::invalid_argument,
1162 "SummaryData entry", Index, "object")
1163 .build();
1164 }
1165
1166 auto ExpectedEntry =
1167 encodingSummaryDataMapEntryFromJSON(*OptSummaryDataMapEntryObject);
1168 if (!ExpectedEntry) {
1169 return ErrorBuilder::wrap(ExpectedEntry.takeError())
1170 .context(ErrorMessages::ReadingFromIndex, "SummaryData entry", Index)
1171 .build();
1172 }
1173
1174 auto [SummaryIt, SummaryInserted] =
1175 EncodingSummaryDataMap.emplace(std::move(*ExpectedEntry));
1176 if (!SummaryInserted) {
1177 return ErrorBuilder::create(std::errc::invalid_argument,
1179 "SummaryData entry", Index, SummaryIt->first)
1180 .build();
1181 }
1182 }
1183
1184 return std::move(EncodingSummaryDataMap);
1185}
1186
1187Array JSONFormat::encodingSummaryDataMapToJSON(
1188 const std::map<SummaryName,
1189 std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>>
1190 &EncodingSummaryDataMap) const {
1191 Array Result;
1192 Result.reserve(EncodingSummaryDataMap.size());
1193
1194 for (const auto &[SN, EncodingMap] : EncodingSummaryDataMap) {
1195 Result.push_back(encodingSummaryDataMapEntryToJSON(SN, EncodingMap));
1196 }
1197
1198 return Result;
1199}
1200
1201} // namespace clang::ssaf
#define V(N, I)
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)
static clang::ssaf::SerializationFormatRegistry::Add< clang::ssaf::JSONFormat > RegisterJSONFormat("json", "JSON serialization format")
volatile int SSAFJSONFormatAnchorSource
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
Represents the linkage properties of an entity in the program model.
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.
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.
friend class JSONEntitySummaryEncoding
Definition JSONFormat.h:36
void forEachRegisteredAnalysis(llvm::function_ref< void(llvm::StringRef Name, llvm::StringRef Desc)> Callback) const override
Invokes Callback once for each analysis that has registered serialization support for this format.
Represents a hierarchical sequence of build namespaces.
static EntityId makeEntityId(const size_t Index)
Uniquely identifies an analysis summary.
Definition SummaryName.h:22
llvm::StringRef str() const
Explicit conversion to the underlying string representation.
Definition SummaryName.h:31
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
constexpr const char * FailedToSerializeEntitySummaryMismatchedSummaryName
constexpr const char * InvalidBuildNamespaceKind
constexpr const char * ReadingFromField
constexpr const char * FailedToReadObjectAtIndex
constexpr const char * FailedToDeserializeEntitySummaryNoFormatInfo
constexpr const char * InvalidEntityLinkageType
constexpr const char * FileIsDirectory
constexpr const char * FileNotFound
constexpr const char * FailedToReadObjectAtField
constexpr const char * FileExists
constexpr const char * FailedToReadEntityIdObject
constexpr const char * ReadingFromIndex
constexpr const char * WritingToField
constexpr const char * FailedInsertionOnDuplication
constexpr const char * FailedToDeserializeLinkageTableExtraId
constexpr const char * FailedToSerializeEntitySummaryMissingData
constexpr const char * FailedToDeserializeEntitySummaryMissingData
constexpr const char * FailedToWriteFile
constexpr const char * FailedToDeserializeLinkageTableMissingId
constexpr const char * FileIsNotJSON
constexpr const char * FailedToReadFile
constexpr const char * ParentDirectoryNotFound
constexpr const char * FailedToSerializeEntitySummaryNoFormatInfo
constexpr const char * WritingToIndex
SummaryName summaryNameFromJSON(llvm::StringRef SummaryNameStr)
llvm::StringRef summaryNameToJSON(const SummaryName &SN)
std::optional< EntityLinkageType > entityLinkageTypeFromString(llvm::StringRef Str)
Parses a string produced by entityLinkageTypeToString().
llvm::json::Array Array
std::optional< BuildNamespaceKind > buildNamespaceKindFromString(llvm::StringRef Str)
Parses a string produced by buildNamespaceKindToString().
llvm::Expected< EntityLinkageType > entityLinkageTypeFromJSON(llvm::StringRef EntityLinkageTypeStr)
constexpr const char * JSONEntityIdKey
An entity ID is encoded as the single-key object {"@": <index>}.
llvm::json::Value Value
llvm::Expected< BuildNamespaceKind > buildNamespaceKindFromJSON(llvm::StringRef BuildNamespaceKindStr)
llvm::json::Object Object
llvm::Expected< Value > readJSON(llvm::StringRef Path)
constexpr const char * JSONFormatFileExtension
llvm::StringRef buildNamespaceKindToJSON(BuildNamespaceKind BNK)
llvm::StringRef entityLinkageTypeToJSON(EntityLinkageType LT)
llvm::Error writeJSON(Value &&V, llvm::StringRef Path)
llvm::StringRef buildNamespaceKindToString(BuildNamespaceKind BNK)
Returns the canonical string representation of BNK used for serialization and display (e....
llvm::StringRef entityLinkageTypeToString(EntityLinkageType LT)
Returns the canonical string representation of LT used for serialization and display (e....
@ Result
The result type of a method or function.
Definition TypeBase.h:905
unsigned long uint64_t
template class CLANG_TEMPLATE_ABI Registry< clang::ssaf::JSONFormat::FormatInfo >