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"
19LLVM_INSTANTIATE_REGISTRY(llvm::Registry<JSONFormat::FormatInfo>)
27constexpr const char *JSONFormatFileExtension =
".json";
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";
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}'";
55constexpr const char *FailedInsertionOnDuplication =
56 "failed to insert {0} at index '{1}': encountered duplicate {2} '{3}'";
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}";
65constexpr const char *FailedToDeserializeEntitySummary =
66 "failed to deserialize EntitySummary: no FormatInfo registered for summary "
68constexpr const char *FailedToSerializeEntitySummary =
69 "failed to serialize EntitySummary: no FormatInfo registered for summary "
72constexpr const char *InvalidBuildNamespaceKind =
73 "invalid 'kind' BuildNamespaceKind value '{0}'";
86 if (!llvm::sys::fs::exists(Path)) {
88 ErrorMessages::FailedToReadFile, Path,
89 ErrorMessages::FileNotFound)
93 if (llvm::sys::fs::is_directory(Path)) {
95 ErrorMessages::FailedToReadFile, Path,
96 ErrorMessages::FileIsDirectory)
100 if (!Path.ends_with_insensitive(JSONFormatFileExtension)) {
102 ErrorMessages::FailedToReadFile, Path,
103 llvm::formatv(ErrorMessages::FileIsNotJSON,
104 JSONFormatFileExtension))
108 auto BufferOrError = llvm::MemoryBuffer::getFile(Path);
109 if (!BufferOrError) {
110 const std::error_code EC = BufferOrError.getError();
116 return llvm::json::parse(BufferOrError.get()->getBuffer());
119llvm::Error writeJSON(
Value &&
Value, llvm::StringRef Path) {
120 if (llvm::sys::fs::exists(Path)) {
122 ErrorMessages::FailedToWriteFile, Path,
123 ErrorMessages::FileExists)
127 llvm::StringRef Dir = llvm::sys::path::parent_path(Path);
128 if (!Dir.empty() && !llvm::sys::fs::is_directory(Dir)) {
130 ErrorMessages::FailedToWriteFile, Path,
131 ErrorMessages::ParentDirectoryNotFound)
135 if (!Path.ends_with_insensitive(JSONFormatFileExtension)) {
137 ErrorMessages::FailedToWriteFile, Path,
138 llvm::formatv(ErrorMessages::FileIsNotJSON,
139 JSONFormatFileExtension))
144 llvm::raw_fd_ostream OutStream(Path, EC, llvm::sys::fs::OF_Text);
152 OutStream << llvm::formatv(
"{0:2}\n",
Value);
155 if (OutStream.has_error()) {
157 ErrorMessages::FailedToWriteFile, Path,
158 OutStream.error().message())
162 return llvm::Error::success();
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;
177 llvm::report_fatal_error(
178 "FormatInfo is already registered for summary: " +
179 Info->ForSummary.str());
191SummaryName summaryNameFromJSON(llvm::StringRef SummaryNameStr) {
195llvm::StringRef summaryNameToJSON(
const SummaryName &SN) {
return SN.
str(); }
203EntityId JSONFormat::entityIdFromJSON(
const uint64_t EntityIdIndex)
const {
204 return makeEntityId(
static_cast<size_t>(EntityIdIndex));
215llvm::Expected<BuildNamespaceKind> JSONFormat::buildNamespaceKindFromJSON(
216 llvm::StringRef BuildNamespaceKindStr)
const {
218 if (!OptBuildNamespaceKind) {
220 ErrorMessages::InvalidBuildNamespaceKind,
221 BuildNamespaceKindStr)
225 return *OptBuildNamespaceKind;
240llvm::Expected<BuildNamespace>
241JSONFormat::buildNamespaceFromJSON(
const Object &BuildNamespaceObject)
const {
242 auto OptBuildNamespaceKindStr = BuildNamespaceObject.getString(
"kind");
243 if (!OptBuildNamespaceKindStr) {
245 ErrorMessages::FailedToReadObjectAtField,
246 "BuildNamespaceKind",
"kind",
"string")
250 auto ExpectedKind = buildNamespaceKindFromJSON(*OptBuildNamespaceKindStr);
253 .
context(ErrorMessages::ReadingFromField,
"BuildNamespaceKind",
"kind")
256 auto OptNameStr = BuildNamespaceObject.getString(
"name");
259 ErrorMessages::FailedToReadObjectAtField,
260 "BuildNamespaceName",
"name",
"string")
264 return {BuildNamespace(*ExpectedKind, *OptNameStr)};
278llvm::Expected<NestedBuildNamespace> JSONFormat::nestedBuildNamespaceFromJSON(
279 const Array &NestedBuildNamespaceArray)
const {
280 std::vector<BuildNamespace> Namespaces;
282 size_t NamespaceCount = NestedBuildNamespaceArray.size();
283 Namespaces.reserve(NamespaceCount);
285 for (
const auto &[Index, BuildNamespaceValue] :
286 llvm::enumerate(NestedBuildNamespaceArray)) {
288 const Object *BuildNamespaceObject = BuildNamespaceValue.getAsObject();
289 if (!BuildNamespaceObject) {
291 ErrorMessages::FailedToReadObjectAtIndex,
292 "BuildNamespace", Index,
"object")
296 auto ExpectedBuildNamespace = buildNamespaceFromJSON(*BuildNamespaceObject);
297 if (!ExpectedBuildNamespace) {
299 .
context(ErrorMessages::ReadingFromIndex,
"BuildNamespace", Index)
303 Namespaces.push_back(std::move(*ExpectedBuildNamespace));
306 return NestedBuildNamespace(std::move(Namespaces));
309Array JSONFormat::nestedBuildNamespaceToJSON(
312 const auto &Namespaces = getNamespaces(NBN);
313 Result.reserve(Namespaces.size());
315 for (
const auto &BN : Namespaces) {
316 Result.push_back(buildNamespaceToJSON(BN));
326llvm::Expected<EntityName>
327JSONFormat::entityNameFromJSON(
const Object &EntityNameObject)
const {
328 const auto OptUSR = EntityNameObject.getString(
"usr");
331 ErrorMessages::FailedToReadObjectAtField,
"USR",
336 const auto OptSuffix = EntityNameObject.getString(
"suffix");
339 ErrorMessages::FailedToReadObjectAtField,
340 "Suffix",
"suffix",
"string")
344 const Array *OptNamespaceArray = EntityNameObject.getArray(
"namespace");
345 if (!OptNamespaceArray) {
347 ErrorMessages::FailedToReadObjectAtField,
348 "NestedBuildNamespace",
"namespace",
"array")
352 auto ExpectedNamespace = nestedBuildNamespaceFromJSON(*OptNamespaceArray);
353 if (!ExpectedNamespace) {
355 .
context(ErrorMessages::ReadingFromField,
"NestedBuildNamespace",
360 return EntityName{*OptUSR, *OptSuffix, std::move(*ExpectedNamespace)};
366 Result[
"suffix"] = getSuffix(EN);
367 Result[
"namespace"] = nestedBuildNamespaceToJSON(getNamespace(EN));
375llvm::Expected<std::pair<EntityName, EntityId>>
376JSONFormat::entityIdTableEntryFromJSON(
377 const Object &EntityIdTableEntryObject)
const {
379 const Object *OptEntityNameObject =
380 EntityIdTableEntryObject.getObject(
"name");
381 if (!OptEntityNameObject) {
383 ErrorMessages::FailedToReadObjectAtField,
384 "EntityName",
"name",
"object")
388 auto ExpectedEntityName = entityNameFromJSON(*OptEntityNameObject);
389 if (!ExpectedEntityName) {
391 .
context(ErrorMessages::ReadingFromField,
"EntityName",
"name")
395 const Value *EntityIdIntValue = EntityIdTableEntryObject.get(
"id");
396 if (!EntityIdIntValue) {
398 ErrorMessages::FailedToReadObjectAtField,
400 "number (unsigned 64-bit integer)")
404 const std::optional<uint64_t> OptEntityIdInt =
405 EntityIdIntValue->getAsUINT64();
406 if (!OptEntityIdInt) {
408 ErrorMessages::FailedToReadObjectAtField,
410 "number (unsigned 64-bit integer)")
414 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
416 return std::make_pair(std::move(*ExpectedEntityName), std::move(EI));
422 Entry[
"id"] = entityIdToJSON(EI);
423 Entry[
"name"] = entityNameToJSON(EN);
431llvm::Expected<EntityIdTable>
432JSONFormat::entityIdTableFromJSON(
const Array &EntityIdTableArray)
const {
433 EntityIdTable IdTable;
434 std::map<EntityName, EntityId> &Entities = getEntities(IdTable);
436 for (
const auto &[Index, EntityIdTableEntryValue] :
437 llvm::enumerate(EntityIdTableArray)) {
439 const Object *OptEntityIdTableEntryObject =
440 EntityIdTableEntryValue.getAsObject();
441 if (!OptEntityIdTableEntryObject) {
443 ErrorMessages::FailedToReadObjectAtIndex,
444 "EntityIdTable entry", Index,
"object")
448 auto ExpectedEntityIdTableEntry =
449 entityIdTableEntryFromJSON(*OptEntityIdTableEntryObject);
450 if (!ExpectedEntityIdTableEntry)
452 .
context(ErrorMessages::ReadingFromIndex,
"EntityIdTable entry",
456 auto [EntityIt, EntityInserted] =
457 Entities.emplace(std::move(*ExpectedEntityIdTableEntry));
458 if (!EntityInserted) {
460 ErrorMessages::FailedInsertionOnDuplication,
461 "EntityIdTable entry", Index,
"EntityId",
471 Array EntityIdTableArray;
472 const auto &Entities = getEntities(IdTable);
473 EntityIdTableArray.reserve(Entities.size());
475 for (
const auto &[EntityName, EntityId] : Entities) {
476 EntityIdTableArray.push_back(
477 entityIdTableEntryToJSON(EntityName, EntityId));
480 return EntityIdTableArray;
487llvm::Expected<std::unique_ptr<EntitySummary>>
488JSONFormat::entitySummaryFromJSON(
const SummaryName &SN,
489 const Object &EntitySummaryObject,
491 auto InfoIt = FormatInfos.find(SN);
492 if (InfoIt == FormatInfos.end()) {
494 ErrorMessages::FailedToDeserializeEntitySummary,
499 const auto &InfoEntry = InfoIt->second;
500 assert(InfoEntry.ForSummary == SN);
503 return InfoEntry.Deserialize(EntitySummaryObject, IdTable, Converter);
506llvm::Expected<Object>
507JSONFormat::entitySummaryToJSON(
const SummaryName &SN,
509 auto InfoIt = FormatInfos.find(SN);
510 if (InfoIt == FormatInfos.end()) {
512 ErrorMessages::FailedToSerializeEntitySummary,
517 const auto &InfoEntry = InfoIt->second;
518 assert(InfoEntry.ForSummary == SN);
521 return InfoEntry.Serialize(ES, Converter);
528llvm::Expected<std::pair<EntityId, std::unique_ptr<EntitySummary>>>
529JSONFormat::entityDataMapEntryFromJSON(
const Object &EntityDataMapEntryObject,
533 const Value *EntityIdIntValue = EntityDataMapEntryObject.get(
"entity_id");
534 if (!EntityIdIntValue) {
536 ErrorMessages::FailedToReadObjectAtField,
537 "EntityId",
"entity_id",
538 "number (unsigned 64-bit integer)")
542 const std::optional<uint64_t> OptEntityIdInt =
543 EntityIdIntValue->getAsUINT64();
544 if (!OptEntityIdInt) {
546 ErrorMessages::FailedToReadObjectAtField,
547 "EntityId",
"entity_id",
"integer")
551 EntityId EI = entityIdFromJSON(*OptEntityIdInt);
553 const Object *OptEntitySummaryObject =
554 EntityDataMapEntryObject.getObject(
"entity_summary");
555 if (!OptEntitySummaryObject) {
557 ErrorMessages::FailedToReadObjectAtField,
558 "EntitySummary",
"entity_summary",
"object")
562 auto ExpectedEntitySummary =
563 entitySummaryFromJSON(SN, *OptEntitySummaryObject, IdTable);
564 if (!ExpectedEntitySummary) {
566 .
context(ErrorMessages::ReadingFromField,
"EntitySummary",
571 return std::make_pair(std::move(EI), std::move(*ExpectedEntitySummary));
578llvm::Expected<std::map<EntityId, std::unique_ptr<EntitySummary>>>
579JSONFormat::entityDataMapFromJSON(
const SummaryName &SN,
580 const Array &EntityDataArray,
582 std::map<EntityId, std::unique_ptr<EntitySummary>> EntityDataMap;
584 for (
const auto &[Index, EntityDataMapEntryValue] :
585 llvm::enumerate(EntityDataArray)) {
587 const Object *OptEntityDataMapEntryObject =
588 EntityDataMapEntryValue.getAsObject();
589 if (!OptEntityDataMapEntryObject) {
591 ErrorMessages::FailedToReadObjectAtIndex,
592 "EntitySummary entry", Index,
"object")
596 auto ExpectedEntityDataMapEntry =
597 entityDataMapEntryFromJSON(*OptEntityDataMapEntryObject, SN, IdTable);
598 if (!ExpectedEntityDataMapEntry)
600 .
context(ErrorMessages::ReadingFromIndex,
"EntitySummary entry",
604 auto [DataIt, DataInserted] =
605 EntityDataMap.insert(std::move(*ExpectedEntityDataMapEntry));
608 ErrorMessages::FailedInsertionOnDuplication,
609 "EntitySummary entry", Index,
"EntityId",
615 return std::move(EntityDataMap);
618llvm::Expected<Array> JSONFormat::entityDataMapToJSON(
620 const std::map<
EntityId, std::unique_ptr<EntitySummary>> &EntityDataMap)
623 Result.reserve(EntityDataMap.size());
625 for (
const auto &[Index, EntityDataMapEntry] :
626 llvm::enumerate(EntityDataMap)) {
627 const auto &[EntityId, EntitySummary] = EntityDataMapEntry;
631 Entry[
"entity_id"] = entityIdToJSON(EntityId);
633 auto ExpectedEntitySummaryObject = entitySummaryToJSON(SN, *EntitySummary);
634 if (!ExpectedEntitySummaryObject) {
636 .
context(ErrorMessages::WritingToIndex,
"EntitySummary entry", Index)
640 Entry[
"entity_summary"] = std::move(*ExpectedEntitySummaryObject);
642 Result.push_back(std::move(Entry));
653 std::pair<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
654JSONFormat::summaryDataMapEntryFromJSON(
const Object &SummaryDataMapEntryObject,
657 std::optional<llvm::StringRef> OptSummaryNameStr =
658 SummaryDataMapEntryObject.getString(
"summary_name");
659 if (!OptSummaryNameStr) {
661 ErrorMessages::FailedToReadObjectAtField,
662 "SummaryName",
"summary_name",
"string")
666 SummaryName SN = summaryNameFromJSON(*OptSummaryNameStr);
668 const Array *OptEntityDataArray =
669 SummaryDataMapEntryObject.getArray(
"summary_data");
670 if (!OptEntityDataArray) {
672 ErrorMessages::FailedToReadObjectAtField,
673 "EntitySummary entries",
"summary_data",
678 auto ExpectedEntityDataMap =
679 entityDataMapFromJSON(SN, *OptEntityDataArray, IdTable);
680 if (!ExpectedEntityDataMap)
682 .
context(ErrorMessages::ReadingFromField,
"EntitySummary entries",
686 return std::make_pair(std::move(SN), std::move(*ExpectedEntityDataMap));
689llvm::Expected<Object> JSONFormat::summaryDataMapEntryToJSON(
691 const std::map<
EntityId, std::unique_ptr<EntitySummary>> &SD)
const {
694 Result[
"summary_name"] = summaryNameToJSON(SN);
696 auto ExpectedSummaryDataArray = entityDataMapToJSON(SN, SD);
697 if (!ExpectedSummaryDataArray) {
699 .
context(ErrorMessages::WritingToField,
"EntitySummary entries",
704 Result[
"summary_data"] = std::move(*ExpectedSummaryDataArray);
714 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>>
715JSONFormat::summaryDataMapFromJSON(
const Array &SummaryDataArray,
717 std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>>
720 for (
const auto &[Index, SummaryDataMapEntryValue] :
721 llvm::enumerate(SummaryDataArray)) {
723 const Object *OptSummaryDataMapEntryObject =
724 SummaryDataMapEntryValue.getAsObject();
725 if (!OptSummaryDataMapEntryObject) {
727 ErrorMessages::FailedToReadObjectAtIndex,
728 "SummaryData entry", Index,
"object")
732 auto ExpectedSummaryDataMapEntry =
733 summaryDataMapEntryFromJSON(*OptSummaryDataMapEntryObject, IdTable);
734 if (!ExpectedSummaryDataMapEntry) {
736 .
context(ErrorMessages::ReadingFromIndex,
"SummaryData entry", Index)
740 auto [SummaryIt, SummaryInserted] =
741 SummaryDataMap.emplace(std::move(*ExpectedSummaryDataMapEntry));
742 if (!SummaryInserted) {
744 ErrorMessages::FailedInsertionOnDuplication,
745 "SummaryData entry", Index,
"SummaryName",
746 SummaryIt->first.str())
751 return std::move(SummaryDataMap);
754llvm::Expected<Array> JSONFormat::summaryDataMapToJSON(
756 std::map<
EntityId, std::unique_ptr<EntitySummary>>>
757 &SummaryDataMap)
const {
759 Result.reserve(SummaryDataMap.size());
761 for (
const auto &[Index, SummaryDataMapEntry] :
762 llvm::enumerate(SummaryDataMap)) {
763 const auto &[SummaryName, DataMap] = SummaryDataMapEntry;
765 auto ExpectedSummaryDataMapObject =
766 summaryDataMapEntryToJSON(SummaryName, DataMap);
767 if (!ExpectedSummaryDataMapObject) {
769 .
context(ErrorMessages::WritingToIndex,
"SummaryData entry", Index)
773 Result.push_back(std::move(*ExpectedSummaryDataMapObject));
784 auto ExpectedJSON = readJSON(Path);
787 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
791 Object *RootObjectPtr = ExpectedJSON->getAsObject();
792 if (!RootObjectPtr) {
794 ErrorMessages::FailedToReadObject,
"TUSummary",
796 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
800 const Object &RootObject = *RootObjectPtr;
802 const Object *TUNamespaceObject = RootObject.getObject(
"tu_namespace");
803 if (!TUNamespaceObject) {
805 ErrorMessages::FailedToReadObjectAtField,
806 "BuildNamespace",
"tu_namespace",
"object")
807 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
811 auto ExpectedTUNamespace = buildNamespaceFromJSON(*TUNamespaceObject);
812 if (!ExpectedTUNamespace) {
814 .
context(ErrorMessages::ReadingFromField,
"BuildNamespace",
816 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
820 TUSummary Summary(std::move(*ExpectedTUNamespace));
823 const Array *IdTableArray = RootObject.getArray(
"id_table");
826 ErrorMessages::FailedToReadObjectAtField,
827 "IdTable",
"id_table",
"array")
828 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
832 auto ExpectedIdTable = entityIdTableFromJSON(*IdTableArray);
833 if (!ExpectedIdTable) {
835 .
context(ErrorMessages::ReadingFromField,
"IdTable",
"id_table")
836 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
840 getIdTable(Summary) = std::move(*ExpectedIdTable);
844 const Array *SummaryDataArray = RootObject.getArray(
"data");
845 if (!SummaryDataArray) {
847 ErrorMessages::FailedToReadObjectAtField,
848 "SummaryData entries",
"data",
"array")
849 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
853 auto ExpectedSummaryDataMap =
854 summaryDataMapFromJSON(*SummaryDataArray, getIdTable(Summary));
855 if (!ExpectedSummaryDataMap) {
857 .
context(ErrorMessages::ReadingFromField,
"SummaryData entries",
859 .
context(ErrorMessages::ReadingFromFile,
"TUSummary", Path)
863 getData(Summary) = std::move(*ExpectedSummaryDataMap);
866 return std::move(Summary);
870 llvm::StringRef Path) {
873 RootObject[
"tu_namespace"] = buildNamespaceToJSON(getTUNamespace(S));
875 RootObject[
"id_table"] = entityIdTableToJSON(getIdTable(S));
877 auto ExpectedDataObject = summaryDataMapToJSON(getData(S));
878 if (!ExpectedDataObject) {
880 .
context(ErrorMessages::WritingToFile,
"TUSummary", Path)
884 RootObject[
"data"] = std::move(*ExpectedDataObject);
886 if (
auto Error = writeJSON(std::move(RootObject), Path)) {
888 .
context(ErrorMessages::WritingToFile,
"TUSummary", Path)
892 return llvm::Error::success();
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)
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.
Uniquely identifies an entity in a program.
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.
Represents a hierarchical sequence of build namespaces.
Uniquely identifies an analysis summary.
llvm::StringRef str() const
Explicit conversion to the underlying string representation.
Data extracted for a given translation unit and for a given set of analyses.
StringRef getName(const HeaderType T)
std::optional< BuildNamespaceKind > parseBuildNamespaceKind(llvm::StringRef Str)
llvm::StringRef toString(BuildNamespaceKind BNK)
@ Result
The result type of a method or function.