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