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 return ErrorBuilder::create(EC: std::errc::invalid_argument,
149 Fmt: ErrorMessages::UnknownArtifactEncodingType,
150 ArgVals&: *ExpectedType, ArgVals: JSONTypeKey,
151 ArgVals: JSONTypeValueTUSummary, ArgVals: JSONTypeValueLUSummary)
152 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "ArtifactEncoding", ArgVals&: Path)
153 .build();
154}
155
156llvm::Error JSONFormat::writeArtifactEncoding(const ArtifactEncoding &E,
157 llvm::StringRef Path) {
158 return std::visit(
159 visitor: [&](const auto &Enc) -> llvm::Error {
160 using T = std::decay_t<decltype(Enc)>;
161 if constexpr (std::is_same_v<T, TUSummaryEncoding>) {
162 return writeTUSummaryEncoding(SummaryEncoding: Enc, Path);
163 } else {
164 static_assert(
165 std::is_same_v<T, LUSummaryEncoding>,
166 "ArtifactEncoding visitor must cover all variant alternatives");
167 return writeLUSummaryEncoding(SummaryEncoding: Enc, Path);
168 }
169 },
170 variants: E);
171}
172
173} // namespace clang::ssaf
174