1//===- Artifact.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// Generic artifact read/write entry points that dispatch on the
10// self-describing "type" field of the JSON document.
11//
12//===----------------------------------------------------------------------===//
13
14#include "JSONFormatImpl.h"
15
16namespace clang::ssaf {
17
18llvm::Expected<Artifact> JSONFormat::readArtifact(llvm::StringRef Path) {
19 auto ExpectedJSON = readJSON(Path);
20 if (!ExpectedJSON) {
21 return ErrorBuilder::wrap(E: ExpectedJSON.takeError())
22 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
23 .build();
24 }
25
26 Object *RootObjectPtr = ExpectedJSON->getAsObject();
27 if (!RootObjectPtr) {
28 return ErrorBuilder::create(EC: std::errc::invalid_argument,
29 Fmt: ErrorMessages::FailedToReadObject, ArgVals: "Artifact",
30 ArgVals: "object")
31 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
32 .build();
33 }
34
35 auto ExpectedType = readSummaryType(RootObject: *RootObjectPtr);
36 if (!ExpectedType) {
37 return ErrorBuilder::wrap(E: ExpectedType.takeError())
38 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
39 .build();
40 }
41
42 // Dispatch by the self-describing type field. The helpers operate on
43 // the already-parsed root object so the file is read and parsed only
44 // once per readArtifact call.
45 if (*ExpectedType == JSONTypeValueTUSummary) {
46 auto ExpectedTU = readTUSummaryFromObject(Root: *RootObjectPtr);
47 if (!ExpectedTU) {
48 return ErrorBuilder::wrap(E: ExpectedTU.takeError())
49 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
50 .build();
51 }
52 return Artifact{std::move(*ExpectedTU)};
53 }
54
55 if (*ExpectedType == JSONTypeValueLUSummary) {
56 auto ExpectedLU = readLUSummaryFromObject(Root: *RootObjectPtr);
57 if (!ExpectedLU) {
58 return ErrorBuilder::wrap(E: ExpectedLU.takeError())
59 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
60 .build();
61 }
62 return Artifact{std::move(*ExpectedLU)};
63 }
64
65 if (*ExpectedType == JSONTypeValueWPASuite) {
66 auto ExpectedWPA = readWPASuiteFromObject(Root: *RootObjectPtr);
67 if (!ExpectedWPA) {
68 return ErrorBuilder::wrap(E: ExpectedWPA.takeError())
69 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
70 .build();
71 }
72 return Artifact{std::move(*ExpectedWPA)};
73 }
74
75 return ErrorBuilder::create(EC: std::errc::invalid_argument,
76 Fmt: ErrorMessages::UnknownArtifactType, ArgVals&: *ExpectedType,
77 ArgVals: JSONTypeKey, ArgVals: JSONTypeValueTUSummary,
78 ArgVals: JSONTypeValueLUSummary, ArgVals: JSONTypeValueWPASuite)
79 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "Artifact", ArgVals&: Path)
80 .build();
81}
82
83llvm::Error JSONFormat::writeArtifact(const Artifact &A, llvm::StringRef Path) {
84 return std::visit(
85 visitor: [&](const auto &S) -> llvm::Error {
86 using T = std::decay_t<decltype(S)>;
87 if constexpr (std::is_same_v<T, TUSummary>) {
88 return writeTUSummary(Summary: S, Path);
89 } else if constexpr (std::is_same_v<T, LUSummary>) {
90 return writeLUSummary(Summary: S, Path);
91 } else {
92 static_assert(std::is_same_v<T, WPASuite>,
93 "Artifact visitor must cover all variant alternatives");
94 return writeWPASuite(Suite: S, Path);
95 }
96 },
97 variants: A);
98}
99
100llvm::Expected<ArtifactEncoding>
101JSONFormat::readArtifactEncoding(llvm::StringRef Path) {
102 auto ExpectedJSON = readJSON(Path);
103 if (!ExpectedJSON) {
104 return ErrorBuilder::wrap(E: ExpectedJSON.takeError())
105 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
106 .build();
107 }
108
109 Object *RootObjectPtr = ExpectedJSON->getAsObject();
110 if (!RootObjectPtr) {
111 return ErrorBuilder::create(EC: std::errc::invalid_argument,
112 Fmt: ErrorMessages::FailedToReadObject,
113 ArgVals: "ArtifactEncoding", ArgVals: "object")
114 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
115 .build();
116 }
117
118 auto ExpectedType = readSummaryType(RootObject: *RootObjectPtr);
119 if (!ExpectedType) {
120 return ErrorBuilder::wrap(E: ExpectedType.takeError())
121 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
122 .build();
123 }
124
125 // Dispatch by the self-describing type field. The helpers operate on
126 // the already-parsed root object so the file is read and parsed only
127 // once per readArtifactEncoding call.
128 if (*ExpectedType == JSONTypeValueTUSummary) {
129 auto ExpectedTU = readTUSummaryEncodingFromObject(Root: *RootObjectPtr);
130 if (!ExpectedTU) {
131 return ErrorBuilder::wrap(E: ExpectedTU.takeError())
132 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
133 .build();
134 }
135 return ArtifactEncoding{std::move(*ExpectedTU)};
136 }
137
138 if (*ExpectedType == JSONTypeValueLUSummary) {
139 auto ExpectedLU = readLUSummaryEncodingFromObject(Root: *RootObjectPtr);
140 if (!ExpectedLU) {
141 return ErrorBuilder::wrap(E: ExpectedLU.takeError())
142 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
143 .build();
144 }
145 return ArtifactEncoding{std::move(*ExpectedLU)};
146 }
147
148 if (*ExpectedType == JSONTypeValueStaticLibrary) {
149 auto ExpectedStaticLibrary = readStaticLibraryFromObject(Root: *RootObjectPtr);
150 if (!ExpectedStaticLibrary) {
151 return ErrorBuilder::wrap(E: ExpectedStaticLibrary.takeError())
152 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
153 .build();
154 }
155 return ArtifactEncoding{std::move(*ExpectedStaticLibrary)};
156 }
157
158 if (*ExpectedType == JSONTypeValueMultiArchStaticLibrary) {
159 auto ExpectedM = readMultiArchStaticLibraryFromObject(Root: *RootObjectPtr);
160 if (!ExpectedM) {
161 return ErrorBuilder::wrap(E: ExpectedM.takeError())
162 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
163 .build();
164 }
165 return ArtifactEncoding{std::move(*ExpectedM)};
166 }
167
168 if (*ExpectedType == JSONTypeValueMultiArchSharedLibrary) {
169 auto ExpectedM = readMultiArchSharedLibraryFromObject(Root: *RootObjectPtr);
170 if (!ExpectedM) {
171 return ErrorBuilder::wrap(E: ExpectedM.takeError())
172 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
173 .build();
174 }
175 return ArtifactEncoding{std::move(*ExpectedM)};
176 }
177
178 return ErrorBuilder::create(
179 EC: std::errc::invalid_argument,
180 Fmt: ErrorMessages::UnknownArtifactEncodingType, ArgVals&: *ExpectedType,
181 ArgVals: JSONTypeKey, ArgVals: JSONTypeValueTUSummary, ArgVals: JSONTypeValueLUSummary,
182 ArgVals: JSONTypeValueStaticLibrary, ArgVals: JSONTypeValueMultiArchStaticLibrary,
183 ArgVals: JSONTypeValueMultiArchSharedLibrary)
184 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
185 .build();
186}
187
188llvm::Error JSONFormat::writeArtifactEncoding(const ArtifactEncoding &E,
189 llvm::StringRef Path) {
190 return std::visit(
191 visitor: [&](const auto &Enc) -> llvm::Error {
192 using T = std::decay_t<decltype(Enc)>;
193 if constexpr (std::is_same_v<T, TUSummaryEncoding>) {
194 return writeTUSummaryEncoding(SummaryEncoding: Enc, Path);
195 } else if constexpr (std::is_same_v<T, LUSummaryEncoding>) {
196 return writeLUSummaryEncoding(SummaryEncoding: Enc, Path);
197 } else if constexpr (std::is_same_v<T, StaticLibrary>) {
198 return writeStaticLibrary(S: Enc, Path);
199 } else if constexpr (std::is_same_v<T, MultiArchStaticLibrary>) {
200 return writeMultiArchStaticLibrary(M: Enc, Path);
201 } else {
202 static_assert(
203 std::is_same_v<T, MultiArchSharedLibrary>,
204 "ArtifactEncoding visitor must cover all variant alternatives");
205 return writeMultiArchSharedLibrary(M: Enc, Path);
206 }
207 },
208 variants: E);
209}
210
211} // namespace clang::ssaf
212