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::addUUID(const Target &Target_, StringRef UUID) {
75   auto Iter = lower_bound(UUIDs, Target_,
76                           [](const std::pair<Target, std::string> &LHS,
77                              Target RHS) { return LHS.first < RHS; });
78 
79   if ((Iter != UUIDs.end()) && !(Target_ < Iter->first)) {
80     Iter->second = std::string(UUID);
81     return;
82   }
83 
84   UUIDs.emplace(Iter, Target_, std::string(UUID));
85 }
86 
87 void InterfaceFile::addUUID(const Target &Target, uint8_t UUID[16]) {
88   std::stringstream Stream;
89   for (unsigned i = 0; i < 16; ++i) {
90     if (i == 4 || i == 6 || i == 8 || i == 10)
91       Stream << '-';
92     Stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex
93            << static_cast<int>(UUID[i]);
94   }
95   addUUID(Target, Stream.str());
96 }
97 
98 void InterfaceFile::addTarget(const Target &Target) {
99   addEntry(Targets, Target);
100 }
101 
102 InterfaceFile::const_filtered_target_range
103 InterfaceFile::targets(ArchitectureSet Archs) const {
104   std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
105     return Archs.has(Target_.Arch);
106   };
107   return make_filter_range(Targets, fn);
108 }
109 
110 void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name,
111                               const TargetList &Targets, SymbolFlags Flags) {
112   Name = copyString(Name);
113   auto result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr);
114   if (result.second)
115     result.first->second = new (Allocator) Symbol{Kind, Name, Targets, Flags};
116   else
117     for (const auto &Target : Targets)
118       result.first->second->addTarget(Target);
119 }
120 
121 void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
122   auto Pos = llvm::lower_bound(Documents, Document,
123                                [](const std::shared_ptr<InterfaceFile> &LHS,
124                                   const std::shared_ptr<InterfaceFile> &RHS) {
125                                  return LHS->InstallName < RHS->InstallName;
126                                });
127   Document->Parent = this;
128   Documents.insert(Pos, Document);
129 }
130 
131 bool InterfaceFile::operator==(const InterfaceFile &O) const {
132   if (Targets != O.Targets)
133     return false;
134   if (InstallName != O.InstallName)
135     return false;
136   if ((CurrentVersion != O.CurrentVersion) ||
137       (CompatibilityVersion != O.CompatibilityVersion))
138     return false;
139   if (SwiftABIVersion != O.SwiftABIVersion)
140     return false;
141   if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
142     return false;
143   if (IsAppExtensionSafe != O.IsAppExtensionSafe)
144     return false;
145   if (IsInstallAPI != O.IsInstallAPI)
146     return false;
147   if (ParentUmbrellas != O.ParentUmbrellas)
148     return false;
149   if (AllowableClients != O.AllowableClients)
150     return false;
151   if (ReexportedLibraries != O.ReexportedLibraries)
152     return false;
153   if (Symbols != O.Symbols)
154     return false;
155   if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
156                   O.Documents.end(),
157                   [](const std::shared_ptr<InterfaceFile> LHS,
158                      const std::shared_ptr<InterfaceFile> RHS) {
159                     return *LHS == *RHS;
160                   }))
161     return false;
162   return true;
163 }
164