1//===- LUSummary.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/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h"
12#include "llvm/TargetParser/Triple.h"
13
14#include <set>
15
16namespace clang::ssaf {
17
18//----------------------------------------------------------------------------
19// LUSummary
20//----------------------------------------------------------------------------
21
22llvm::Expected<LUSummary> JSONFormat::readLUSummary(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 if (auto Err = checkSummaryType(RootObject: *RootObjectPtr, ExpectedType: JSONTypeValueLUSummary)) {
40 return ErrorBuilder::wrap(E: std::move(Err))
41 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
42 .build();
43 }
44
45 auto ExpectedSummary = readLUSummaryFromObject(Root: *RootObjectPtr);
46 if (!ExpectedSummary) {
47 return ErrorBuilder::wrap(E: ExpectedSummary.takeError())
48 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "LUSummary", ArgVals&: Path)
49 .build();
50 }
51
52 return std::move(*ExpectedSummary);
53}
54
55llvm::Expected<LUSummary>
56JSONFormat::readLUSummaryFromObject(const Object &RootObject) {
57 auto OptTargetTriple = RootObject.getString(K: "target_triple");
58 if (!OptTargetTriple) {
59 return ErrorBuilder::create(EC: std::errc::invalid_argument,
60 Fmt: ErrorMessages::FailedToReadObjectAtField,
61 ArgVals: "TargetTriple", ArgVals: "target_triple", ArgVals: "string")
62 .build();
63 }
64
65 if (auto Err = validateNormalizedTargetTriple(Triple: *OptTargetTriple)) {
66 return ErrorBuilder::wrap(E: std::move(Err))
67 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "TargetTriple",
68 ArgVals: "target_triple")
69 .build();
70 }
71
72 llvm::Triple T(*OptTargetTriple);
73
74 const Array *LUNamespaceArray = RootObject.getArray(K: "lu_namespace");
75 if (!LUNamespaceArray) {
76 return ErrorBuilder::create(EC: std::errc::invalid_argument,
77 Fmt: ErrorMessages::FailedToReadObjectAtField,
78 ArgVals: "NestedBuildNamespace", ArgVals: "lu_namespace", ArgVals: "array")
79 .build();
80 }
81
82 auto ExpectedLUNamespace = nestedBuildNamespaceFromJSON(NestedBuildNamespaceArray: *LUNamespaceArray);
83 if (!ExpectedLUNamespace) {
84 return ErrorBuilder::wrap(E: ExpectedLUNamespace.takeError())
85 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "NestedBuildNamespace",
86 ArgVals: "lu_namespace")
87 .build();
88 }
89
90 LUSummary Summary(std::move(T), std::move(*ExpectedLUNamespace));
91
92 {
93 const Array *IdTableArray = RootObject.getArray(K: "id_table");
94 if (!IdTableArray) {
95 return ErrorBuilder::create(EC: std::errc::invalid_argument,
96 Fmt: ErrorMessages::FailedToReadObjectAtField,
97 ArgVals: "IdTable", ArgVals: "id_table", ArgVals: "array")
98 .build();
99 }
100
101 auto ExpectedIdTable = luEntityIdTableFromJSON(EntityIdTableArray: *IdTableArray);
102 if (!ExpectedIdTable) {
103 return ErrorBuilder::wrap(E: ExpectedIdTable.takeError())
104 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "IdTable", ArgVals: "id_table")
105 .build();
106 }
107
108 getIdTable(X&: Summary) = std::move(*ExpectedIdTable);
109 }
110
111 {
112 const Array *LinkageTableArray = RootObject.getArray(K: "linkage_table");
113 if (!LinkageTableArray) {
114 return ErrorBuilder::create(EC: std::errc::invalid_argument,
115 Fmt: ErrorMessages::FailedToReadObjectAtField,
116 ArgVals: "LinkageTable", ArgVals: "linkage_table", ArgVals: "array")
117 .build();
118 }
119
120 auto ExpectedIdRange =
121 llvm::make_second_range(c&: getEntities(X&: getIdTable(X&: Summary)));
122 std::set<EntityId> ExpectedIds(ExpectedIdRange.begin(),
123 ExpectedIdRange.end());
124
125 // Move ExpectedIds in since linkageTableFromJSON consumes it to verify
126 // that the linkage table contains exactly the ids present in the IdTable.
127 auto ExpectedLinkageTable =
128 linkageTableFromJSON(LinkageTableArray: *LinkageTableArray, ExpectedIds: std::move(ExpectedIds));
129 if (!ExpectedLinkageTable) {
130 return ErrorBuilder::wrap(E: ExpectedLinkageTable.takeError())
131 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "LinkageTable",
132 ArgVals: "linkage_table")
133 .build();
134 }
135
136 getLinkageTable(X&: Summary) = std::move(*ExpectedLinkageTable);
137 }
138
139 {
140 const Array *SummaryDataArray = RootObject.getArray(K: "data");
141 if (!SummaryDataArray) {
142 return ErrorBuilder::create(EC: std::errc::invalid_argument,
143 Fmt: ErrorMessages::FailedToReadObjectAtField,
144 ArgVals: "SummaryData entries", ArgVals: "data", ArgVals: "array")
145 .build();
146 }
147
148 auto ExpectedSummaryDataMap =
149 summaryDataMapFromJSON(SummaryDataArray: *SummaryDataArray, IdTable&: getIdTable(X&: Summary));
150 if (!ExpectedSummaryDataMap) {
151 return ErrorBuilder::wrap(E: ExpectedSummaryDataMap.takeError())
152 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "SummaryData entries",
153 ArgVals: "data")
154 .build();
155 }
156
157 getData(X&: Summary) = std::move(*ExpectedSummaryDataMap);
158 }
159
160 return std::move(Summary);
161}
162
163llvm::Error JSONFormat::writeLUSummary(const LUSummary &S,
164 llvm::StringRef Path) {
165 Object RootObject;
166
167 RootObject[JSONTypeKey] = JSONTypeValueLUSummary;
168
169 RootObject["target_triple"] =
170 llvm::Triple::normalize(Str: getTargetTriple(X: S).str());
171
172 RootObject["lu_namespace"] = nestedBuildNamespaceToJSON(NBN: getLUNamespace(X: S));
173
174 RootObject["id_table"] = luEntityIdTableToJSON(IdTable: getIdTable(X: S));
175
176 RootObject["linkage_table"] = linkageTableToJSON(LinkageTable: getLinkageTable(X: S));
177
178 auto ExpectedDataObject = summaryDataMapToJSON(SummaryDataMap: getData(X: S));
179 if (!ExpectedDataObject) {
180 return ErrorBuilder::wrap(E: ExpectedDataObject.takeError())
181 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "LUSummary", ArgVals&: Path)
182 .build();
183 }
184
185 RootObject["data"] = std::move(*ExpectedDataObject);
186
187 if (auto Error = writeJSON(V: std::move(RootObject), Path)) {
188 return ErrorBuilder::wrap(E: std::move(Error))
189 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "LUSummary", ArgVals&: Path)
190 .build();
191 }
192
193 return llvm::Error::success();
194}
195
196} // namespace clang::ssaf
197