1//===- StaticLibrary.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/StaticLibrary.h"
12#include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h"
13#include "llvm/TargetParser/Triple.h"
14
15namespace clang::ssaf {
16
17//----------------------------------------------------------------------------
18// StaticLibrary
19//----------------------------------------------------------------------------
20
21llvm::Expected<StaticLibrary>
22JSONFormat::readStaticLibrary(llvm::StringRef Path) {
23 auto ExpectedJSON = readJSON(Path);
24 if (!ExpectedJSON) {
25 return ErrorBuilder::wrap(E: ExpectedJSON.takeError())
26 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "StaticLibrary", 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,
34 ArgVals: "StaticLibrary", ArgVals: "object")
35 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "StaticLibrary", ArgVals&: Path)
36 .build();
37 }
38
39 if (auto Err = checkSummaryType(RootObject: *RootObjectPtr, ExpectedType: JSONTypeValueStaticLibrary)) {
40 return ErrorBuilder::wrap(E: std::move(Err))
41 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "StaticLibrary", ArgVals&: Path)
42 .build();
43 }
44
45 auto ExpectedStaticLibrary = readStaticLibraryFromObject(Root: *RootObjectPtr);
46 if (!ExpectedStaticLibrary) {
47 return ErrorBuilder::wrap(E: ExpectedStaticLibrary.takeError())
48 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "StaticLibrary", ArgVals&: Path)
49 .build();
50 }
51
52 return std::move(*ExpectedStaticLibrary);
53}
54
55llvm::Expected<StaticLibrary>
56JSONFormat::readStaticLibraryFromObject(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 Object *NamespaceObject = RootObject.getObject(K: "namespace");
75 if (!NamespaceObject) {
76 return ErrorBuilder::create(EC: std::errc::invalid_argument,
77 Fmt: ErrorMessages::FailedToReadObjectAtField,
78 ArgVals: "BuildNamespace", ArgVals: "namespace", ArgVals: "object")
79 .build();
80 }
81
82 auto ExpectedNamespace = buildNamespaceFromJSON(BuildNamespaceObject: *NamespaceObject);
83 if (!ExpectedNamespace) {
84 return ErrorBuilder::wrap(E: ExpectedNamespace.takeError())
85 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "BuildNamespace", ArgVals: "namespace")
86 .build();
87 }
88
89 if (getKind(X&: *ExpectedNamespace) != BuildNamespaceKind::StaticLibrary) {
90 return ErrorBuilder::create(
91 EC: std::errc::invalid_argument,
92 Fmt: ErrorMessages::MismatchedSummaryType,
93 ArgVals: buildNamespaceKindToJSON(BNK: BuildNamespaceKind::StaticLibrary),
94 ArgVals: "namespace.kind",
95 ArgVals: buildNamespaceKindToJSON(BNK: getKind(X&: *ExpectedNamespace)))
96 .build();
97 }
98
99 StaticLibrary S(std::move(T), std::move(*ExpectedNamespace));
100
101 const Array *MembersArray = RootObject.getArray(K: "members");
102 if (!MembersArray) {
103 return ErrorBuilder::create(EC: std::errc::invalid_argument,
104 Fmt: ErrorMessages::FailedToReadObjectAtField,
105 ArgVals: "StaticLibrary members", ArgVals: "members", ArgVals: "array")
106 .build();
107 }
108
109 auto &Members = getMembers(X&: S);
110 const auto &StaticLibraryTriple = getTargetTriple(X&: S);
111
112 for (const auto &[Index, MemberValue] : llvm::enumerate(First: *MembersArray)) {
113 const Object *MemberObject = MemberValue.getAsObject();
114 if (!MemberObject) {
115 return ErrorBuilder::create(EC: std::errc::invalid_argument,
116 Fmt: ErrorMessages::FailedToReadObjectAtIndex,
117 ArgVals: "StaticLibrary member", ArgVals&: Index, ArgVals: "object")
118 .build();
119 }
120
121 if (auto Err = checkSummaryType(RootObject: *MemberObject, ExpectedType: JSONTypeValueTUSummary)) {
122 return ErrorBuilder::wrap(E: std::move(Err))
123 .context(Fmt: ErrorMessages::ReadingFromIndex, ArgVals: "StaticLibrary member",
124 ArgVals&: Index)
125 .build();
126 }
127
128 auto ExpectedMember = readTUSummaryEncodingFromObject(Root: *MemberObject);
129 if (!ExpectedMember) {
130 return ErrorBuilder::wrap(E: ExpectedMember.takeError())
131 .context(Fmt: ErrorMessages::ReadingFromIndex, ArgVals: "StaticLibrary member",
132 ArgVals&: Index)
133 .build();
134 }
135
136 if (ExpectedMember->getTargetTriple() != StaticLibraryTriple) {
137 return ErrorBuilder::create(
138 EC: std::errc::invalid_argument,
139 Fmt: ErrorMessages::MismatchedSummaryType,
140 ArgVals: llvm::Triple::normalize(Str: StaticLibraryTriple.str()),
141 ArgVals: "target_triple",
142 ArgVals: llvm::Triple::normalize(
143 Str: ExpectedMember->getTargetTriple().str()))
144 .context(Fmt: ErrorMessages::ReadingFromIndex, ArgVals: "StaticLibrary member",
145 ArgVals&: Index)
146 .build();
147 }
148
149 auto MemberNamespace = getTUNamespace(X&: *ExpectedMember);
150 auto Owned =
151 std::make_unique<TUSummaryEncoding>(args: std::move(*ExpectedMember));
152 auto [It, Inserted] = Members.insert(x: std::move(Owned));
153 if (!Inserted) {
154 return ErrorBuilder::create(EC: std::errc::invalid_argument,
155 Fmt: ErrorMessages::FailedInsertionOnDuplication,
156 ArgVals: "StaticLibrary member", ArgVals&: Index,
157 ArgVals&: MemberNamespace)
158 .build();
159 }
160 }
161
162 return std::move(S);
163}
164
165llvm::Error JSONFormat::writeStaticLibrary(const StaticLibrary &S,
166 llvm::StringRef Path) {
167 if (auto Error = writeJSON(V: staticLibraryToJSON(S), Path)) {
168 return ErrorBuilder::wrap(E: std::move(Error))
169 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "StaticLibrary", ArgVals&: Path)
170 .build();
171 }
172
173 return llvm::Error::success();
174}
175
176Object JSONFormat::staticLibraryToJSON(const StaticLibrary &S) const {
177 Object RootObject;
178
179 RootObject[JSONTypeKey] = JSONTypeValueStaticLibrary;
180
181 RootObject["target_triple"] =
182 llvm::Triple::normalize(Str: getTargetTriple(X: S).str());
183
184 RootObject["namespace"] = buildNamespaceToJSON(BN: getNamespace(X: S));
185
186 Array MembersArray;
187 MembersArray.reserve(S: getMembers(X: S).size());
188 for (const auto &Member : getMembers(X: S)) {
189 MembersArray.push_back(E: tuSummaryEncodingToJSON(SE: *Member));
190 }
191 RootObject["members"] = std::move(MembersArray);
192
193 return RootObject;
194}
195
196} // namespace clang::ssaf
197