xref: /freebsd/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp (revision 27bd6c32bbb49a592a0dfbec5f211a7c2fed31d6)
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 "llvm/TextAPI/RecordsSlice.h"
15  #include "llvm/TextAPI/TextAPIError.h"
16  #include <iomanip>
17  #include <sstream>
18  
19  using namespace llvm;
20  using namespace llvm::MachO;
21  
22  void InterfaceFileRef::addTarget(const Target &Target) {
23    addEntry(Targets, Target);
24  }
25  
26  void InterfaceFile::addAllowableClient(StringRef InstallName,
27                                         const Target &Target) {
28    if (InstallName.empty())
29      return;
30    auto Client = addEntry(AllowableClients, InstallName);
31    Client->addTarget(Target);
32  }
33  
34  void InterfaceFile::addReexportedLibrary(StringRef InstallName,
35                                           const Target &Target) {
36    if (InstallName.empty())
37      return;
38    auto Lib = addEntry(ReexportedLibraries, InstallName);
39    Lib->addTarget(Target);
40  }
41  
42  void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {
43    if (Parent.empty())
44      return;
45    auto Iter = lower_bound(ParentUmbrellas, Target_,
46                            [](const std::pair<Target, std::string> &LHS,
47                               Target RHS) { return LHS.first < RHS; });
48  
49    if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
50      Iter->second = std::string(Parent);
51      return;
52    }
53  
54    ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
55  }
56  
57  void InterfaceFile::addRPath(StringRef RPath, const Target &InputTarget) {
58    if (RPath.empty())
59      return;
60    using RPathEntryT = const std::pair<Target, std::string>;
61    RPathEntryT Entry(InputTarget, RPath);
62    auto Iter =
63        lower_bound(RPaths, Entry,
64                    [](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; });
65  
66    if ((Iter != RPaths.end()) && (*Iter == Entry))
67      return;
68  
69    RPaths.emplace(Iter, Entry);
70  }
71  
72  void InterfaceFile::addTarget(const Target &Target) {
73    addEntry(Targets, Target);
74  }
75  
76  InterfaceFile::const_filtered_target_range
77  InterfaceFile::targets(ArchitectureSet Archs) const {
78    std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
79      return Archs.has(Target_.Arch);
80    };
81    return make_filter_range(Targets, fn);
82  }
83  
84  void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
85    auto Pos = llvm::lower_bound(Documents, Document,
86                                 [](const std::shared_ptr<InterfaceFile> &LHS,
87                                    const std::shared_ptr<InterfaceFile> &RHS) {
88                                   return LHS->InstallName < RHS->InstallName;
89                                 });
90    Document->Parent = this;
91    Documents.insert(Pos, Document);
92  }
93  
94  void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
95                                    bool Overwrite) {
96    auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
97      auto It = lower_bound(
98          Documents, Reexport->getInstallName(),
99          [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
100            return Lhs->getInstallName() < Rhs;
101          });
102  
103      if (Overwrite && It != Documents.end() &&
104          Reexport->getInstallName() == (*It)->getInstallName()) {
105        std::replace(Documents.begin(), Documents.end(), *It,
106                     std::move(Reexport));
107        return;
108      }
109  
110      if ((It != Documents.end()) &&
111          !(Reexport->getInstallName() < (*It)->getInstallName()))
112        return;
113  
114      Documents.emplace(It, std::move(Reexport));
115    };
116    for (auto Doc : Library->documents())
117      AddFwk(std::move(Doc));
118  
119    Library->Documents.clear();
120    AddFwk(std::move(Library));
121  }
122  
123  Expected<std::unique_ptr<InterfaceFile>>
124  InterfaceFile::merge(const InterfaceFile *O) const {
125    // Verify files can be merged.
126    if (getInstallName() != O->getInstallName()) {
127      return make_error<StringError>("install names do not match",
128                                     inconvertibleErrorCode());
129    }
130  
131    if (getCurrentVersion() != O->getCurrentVersion()) {
132      return make_error<StringError>("current versions do not match",
133                                     inconvertibleErrorCode());
134    }
135  
136    if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
137      return make_error<StringError>("compatibility versions do not match",
138                                     inconvertibleErrorCode());
139    }
140  
141    if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
142        (getSwiftABIVersion() != O->getSwiftABIVersion())) {
143      return make_error<StringError>("swift ABI versions do not match",
144                                     inconvertibleErrorCode());
145    }
146  
147    if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
148      return make_error<StringError>("two level namespace flags do not match",
149                                     inconvertibleErrorCode());
150    }
151  
152    if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
153      return make_error<StringError>(
154          "application extension safe flags do not match",
155          inconvertibleErrorCode());
156    }
157  
158    std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
159    IF->setFileType(std::max(getFileType(), O->getFileType()));
160    IF->setPath(getPath());
161    IF->setInstallName(getInstallName());
162    IF->setCurrentVersion(getCurrentVersion());
163    IF->setCompatibilityVersion(getCompatibilityVersion());
164  
165    if (getSwiftABIVersion() == 0)
166      IF->setSwiftABIVersion(O->getSwiftABIVersion());
167    else
168      IF->setSwiftABIVersion(getSwiftABIVersion());
169  
170    IF->setTwoLevelNamespace(isTwoLevelNamespace());
171    IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
172  
173    for (const auto &It : umbrellas()) {
174      if (!It.second.empty())
175        IF->addParentUmbrella(It.first, It.second);
176    }
177    for (const auto &It : O->umbrellas()) {
178      if (!It.second.empty())
179        IF->addParentUmbrella(It.first, It.second);
180    }
181    IF->addTargets(targets());
182    IF->addTargets(O->targets());
183  
184    for (const auto &Lib : allowableClients())
185      for (const auto &Target : Lib.targets())
186        IF->addAllowableClient(Lib.getInstallName(), Target);
187  
188    for (const auto &Lib : O->allowableClients())
189      for (const auto &Target : Lib.targets())
190        IF->addAllowableClient(Lib.getInstallName(), Target);
191  
192    for (const auto &Lib : reexportedLibraries())
193      for (const auto &Target : Lib.targets())
194        IF->addReexportedLibrary(Lib.getInstallName(), Target);
195  
196    for (const auto &Lib : O->reexportedLibraries())
197      for (const auto &Target : Lib.targets())
198        IF->addReexportedLibrary(Lib.getInstallName(), Target);
199  
200    for (const auto &[Target, Path] : rpaths())
201      IF->addRPath(Path, Target);
202    for (const auto &[Target, Path] : O->rpaths())
203      IF->addRPath(Path, Target);
204  
205    for (const auto *Sym : symbols()) {
206      IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
207                    Sym->getFlags());
208    }
209  
210    for (const auto *Sym : O->symbols()) {
211      IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
212                    Sym->getFlags());
213    }
214  
215    return std::move(IF);
216  }
217  
218  Expected<std::unique_ptr<InterfaceFile>>
219  InterfaceFile::remove(Architecture Arch) const {
220    if (getArchitectures() == Arch)
221      return make_error<StringError>("cannot remove last architecture slice '" +
222                                         getArchitectureName(Arch) + "'",
223                                     inconvertibleErrorCode());
224  
225    if (!getArchitectures().has(Arch)) {
226      bool Found = false;
227      for (auto &Doc : Documents) {
228        if (Doc->getArchitectures().has(Arch)) {
229          Found = true;
230          break;
231        }
232      }
233  
234      if (!Found)
235        return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
236    }
237  
238    std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
239    IF->setFileType(getFileType());
240    IF->setPath(getPath());
241    IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
242    IF->setInstallName(getInstallName());
243    IF->setCurrentVersion(getCurrentVersion());
244    IF->setCompatibilityVersion(getCompatibilityVersion());
245    IF->setSwiftABIVersion(getSwiftABIVersion());
246    IF->setTwoLevelNamespace(isTwoLevelNamespace());
247    IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
248    for (const auto &It : umbrellas())
249      if (It.first.Arch != Arch)
250        IF->addParentUmbrella(It.first, It.second);
251  
252    for (const auto &Lib : allowableClients()) {
253      for (const auto &Target : Lib.targets())
254        if (Target.Arch != Arch)
255          IF->addAllowableClient(Lib.getInstallName(), Target);
256    }
257  
258    for (const auto &Lib : reexportedLibraries()) {
259      for (const auto &Target : Lib.targets())
260        if (Target.Arch != Arch)
261          IF->addReexportedLibrary(Lib.getInstallName(), Target);
262    }
263  
264    for (const auto *Sym : symbols()) {
265      auto Archs = Sym->getArchitectures();
266      Archs.clear(Arch);
267      if (Archs.empty())
268        continue;
269  
270      IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
271                    Sym->getFlags());
272    }
273  
274    for (auto &Doc : Documents) {
275      // Skip the inlined document if the to be removed architecture is the
276      // only one left.
277      if (Doc->getArchitectures() == Arch)
278        continue;
279  
280      // If the document doesn't contain the arch, then no work is to be done
281      // and it can be copied over.
282      if (!Doc->getArchitectures().has(Arch)) {
283        auto NewDoc = Doc;
284        IF->addDocument(std::move(NewDoc));
285        continue;
286      }
287  
288      auto Result = Doc->remove(Arch);
289      if (!Result)
290        return Result;
291  
292      IF->addDocument(std::move(Result.get()));
293    }
294  
295    return std::move(IF);
296  }
297  
298  Expected<std::unique_ptr<InterfaceFile>>
299  InterfaceFile::extract(Architecture Arch) const {
300    if (!getArchitectures().has(Arch)) {
301      return make_error<StringError>("file doesn't have architecture '" +
302                                         getArchitectureName(Arch) + "'",
303                                     inconvertibleErrorCode());
304    }
305  
306    std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
307    IF->setFileType(getFileType());
308    IF->setPath(getPath());
309    IF->addTargets(targets(Arch));
310    IF->setInstallName(getInstallName());
311    IF->setCurrentVersion(getCurrentVersion());
312    IF->setCompatibilityVersion(getCompatibilityVersion());
313    IF->setSwiftABIVersion(getSwiftABIVersion());
314    IF->setTwoLevelNamespace(isTwoLevelNamespace());
315    IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
316    for (const auto &It : umbrellas())
317      if (It.first.Arch == Arch)
318        IF->addParentUmbrella(It.first, It.second);
319  
320    for (const auto &It : rpaths())
321      if (It.first.Arch == Arch)
322        IF->addRPath(It.second, It.first);
323  
324    for (const auto &Lib : allowableClients())
325      for (const auto &Target : Lib.targets())
326        if (Target.Arch == Arch)
327          IF->addAllowableClient(Lib.getInstallName(), Target);
328  
329    for (const auto &Lib : reexportedLibraries())
330      for (const auto &Target : Lib.targets())
331        if (Target.Arch == Arch)
332          IF->addReexportedLibrary(Lib.getInstallName(), Target);
333  
334    for (const auto *Sym : symbols()) {
335      if (Sym->hasArchitecture(Arch))
336        IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
337                      Sym->getFlags());
338    }
339  
340    for (auto &Doc : Documents) {
341      // Skip documents that don't have the requested architecture.
342      if (!Doc->getArchitectures().has(Arch))
343        continue;
344  
345      auto Result = Doc->extract(Arch);
346      if (!Result)
347        return Result;
348  
349      IF->addDocument(std::move(Result.get()));
350    }
351  
352    return std::move(IF);
353  }
354  
355  void InterfaceFile::setFromBinaryAttrs(const RecordsSlice::BinaryAttrs &BA,
356                                         const Target &Targ) {
357    if (getFileType() != BA.File)
358      setFileType(BA.File);
359    if (getInstallName().empty())
360      setInstallName(BA.InstallName);
361    if (BA.AppExtensionSafe && !isApplicationExtensionSafe())
362      setApplicationExtensionSafe();
363    if (BA.TwoLevelNamespace && !isTwoLevelNamespace())
364      setTwoLevelNamespace();
365    if (BA.OSLibNotForSharedCache && !isOSLibNotForSharedCache())
366      setOSLibNotForSharedCache();
367    if (getCurrentVersion().empty())
368      setCurrentVersion(BA.CurrentVersion);
369    if (getCompatibilityVersion().empty())
370      setCompatibilityVersion(BA.CompatVersion);
371    if (getSwiftABIVersion() == 0)
372      setSwiftABIVersion(BA.SwiftABI);
373    if (getPath().empty())
374      setPath(BA.Path);
375    if (!BA.ParentUmbrella.empty())
376      addParentUmbrella(Targ, BA.ParentUmbrella);
377    for (const auto &Client : BA.AllowableClients)
378      addAllowableClient(Client, Targ);
379    for (const auto &Lib : BA.RexportedLibraries)
380      addReexportedLibrary(Lib, Targ);
381  }
382  
383  static bool isYAMLTextStub(const FileType &Kind) {
384    return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
385  }
386  
387  bool InterfaceFile::operator==(const InterfaceFile &O) const {
388    if (Targets != O.Targets)
389      return false;
390    if (InstallName != O.InstallName)
391      return false;
392    if ((CurrentVersion != O.CurrentVersion) ||
393        (CompatibilityVersion != O.CompatibilityVersion))
394      return false;
395    if (SwiftABIVersion != O.SwiftABIVersion)
396      return false;
397    if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
398      return false;
399    if (IsAppExtensionSafe != O.IsAppExtensionSafe)
400      return false;
401    if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)
402      return false;
403    if (HasSimSupport != O.HasSimSupport)
404      return false;
405    if (ParentUmbrellas != O.ParentUmbrellas)
406      return false;
407    if (AllowableClients != O.AllowableClients)
408      return false;
409    if (ReexportedLibraries != O.ReexportedLibraries)
410      return false;
411    if (*SymbolsSet != *O.SymbolsSet)
412      return false;
413    // Don't compare run search paths for older filetypes that cannot express
414    // them.
415    if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
416      if (RPaths != O.RPaths)
417        return false;
418      if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
419        return false;
420    }
421  
422    if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
423                    O.Documents.end(),
424                    [](const std::shared_ptr<InterfaceFile> LHS,
425                       const std::shared_ptr<InterfaceFile> RHS) {
426                      return *LHS == *RHS;
427                    }))
428      return false;
429    return true;
430  }
431