xref: /llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp (revision bc85cf1687435f28fb01b1aa5303317e6118490c)
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.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/TextAPI/InterfaceFile.h"
14 #include <iomanip>
15 #include <sstream>
16 
17 using namespace llvm;
18 using namespace llvm::MachO;
19 
20 namespace {
21 template <typename C>
22 typename C::iterator addEntry(C &Container, StringRef InstallName) {
23   auto I = partition_point(Container, [=](const InterfaceFileRef &O) {
24     return O.getInstallName() < InstallName;
25   });
26   if (I != Container.end() && I->getInstallName() == InstallName)
27     return I;
28 
29   return Container.emplace(I, InstallName);
30 }
31 
32 template <typename C>
33 typename C::iterator addEntry(C &Container, const Target &Target_) {
34   auto Iter =
35       lower_bound(Container, Target_, [](const Target &LHS, const Target &RHS) {
36         return LHS < RHS;
37       });
38   if ((Iter != std::end(Container)) && !(Target_ < *Iter))
39     return Iter;
40 
41   return Container.insert(Iter, Target_);
42 }
43 } // end namespace
44 
45 void InterfaceFileRef::addTarget(const Target &Target) {
46   addEntry(Targets, Target);
47 }
48 
49 void InterfaceFile::addAllowableClient(StringRef InstallName,
50                                        const Target &Target) {
51   auto Client = addEntry(AllowableClients, InstallName);
52   Client->addTarget(Target);
53 }
54 
55 void InterfaceFile::addReexportedLibrary(StringRef InstallName,
56                                          const Target &Target) {
57   auto Lib = addEntry(ReexportedLibraries, InstallName);
58   Lib->addTarget(Target);
59 }
60 
61 void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {
62   auto Iter = lower_bound(ParentUmbrellas, Target_,
63                           [](const std::pair<Target, std::string> &LHS,
64                              Target RHS) { return LHS.first < RHS; });
65 
66   if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
67     Iter->second = std::string(Parent);
68     return;
69   }
70 
71   ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
72 }
73 
74 void InterfaceFile::addRPath(const Target &InputTarget, StringRef RPath) {
75   auto Iter = lower_bound(RPaths, InputTarget,
76                           [](const std::pair<Target, std::string> &LHS,
77                              Target RHS) { return LHS.first < RHS; });
78 
79   if ((Iter != RPaths.end()) && !(InputTarget < Iter->first)) {
80     Iter->second = std::string(RPath);
81     return;
82   }
83 
84   RPaths.emplace(Iter, InputTarget, std::string(RPath));
85 }
86 
87 void InterfaceFile::addUUID(const Target &Target_, StringRef UUID) {
88   auto Iter = lower_bound(UUIDs, Target_,
89                           [](const std::pair<Target, std::string> &LHS,
90                              Target RHS) { return LHS.first < RHS; });
91 
92   if ((Iter != UUIDs.end()) && !(Target_ < Iter->first)) {
93     Iter->second = std::string(UUID);
94     return;
95   }
96 
97   UUIDs.emplace(Iter, Target_, std::string(UUID));
98 }
99 
100 void InterfaceFile::addUUID(const Target &Target, uint8_t UUID[16]) {
101   std::stringstream Stream;
102   for (unsigned i = 0; i < 16; ++i) {
103     if (i == 4 || i == 6 || i == 8 || i == 10)
104       Stream << '-';
105     Stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex
106            << static_cast<int>(UUID[i]);
107   }
108   addUUID(Target, Stream.str());
109 }
110 
111 void InterfaceFile::addTarget(const Target &Target) {
112   addEntry(Targets, Target);
113 }
114 
115 InterfaceFile::const_filtered_target_range
116 InterfaceFile::targets(ArchitectureSet Archs) const {
117   std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
118     return Archs.has(Target_.Arch);
119   };
120   return make_filter_range(Targets, fn);
121 }
122 
123 void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name,
124                               const TargetList &Targets, SymbolFlags Flags) {
125   Name = copyString(Name);
126   auto result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr);
127   if (result.second)
128     result.first->second = new (Allocator) Symbol{Kind, Name, Targets, Flags};
129   else
130     for (const auto &Target : Targets)
131       result.first->second->addTarget(Target);
132 }
133 
134 void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
135   auto Pos = llvm::lower_bound(Documents, Document,
136                                [](const std::shared_ptr<InterfaceFile> &LHS,
137                                   const std::shared_ptr<InterfaceFile> &RHS) {
138                                  return LHS->InstallName < RHS->InstallName;
139                                });
140   Document->Parent = this;
141   Documents.insert(Pos, Document);
142 }
143 
144 static bool isYAMLTextStub(const FileType &Kind) {
145   return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
146 }
147 
148 bool InterfaceFile::operator==(const InterfaceFile &O) const {
149   if (Targets != O.Targets)
150     return false;
151   if (InstallName != O.InstallName)
152     return false;
153   if ((CurrentVersion != O.CurrentVersion) ||
154       (CompatibilityVersion != O.CompatibilityVersion))
155     return false;
156   if (SwiftABIVersion != O.SwiftABIVersion)
157     return false;
158   if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
159     return false;
160   if (IsAppExtensionSafe != O.IsAppExtensionSafe)
161     return false;
162   if (IsInstallAPI != O.IsInstallAPI)
163     return false;
164   if (ParentUmbrellas != O.ParentUmbrellas)
165     return false;
166   if (AllowableClients != O.AllowableClients)
167     return false;
168   if (ReexportedLibraries != O.ReexportedLibraries)
169     return false;
170   if (Symbols != O.Symbols)
171     return false;
172   // Don't compare run search paths for older filetypes that cannot express
173   // them.
174   if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
175     if (RPaths != O.RPaths)
176       return false;
177   }
178 
179   if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
180                   O.Documents.end(),
181                   [](const std::shared_ptr<InterfaceFile> LHS,
182                      const std::shared_ptr<InterfaceFile> RHS) {
183                     return *LHS == *RHS;
184                   }))
185     return false;
186   return true;
187 }
188