Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / TextAPI / InterfaceFile.cpp
blobf1c6add67b97b9100c94cfec5c9366660a812dfc
1 //===- InterfaceFile.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 // Implements the Interface File.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/TextAPI/InterfaceFile.h"
14 #include "llvm/TextAPI/TextAPIError.h"
15 #include <iomanip>
16 #include <sstream>
18 using namespace llvm;
19 using namespace llvm::MachO;
21 void InterfaceFileRef::addTarget(const Target &Target) {
22 addEntry(Targets, Target);
25 void InterfaceFile::addAllowableClient(StringRef InstallName,
26 const Target &Target) {
27 auto Client = addEntry(AllowableClients, InstallName);
28 Client->addTarget(Target);
31 void InterfaceFile::addReexportedLibrary(StringRef InstallName,
32 const Target &Target) {
33 auto Lib = addEntry(ReexportedLibraries, InstallName);
34 Lib->addTarget(Target);
37 void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {
38 auto Iter = lower_bound(ParentUmbrellas, Target_,
39 [](const std::pair<Target, std::string> &LHS,
40 Target RHS) { return LHS.first < RHS; });
42 if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
43 Iter->second = std::string(Parent);
44 return;
47 ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
50 void InterfaceFile::addRPath(const Target &InputTarget, StringRef RPath) {
51 using RPathEntryT = const std::pair<Target, std::string>;
52 RPathEntryT Entry(InputTarget, RPath);
53 auto Iter =
54 lower_bound(RPaths, Entry,
55 [](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; });
57 if ((Iter != RPaths.end()) && (*Iter == Entry))
58 return;
60 RPaths.emplace(Iter, Entry);
63 void InterfaceFile::addTarget(const Target &Target) {
64 addEntry(Targets, Target);
67 InterfaceFile::const_filtered_target_range
68 InterfaceFile::targets(ArchitectureSet Archs) const {
69 std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
70 return Archs.has(Target_.Arch);
72 return make_filter_range(Targets, fn);
75 void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
76 auto Pos = llvm::lower_bound(Documents, Document,
77 [](const std::shared_ptr<InterfaceFile> &LHS,
78 const std::shared_ptr<InterfaceFile> &RHS) {
79 return LHS->InstallName < RHS->InstallName;
80 });
81 Document->Parent = this;
82 Documents.insert(Pos, Document);
85 void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
86 bool Overwrite) {
87 auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
88 auto It = lower_bound(
89 Documents, Reexport->getInstallName(),
90 [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
91 return Lhs->getInstallName() < Rhs;
92 });
94 if (Overwrite && It != Documents.end() &&
95 Reexport->getInstallName() == (*It)->getInstallName()) {
96 std::replace(Documents.begin(), Documents.end(), *It,
97 std::move(Reexport));
98 return;
101 if ((It != Documents.end()) &&
102 !(Reexport->getInstallName() < (*It)->getInstallName()))
103 return;
105 Documents.emplace(It, std::move(Reexport));
107 for (auto Doc : Library->documents())
108 AddFwk(std::move(Doc));
110 Library->Documents.clear();
111 AddFwk(std::move(Library));
114 Expected<std::unique_ptr<InterfaceFile>>
115 InterfaceFile::merge(const InterfaceFile *O) const {
116 // Verify files can be merged.
117 if (getInstallName() != O->getInstallName()) {
118 return make_error<StringError>("install names do not match",
119 inconvertibleErrorCode());
122 if (getCurrentVersion() != O->getCurrentVersion()) {
123 return make_error<StringError>("current versions do not match",
124 inconvertibleErrorCode());
127 if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
128 return make_error<StringError>("compatibility versions do not match",
129 inconvertibleErrorCode());
132 if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
133 (getSwiftABIVersion() != O->getSwiftABIVersion())) {
134 return make_error<StringError>("swift ABI versions do not match",
135 inconvertibleErrorCode());
138 if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
139 return make_error<StringError>("two level namespace flags do not match",
140 inconvertibleErrorCode());
143 if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
144 return make_error<StringError>(
145 "application extension safe flags do not match",
146 inconvertibleErrorCode());
149 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
150 IF->setFileType(std::max(getFileType(), O->getFileType()));
151 IF->setPath(getPath());
152 IF->setInstallName(getInstallName());
153 IF->setCurrentVersion(getCurrentVersion());
154 IF->setCompatibilityVersion(getCompatibilityVersion());
156 if (getSwiftABIVersion() == 0)
157 IF->setSwiftABIVersion(O->getSwiftABIVersion());
158 else
159 IF->setSwiftABIVersion(getSwiftABIVersion());
161 IF->setTwoLevelNamespace(isTwoLevelNamespace());
162 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
164 for (const auto &It : umbrellas()) {
165 if (!It.second.empty())
166 IF->addParentUmbrella(It.first, It.second);
168 for (const auto &It : O->umbrellas()) {
169 if (!It.second.empty())
170 IF->addParentUmbrella(It.first, It.second);
172 IF->addTargets(targets());
173 IF->addTargets(O->targets());
175 for (const auto &Lib : allowableClients())
176 for (const auto &Target : Lib.targets())
177 IF->addAllowableClient(Lib.getInstallName(), Target);
179 for (const auto &Lib : O->allowableClients())
180 for (const auto &Target : Lib.targets())
181 IF->addAllowableClient(Lib.getInstallName(), Target);
183 for (const auto &Lib : reexportedLibraries())
184 for (const auto &Target : Lib.targets())
185 IF->addReexportedLibrary(Lib.getInstallName(), Target);
187 for (const auto &Lib : O->reexportedLibraries())
188 for (const auto &Target : Lib.targets())
189 IF->addReexportedLibrary(Lib.getInstallName(), Target);
191 for (const auto &[Target, Path] : rpaths())
192 IF->addRPath(Target, Path);
193 for (const auto &[Target, Path] : O->rpaths())
194 IF->addRPath(Target, Path);
196 for (const auto *Sym : symbols()) {
197 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
198 Sym->getFlags());
201 for (const auto *Sym : O->symbols()) {
202 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
203 Sym->getFlags());
206 return std::move(IF);
209 Expected<std::unique_ptr<InterfaceFile>>
210 InterfaceFile::remove(Architecture Arch) const {
211 if (getArchitectures() == Arch)
212 return make_error<StringError>("cannot remove last architecture slice '" +
213 getArchitectureName(Arch) + "'",
214 inconvertibleErrorCode());
216 if (!getArchitectures().has(Arch)) {
217 bool Found = false;
218 for (auto &Doc : Documents) {
219 if (Doc->getArchitectures().has(Arch)) {
220 Found = true;
221 break;
225 if (!Found)
226 return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
229 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
230 IF->setFileType(getFileType());
231 IF->setPath(getPath());
232 IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
233 IF->setInstallName(getInstallName());
234 IF->setCurrentVersion(getCurrentVersion());
235 IF->setCompatibilityVersion(getCompatibilityVersion());
236 IF->setSwiftABIVersion(getSwiftABIVersion());
237 IF->setTwoLevelNamespace(isTwoLevelNamespace());
238 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
239 for (const auto &It : umbrellas())
240 if (It.first.Arch != Arch)
241 IF->addParentUmbrella(It.first, It.second);
243 for (const auto &Lib : allowableClients()) {
244 for (const auto &Target : Lib.targets())
245 if (Target.Arch != Arch)
246 IF->addAllowableClient(Lib.getInstallName(), Target);
249 for (const auto &Lib : reexportedLibraries()) {
250 for (const auto &Target : Lib.targets())
251 if (Target.Arch != Arch)
252 IF->addReexportedLibrary(Lib.getInstallName(), Target);
255 for (const auto *Sym : symbols()) {
256 auto Archs = Sym->getArchitectures();
257 Archs.clear(Arch);
258 if (Archs.empty())
259 continue;
261 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
262 Sym->getFlags());
265 for (auto &Doc : Documents) {
266 // Skip the inlined document if the to be removed architecture is the
267 // only one left.
268 if (Doc->getArchitectures() == Arch)
269 continue;
271 // If the document doesn't contain the arch, then no work is to be done
272 // and it can be copied over.
273 if (!Doc->getArchitectures().has(Arch)) {
274 auto NewDoc = Doc;
275 IF->addDocument(std::move(NewDoc));
276 continue;
279 auto Result = Doc->remove(Arch);
280 if (!Result)
281 return Result;
283 IF->addDocument(std::move(Result.get()));
286 return std::move(IF);
289 Expected<std::unique_ptr<InterfaceFile>>
290 InterfaceFile::extract(Architecture Arch) const {
291 if (!getArchitectures().has(Arch)) {
292 return make_error<StringError>("file doesn't have architecture '" +
293 getArchitectureName(Arch) + "'",
294 inconvertibleErrorCode());
297 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
298 IF->setFileType(getFileType());
299 IF->setPath(getPath());
300 IF->addTargets(targets(Arch));
301 IF->setInstallName(getInstallName());
302 IF->setCurrentVersion(getCurrentVersion());
303 IF->setCompatibilityVersion(getCompatibilityVersion());
304 IF->setSwiftABIVersion(getSwiftABIVersion());
305 IF->setTwoLevelNamespace(isTwoLevelNamespace());
306 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
307 for (const auto &It : umbrellas())
308 if (It.first.Arch == Arch)
309 IF->addParentUmbrella(It.first, It.second);
311 for (const auto &It : rpaths())
312 if (It.first.Arch == Arch)
313 IF->addRPath(It.first, It.second);
315 for (const auto &Lib : allowableClients())
316 for (const auto &Target : Lib.targets())
317 if (Target.Arch == Arch)
318 IF->addAllowableClient(Lib.getInstallName(), Target);
320 for (const auto &Lib : reexportedLibraries())
321 for (const auto &Target : Lib.targets())
322 if (Target.Arch == Arch)
323 IF->addReexportedLibrary(Lib.getInstallName(), Target);
325 for (const auto *Sym : symbols()) {
326 if (Sym->hasArchitecture(Arch))
327 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
328 Sym->getFlags());
331 for (auto &Doc : Documents) {
332 // Skip documents that don't have the requested architecture.
333 if (!Doc->getArchitectures().has(Arch))
334 continue;
336 auto Result = Doc->extract(Arch);
337 if (!Result)
338 return Result;
340 IF->addDocument(std::move(Result.get()));
343 return std::move(IF);
346 static bool isYAMLTextStub(const FileType &Kind) {
347 return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
350 bool InterfaceFile::operator==(const InterfaceFile &O) const {
351 if (Targets != O.Targets)
352 return false;
353 if (InstallName != O.InstallName)
354 return false;
355 if ((CurrentVersion != O.CurrentVersion) ||
356 (CompatibilityVersion != O.CompatibilityVersion))
357 return false;
358 if (SwiftABIVersion != O.SwiftABIVersion)
359 return false;
360 if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
361 return false;
362 if (IsAppExtensionSafe != O.IsAppExtensionSafe)
363 return false;
364 if (HasSimSupport != O.HasSimSupport)
365 return false;
366 if (ParentUmbrellas != O.ParentUmbrellas)
367 return false;
368 if (AllowableClients != O.AllowableClients)
369 return false;
370 if (ReexportedLibraries != O.ReexportedLibraries)
371 return false;
372 if (*SymbolsSet != *O.SymbolsSet)
373 return false;
374 // Don't compare run search paths for older filetypes that cannot express
375 // them.
376 if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
377 if (RPaths != O.RPaths)
378 return false;
379 if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
380 return false;
383 if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
384 O.Documents.end(),
385 [](const std::shared_ptr<InterfaceFile> LHS,
386 const std::shared_ptr<InterfaceFile> RHS) {
387 return *LHS == *RHS;
389 return false;
390 return true;