1//===- LUSummaryEncoding.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
11#include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummaryEncoding.h"
12
13#include <set>
14
15namespace clang::ssaf {
16
17//----------------------------------------------------------------------------
18// LUSummaryEncoding
19//----------------------------------------------------------------------------
20
21llvm::Expected<LUSummaryEncoding>
22JSONFormat::readLUSummaryEncoding(llvm::StringRef Path) {
23 auto ExpectedJSON = readJSON(Path);
24 if (!ExpectedJSON) {
25 return ErrorBuilder::wrap(E: ExpectedJSON.takeError())
26 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
27 .build();
28 }
29
30 Object *RootObjectPtr = ExpectedJSON->getAsObject();
31 if (!RootObjectPtr) {
32 return ErrorBuilder::create(EC: std::errc::invalid_argument,
33 Fmt: ErrorMessages::FailedToReadObject, ArgVals: "LUSummary",
34 ArgVals: "object")
35 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
36 .build();
37 }
38
39 const Object &RootObject = *RootObjectPtr;
40
41 const Array *LUNamespaceArray = RootObject.getArray(K: "lu_namespace");
42 if (!LUNamespaceArray) {
43 return ErrorBuilder::create(EC: std::errc::invalid_argument,
44 Fmt: ErrorMessages::FailedToReadObjectAtField,
45 ArgVals: "NestedBuildNamespace", ArgVals: "lu_namespace", ArgVals: "array")
46 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
47 .build();
48 }
49
50 auto ExpectedLUNamespace = nestedBuildNamespaceFromJSON(NestedBuildNamespaceArray: *LUNamespaceArray);
51 if (!ExpectedLUNamespace) {
52 return ErrorBuilder::wrap(E: ExpectedLUNamespace.takeError())
53 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "NestedBuildNamespace",
54 ArgVals: "lu_namespace")
55 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
56 .build();
57 }
58
59 LUSummaryEncoding Encoding(std::move(*ExpectedLUNamespace));
60
61 {
62 const Array *IdTableArray = RootObject.getArray(K: "id_table");
63 if (!IdTableArray) {
64 return ErrorBuilder::create(EC: std::errc::invalid_argument,
65 Fmt: ErrorMessages::FailedToReadObjectAtField,
66 ArgVals: "IdTable", ArgVals: "id_table", ArgVals: "array")
67 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
68 .build();
69 }
70
71 auto ExpectedIdTable = entityIdTableFromJSON(EntityIdTableArray: *IdTableArray);
72 if (!ExpectedIdTable) {
73 return ErrorBuilder::wrap(E: ExpectedIdTable.takeError())
74 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "IdTable", ArgVals: "id_table")
75 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
76 .build();
77 }
78
79 getIdTable(X&: Encoding) = std::move(*ExpectedIdTable);
80 }
81
82 {
83 const Array *LinkageTableArray = RootObject.getArray(K: "linkage_table");
84 if (!LinkageTableArray) {
85 return ErrorBuilder::create(EC: std::errc::invalid_argument,
86 Fmt: ErrorMessages::FailedToReadObjectAtField,
87 ArgVals: "LinkageTable", ArgVals: "linkage_table", ArgVals: "array")
88 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
89 .build();
90 }
91
92 auto ExpectedIdRange =
93 llvm::make_second_range(c&: getEntities(X&: getIdTable(X&: Encoding)));
94 std::set<EntityId> ExpectedIds(ExpectedIdRange.begin(),
95 ExpectedIdRange.end());
96
97 // Move ExpectedIds in since linkageTableFromJSON consumes it to verify
98 // that the linkage table contains exactly the ids present in the IdTable.
99 auto ExpectedLinkageTable =
100 linkageTableFromJSON(LinkageTableArray: *LinkageTableArray, ExpectedIds: std::move(ExpectedIds));
101 if (!ExpectedLinkageTable) {
102 return ErrorBuilder::wrap(E: ExpectedLinkageTable.takeError())
103 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "LinkageTable",
104 ArgVals: "linkage_table")
105 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
106 .build();
107 }
108
109 getLinkageTable(X&: Encoding) = std::move(*ExpectedLinkageTable);
110 }
111
112 {
113 const Array *SummaryDataArray = RootObject.getArray(K: "data");
114 if (!SummaryDataArray) {
115 return ErrorBuilder::create(EC: std::errc::invalid_argument,
116 Fmt: ErrorMessages::FailedToReadObjectAtField,
117 ArgVals: "SummaryData entries", ArgVals: "data", ArgVals: "array")
118 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
119 .build();
120 }
121
122 auto ExpectedEncodingSummaryDataMap =
123 encodingSummaryDataMapFromJSON(SummaryDataArray: *SummaryDataArray);
124 if (!ExpectedEncodingSummaryDataMap) {
125 return ErrorBuilder::wrap(E: ExpectedEncodingSummaryDataMap.takeError())
126 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "SummaryData entries",
127 ArgVals: "data")
128 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
129 .build();
130 }
131
132 getData(X&: Encoding) = std::move(*ExpectedEncodingSummaryDataMap);
133 }
134
135 return std::move(Encoding);
136}
137
138llvm::Error
139JSONFormat::writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding,
140 llvm::StringRef Path) {
141 Object RootObject;
142
143 RootObject["lu_namespace"] =
144 nestedBuildNamespaceToJSON(NBN: getLUNamespace(X: SummaryEncoding));
145
146 RootObject["id_table"] = entityIdTableToJSON(IdTable: getIdTable(X: SummaryEncoding));
147
148 RootObject["linkage_table"] =
149 linkageTableToJSON(LinkageTable: getLinkageTable(X: SummaryEncoding));
150
151 RootObject["data"] = encodingSummaryDataMapToJSON(EncodingSummaryDataMap: getData(X: SummaryEncoding));
152
153 if (auto Error = writeJSON(V: std::move(RootObject), Path)) {
154 return ErrorBuilder::wrap(E: std::move(Error))
155 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "LUSummary", ArgVals&: Path)
156 .build();
157 }
158
159 return llvm::Error::success();
160}
161
162} // namespace clang::ssaf
163