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