1b1c73532SDimitry Andric //===- RecordsSlice.cpp --------------------------------------------------===//
2b1c73532SDimitry Andric //
3b1c73532SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b1c73532SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b1c73532SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b1c73532SDimitry Andric //
7b1c73532SDimitry Andric //===----------------------------------------------------------------------===//
8b1c73532SDimitry Andric //
9b1c73532SDimitry Andric // Implements the Records Slice APIs.
10b1c73532SDimitry Andric //
11b1c73532SDimitry Andric //===----------------------------------------------------------------------===//
12b1c73532SDimitry Andric
13b1c73532SDimitry Andric #include "llvm/TextAPI/RecordsSlice.h"
1499aabd70SDimitry Andric #include "llvm/ADT/SetVector.h"
15ac9a064cSDimitry Andric #include "llvm/TextAPI/InterfaceFile.h"
16b1c73532SDimitry Andric #include "llvm/TextAPI/Record.h"
17b1c73532SDimitry Andric #include "llvm/TextAPI/Symbol.h"
18b1c73532SDimitry Andric #include <utility>
19b1c73532SDimitry Andric
20b1c73532SDimitry Andric using namespace llvm;
21b1c73532SDimitry Andric using namespace llvm::MachO;
22b1c73532SDimitry Andric
addRecord(StringRef Name,SymbolFlags Flags,GlobalRecord::Kind GV,RecordLinkage Linkage)23b1c73532SDimitry Andric Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
24b1c73532SDimitry Andric GlobalRecord::Kind GV, RecordLinkage Linkage) {
25b1c73532SDimitry Andric // Find a specific Record type to capture.
26ac9a064cSDimitry Andric auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);
27b1c73532SDimitry Andric Name = APIName;
28b1c73532SDimitry Andric switch (SymKind) {
29ac9a064cSDimitry Andric case EncodeKind::GlobalSymbol:
30b1c73532SDimitry Andric return addGlobal(Name, Linkage, GV, Flags);
31ac9a064cSDimitry Andric case EncodeKind::ObjectiveCClass:
32ac9a064cSDimitry Andric return addObjCInterface(Name, Linkage, InterfaceType);
33ac9a064cSDimitry Andric case EncodeKind::ObjectiveCClassEHType: {
34ac9a064cSDimitry Andric ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType);
35ac9a064cSDimitry Andric // When classes without ehtype are used in try/catch blocks
36ac9a064cSDimitry Andric // a weak-defined symbol is exported.
37ac9a064cSDimitry Andric if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
38ac9a064cSDimitry Andric updateFlags(Rec, SymbolFlags::WeakDefined);
39ac9a064cSDimitry Andric return Rec;
40ac9a064cSDimitry Andric }
41ac9a064cSDimitry Andric case EncodeKind::ObjectiveCInstanceVariable: {
42b1c73532SDimitry Andric auto [Super, IVar] = Name.split('.');
43b1c73532SDimitry Andric // Attempt to find super class.
44b1c73532SDimitry Andric ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
45b1c73532SDimitry Andric // If not found, create extension since there is no mapped class symbol.
46b1c73532SDimitry Andric if (Container == nullptr)
47b1c73532SDimitry Andric Container = addObjCCategory(Super, {});
48b1c73532SDimitry Andric return addObjCIVar(Container, IVar, Linkage);
49b1c73532SDimitry Andric }
50b1c73532SDimitry Andric }
51b1c73532SDimitry Andric
52b1c73532SDimitry Andric llvm_unreachable("unexpected symbol kind when adding to Record Slice");
53b1c73532SDimitry Andric }
54b1c73532SDimitry Andric
findContainer(bool IsIVar,StringRef Name) const55b1c73532SDimitry Andric ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
56b1c73532SDimitry Andric StringRef Name) const {
57b1c73532SDimitry Andric StringRef Super = IsIVar ? Name.split('.').first : Name;
58b1c73532SDimitry Andric ObjCContainerRecord *Container = findObjCInterface(Super);
59b1c73532SDimitry Andric // Ivars can only exist with extensions, if they did not come from
60b1c73532SDimitry Andric // class.
61b1c73532SDimitry Andric if (Container == nullptr)
62b1c73532SDimitry Andric Container = findObjCCategory(Super, "");
63b1c73532SDimitry Andric return Container;
64b1c73532SDimitry Andric }
65b1c73532SDimitry Andric
66b1c73532SDimitry Andric template <typename R, typename C = RecordMap<R>, typename K = StringRef>
findRecord(K Key,const C & Container)67b1c73532SDimitry Andric R *findRecord(K Key, const C &Container) {
68b1c73532SDimitry Andric const auto *Record = Container.find(Key);
69b1c73532SDimitry Andric if (Record == Container.end())
70b1c73532SDimitry Andric return nullptr;
71b1c73532SDimitry Andric return Record->second.get();
72b1c73532SDimitry Andric }
73b1c73532SDimitry Andric
findGlobal(StringRef Name,GlobalRecord::Kind GV) const74b1c73532SDimitry Andric GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
75b1c73532SDimitry Andric GlobalRecord::Kind GV) const {
76b1c73532SDimitry Andric auto *Record = findRecord<GlobalRecord>(Name, Globals);
77b1c73532SDimitry Andric if (!Record)
78b1c73532SDimitry Andric return nullptr;
79b1c73532SDimitry Andric
80b1c73532SDimitry Andric switch (GV) {
81b1c73532SDimitry Andric case GlobalRecord::Kind::Variable: {
82b1c73532SDimitry Andric if (!Record->isVariable())
83b1c73532SDimitry Andric return nullptr;
84b1c73532SDimitry Andric break;
85b1c73532SDimitry Andric }
86b1c73532SDimitry Andric case GlobalRecord::Kind::Function: {
87b1c73532SDimitry Andric if (!Record->isFunction())
88b1c73532SDimitry Andric return nullptr;
89b1c73532SDimitry Andric break;
90b1c73532SDimitry Andric }
91b1c73532SDimitry Andric case GlobalRecord::Kind::Unknown:
92b1c73532SDimitry Andric return Record;
93b1c73532SDimitry Andric }
94b1c73532SDimitry Andric
95b1c73532SDimitry Andric return Record;
96b1c73532SDimitry Andric }
97b1c73532SDimitry Andric
98ac9a064cSDimitry Andric RecordLinkage
getLinkageForSymbol(ObjCIFSymbolKind CurrType) const99ac9a064cSDimitry Andric ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const {
100ac9a064cSDimitry Andric assert(CurrType <= ObjCIFSymbolKind::EHType &&
101ac9a064cSDimitry Andric "expected single ObjCIFSymbolKind enum value");
102ac9a064cSDimitry Andric if (CurrType == ObjCIFSymbolKind::Class)
103ac9a064cSDimitry Andric return Linkages.Class;
104ac9a064cSDimitry Andric
105ac9a064cSDimitry Andric if (CurrType == ObjCIFSymbolKind::MetaClass)
106ac9a064cSDimitry Andric return Linkages.MetaClass;
107ac9a064cSDimitry Andric
108ac9a064cSDimitry Andric if (CurrType == ObjCIFSymbolKind::EHType)
109ac9a064cSDimitry Andric return Linkages.EHType;
110ac9a064cSDimitry Andric
111ac9a064cSDimitry Andric llvm_unreachable("unexpected ObjCIFSymbolKind");
112ac9a064cSDimitry Andric }
113ac9a064cSDimitry Andric
updateLinkageForSymbols(ObjCIFSymbolKind SymType,RecordLinkage Link)114ac9a064cSDimitry Andric void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType,
115ac9a064cSDimitry Andric RecordLinkage Link) {
116ac9a064cSDimitry Andric if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class)
117ac9a064cSDimitry Andric Linkages.Class = std::max(Link, Linkages.Class);
118ac9a064cSDimitry Andric if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass)
119ac9a064cSDimitry Andric Linkages.MetaClass = std::max(Link, Linkages.MetaClass);
120ac9a064cSDimitry Andric if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType)
121ac9a064cSDimitry Andric Linkages.EHType = std::max(Link, Linkages.EHType);
122ac9a064cSDimitry Andric
123ac9a064cSDimitry Andric // Obj-C Classes represent multiple symbols that could have competing
124ac9a064cSDimitry Andric // linkages, in this case assign the largest one, when querying the linkage of
125ac9a064cSDimitry Andric // the record itself. This allows visitors pick whether they want to account
126ac9a064cSDimitry Andric // for complete symbol information.
127ac9a064cSDimitry Andric Linkage =
128ac9a064cSDimitry Andric std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType));
129ac9a064cSDimitry Andric }
130ac9a064cSDimitry Andric
findObjCInterface(StringRef Name) const131b1c73532SDimitry Andric ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
132b1c73532SDimitry Andric return findRecord<ObjCInterfaceRecord>(Name, Classes);
133b1c73532SDimitry Andric }
134b1c73532SDimitry Andric
findObjCCategory(StringRef ClassToExtend,StringRef Category) const135b1c73532SDimitry Andric ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
136b1c73532SDimitry Andric StringRef Category) const {
137b1c73532SDimitry Andric return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
138b1c73532SDimitry Andric Categories);
139b1c73532SDimitry Andric }
140b1c73532SDimitry Andric
findObjCIVar(StringRef IVar) const141b1c73532SDimitry Andric ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
142b1c73532SDimitry Andric return findRecord<ObjCIVarRecord>(IVar, IVars);
143b1c73532SDimitry Andric }
144b1c73532SDimitry Andric
findObjCIVar(bool IsScopedName,StringRef Name) const145b1c73532SDimitry Andric ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
146b1c73532SDimitry Andric StringRef Name) const {
147b1c73532SDimitry Andric // If scoped name, the name of the container is known.
148b1c73532SDimitry Andric if (IsScopedName) {
149b1c73532SDimitry Andric // IVar does not exist if there is not a container assigned to it.
150b1c73532SDimitry Andric auto *Container = findContainer(/*IsIVar=*/true, Name);
151b1c73532SDimitry Andric if (!Container)
152b1c73532SDimitry Andric return nullptr;
153b1c73532SDimitry Andric
154b1c73532SDimitry Andric StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
155b1c73532SDimitry Andric return Container->findObjCIVar(IVar);
156b1c73532SDimitry Andric }
157b1c73532SDimitry Andric
158b1c73532SDimitry Andric // Otherwise traverse through containers and attempt to find IVar.
159b1c73532SDimitry Andric auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
160b1c73532SDimitry Andric for (const auto &[_, Container] : Records) {
161b1c73532SDimitry Andric if (auto *IVarR = Container->findObjCIVar(Name))
162b1c73532SDimitry Andric return IVarR;
163b1c73532SDimitry Andric }
164b1c73532SDimitry Andric return nullptr;
165b1c73532SDimitry Andric };
166b1c73532SDimitry Andric
167b1c73532SDimitry Andric if (auto *IVarRecord = getIVar(Classes))
168b1c73532SDimitry Andric return IVarRecord;
169b1c73532SDimitry Andric
170b1c73532SDimitry Andric return getIVar(Categories);
171b1c73532SDimitry Andric }
172b1c73532SDimitry Andric
addGlobal(StringRef Name,RecordLinkage Linkage,GlobalRecord::Kind GV,SymbolFlags Flags,bool Inlined)173b1c73532SDimitry Andric GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
174ac9a064cSDimitry Andric GlobalRecord::Kind GV, SymbolFlags Flags,
175ac9a064cSDimitry Andric bool Inlined) {
176b1c73532SDimitry Andric if (GV == GlobalRecord::Kind::Function)
177b1c73532SDimitry Andric Flags |= SymbolFlags::Text;
178b1c73532SDimitry Andric else if (GV == GlobalRecord::Kind::Variable)
179b1c73532SDimitry Andric Flags |= SymbolFlags::Data;
180b1c73532SDimitry Andric
181b1c73532SDimitry Andric Name = copyString(Name);
182b1c73532SDimitry Andric auto Result = Globals.insert({Name, nullptr});
183b1c73532SDimitry Andric if (Result.second)
184b1c73532SDimitry Andric Result.first->second =
185ac9a064cSDimitry Andric std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV, Inlined);
18699aabd70SDimitry Andric else {
187b1c73532SDimitry Andric updateLinkage(Result.first->second.get(), Linkage);
18899aabd70SDimitry Andric updateFlags(Result.first->second.get(), Flags);
18999aabd70SDimitry Andric }
190b1c73532SDimitry Andric return Result.first->second.get();
191b1c73532SDimitry Andric }
192b1c73532SDimitry Andric
addObjCInterface(StringRef Name,RecordLinkage Linkage,ObjCIFSymbolKind SymType)193b1c73532SDimitry Andric ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
194b1c73532SDimitry Andric RecordLinkage Linkage,
195ac9a064cSDimitry Andric ObjCIFSymbolKind SymType) {
196b1c73532SDimitry Andric Name = copyString(Name);
197b1c73532SDimitry Andric auto Result = Classes.insert({Name, nullptr});
198ac9a064cSDimitry Andric if (Result.second)
199b1c73532SDimitry Andric Result.first->second =
200ac9a064cSDimitry Andric std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType);
201ac9a064cSDimitry Andric else
202ac9a064cSDimitry Andric Result.first->second->updateLinkageForSymbols(SymType, Linkage);
203b1c73532SDimitry Andric return Result.first->second.get();
204b1c73532SDimitry Andric }
205ac9a064cSDimitry Andric
mergeFlags(SymbolFlags Flags,RecordLinkage Linkage)20699aabd70SDimitry Andric SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
20799aabd70SDimitry Andric // Add Linkage properties into Flags.
20899aabd70SDimitry Andric switch (Linkage) {
20999aabd70SDimitry Andric case RecordLinkage::Rexported:
21099aabd70SDimitry Andric Flags |= SymbolFlags::Rexported;
21199aabd70SDimitry Andric return Flags;
21299aabd70SDimitry Andric case RecordLinkage::Undefined:
21399aabd70SDimitry Andric Flags |= SymbolFlags::Undefined;
21499aabd70SDimitry Andric return Flags;
21599aabd70SDimitry Andric default:
21699aabd70SDimitry Andric return Flags;
21799aabd70SDimitry Andric }
21899aabd70SDimitry Andric }
219b1c73532SDimitry Andric
addObjCCategory(ObjCCategoryRecord * Record)220b1c73532SDimitry Andric bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
221b1c73532SDimitry Andric auto Result = Categories.insert({Name, Record});
222b1c73532SDimitry Andric return Result.second;
223b1c73532SDimitry Andric }
224b1c73532SDimitry Andric
addObjCCategory(StringRef ClassToExtend,StringRef Category)225b1c73532SDimitry Andric ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
226b1c73532SDimitry Andric StringRef Category) {
227b1c73532SDimitry Andric Category = copyString(Category);
228ac9a064cSDimitry Andric ClassToExtend = copyString(ClassToExtend);
229b1c73532SDimitry Andric
230b1c73532SDimitry Andric // Add owning record first into record slice.
231b1c73532SDimitry Andric auto Result =
232b1c73532SDimitry Andric Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
233b1c73532SDimitry Andric if (Result.second)
234b1c73532SDimitry Andric Result.first->second =
235b1c73532SDimitry Andric std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
236b1c73532SDimitry Andric
237b1c73532SDimitry Andric // Then add reference to it in in the class.
238b1c73532SDimitry Andric if (auto *ObjCClass = findObjCInterface(ClassToExtend))
239b1c73532SDimitry Andric ObjCClass->addObjCCategory(Result.first->second.get());
240b1c73532SDimitry Andric
241b1c73532SDimitry Andric return Result.first->second.get();
242b1c73532SDimitry Andric }
243b1c73532SDimitry Andric
getObjCIVars() const24499aabd70SDimitry Andric std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
24599aabd70SDimitry Andric std::vector<ObjCIVarRecord *> Records;
24699aabd70SDimitry Andric llvm::for_each(IVars,
24799aabd70SDimitry Andric [&](auto &Record) { Records.push_back(Record.second.get()); });
24899aabd70SDimitry Andric return Records;
24999aabd70SDimitry Andric }
25099aabd70SDimitry Andric
25199aabd70SDimitry Andric std::vector<ObjCCategoryRecord *>
getObjCCategories() const25299aabd70SDimitry Andric ObjCInterfaceRecord::getObjCCategories() const {
25399aabd70SDimitry Andric std::vector<ObjCCategoryRecord *> Records;
25499aabd70SDimitry Andric llvm::for_each(Categories,
25599aabd70SDimitry Andric [&](auto &Record) { Records.push_back(Record.second); });
25699aabd70SDimitry Andric return Records;
25799aabd70SDimitry Andric }
25899aabd70SDimitry Andric
addObjCIVar(StringRef IVar,RecordLinkage Linkage)259b1c73532SDimitry Andric ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
260b1c73532SDimitry Andric RecordLinkage Linkage) {
261b1c73532SDimitry Andric auto Result = IVars.insert({IVar, nullptr});
262b1c73532SDimitry Andric if (Result.second)
26399aabd70SDimitry Andric Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
264b1c73532SDimitry Andric return Result.first->second.get();
265b1c73532SDimitry Andric }
266b1c73532SDimitry Andric
addObjCIVar(ObjCContainerRecord * Container,StringRef Name,RecordLinkage Linkage)267b1c73532SDimitry Andric ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
268b1c73532SDimitry Andric StringRef Name,
269b1c73532SDimitry Andric RecordLinkage Linkage) {
270b1c73532SDimitry Andric Name = copyString(Name);
271b1c73532SDimitry Andric ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
272b1c73532SDimitry Andric updateLinkage(Record, Linkage);
273b1c73532SDimitry Andric return Record;
274b1c73532SDimitry Andric }
275b1c73532SDimitry Andric
copyString(StringRef String)276b1c73532SDimitry Andric StringRef RecordsSlice::copyString(StringRef String) {
277b1c73532SDimitry Andric if (String.empty())
278b1c73532SDimitry Andric return {};
279b1c73532SDimitry Andric
280b1c73532SDimitry Andric if (StringAllocator.identifyObject(String.data()))
281b1c73532SDimitry Andric return String;
282b1c73532SDimitry Andric
283b1c73532SDimitry Andric void *Ptr = StringAllocator.Allocate(String.size(), 1);
284b1c73532SDimitry Andric memcpy(Ptr, String.data(), String.size());
285b1c73532SDimitry Andric return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
286b1c73532SDimitry Andric }
287b1c73532SDimitry Andric
getBinaryAttrs()288b1c73532SDimitry Andric RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
289b1c73532SDimitry Andric if (!hasBinaryAttrs())
290b1c73532SDimitry Andric BA = std::make_unique<BinaryAttrs>();
291b1c73532SDimitry Andric return *BA;
292b1c73532SDimitry Andric }
29399aabd70SDimitry Andric
visit(RecordVisitor & V) const29499aabd70SDimitry Andric void RecordsSlice::visit(RecordVisitor &V) const {
29599aabd70SDimitry Andric for (auto &G : Globals)
29699aabd70SDimitry Andric V.visitGlobal(*G.second);
29799aabd70SDimitry Andric for (auto &C : Classes)
29899aabd70SDimitry Andric V.visitObjCInterface(*C.second);
29999aabd70SDimitry Andric for (auto &Cat : Categories)
30099aabd70SDimitry Andric V.visitObjCCategory(*Cat.second);
30199aabd70SDimitry Andric }
30299aabd70SDimitry Andric
30399aabd70SDimitry Andric static std::unique_ptr<InterfaceFile>
createInterfaceFile(const Records & Slices,StringRef InstallName)30499aabd70SDimitry Andric createInterfaceFile(const Records &Slices, StringRef InstallName) {
30599aabd70SDimitry Andric // Pickup symbols first.
30699aabd70SDimitry Andric auto Symbols = std::make_unique<SymbolSet>();
30799aabd70SDimitry Andric for (auto &S : Slices) {
30899aabd70SDimitry Andric if (S->empty())
30999aabd70SDimitry Andric continue;
31099aabd70SDimitry Andric auto &BA = S->getBinaryAttrs();
31199aabd70SDimitry Andric if (BA.InstallName != InstallName)
31299aabd70SDimitry Andric continue;
31399aabd70SDimitry Andric
31499aabd70SDimitry Andric SymbolConverter Converter(Symbols.get(), S->getTarget(),
31599aabd70SDimitry Andric !BA.TwoLevelNamespace);
31699aabd70SDimitry Andric S->visit(Converter);
31799aabd70SDimitry Andric }
31899aabd70SDimitry Andric
31999aabd70SDimitry Andric auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
32099aabd70SDimitry Andric File->setInstallName(InstallName);
32199aabd70SDimitry Andric // Assign other attributes.
32299aabd70SDimitry Andric for (auto &S : Slices) {
32399aabd70SDimitry Andric if (S->empty())
32499aabd70SDimitry Andric continue;
32599aabd70SDimitry Andric auto &BA = S->getBinaryAttrs();
32699aabd70SDimitry Andric if (BA.InstallName != InstallName)
32799aabd70SDimitry Andric continue;
32899aabd70SDimitry Andric const Target &Targ = S->getTarget();
32999aabd70SDimitry Andric File->addTarget(Targ);
330ac9a064cSDimitry Andric File->setFromBinaryAttrs(BA, Targ);
33199aabd70SDimitry Andric }
33299aabd70SDimitry Andric
33399aabd70SDimitry Andric return File;
33499aabd70SDimitry Andric }
33599aabd70SDimitry Andric
33699aabd70SDimitry Andric std::unique_ptr<InterfaceFile>
convertToInterfaceFile(const Records & Slices)33799aabd70SDimitry Andric llvm::MachO::convertToInterfaceFile(const Records &Slices) {
33899aabd70SDimitry Andric std::unique_ptr<InterfaceFile> File;
33999aabd70SDimitry Andric if (Slices.empty())
34099aabd70SDimitry Andric return File;
34199aabd70SDimitry Andric
34299aabd70SDimitry Andric SetVector<StringRef> InstallNames;
34399aabd70SDimitry Andric for (auto &S : Slices) {
34499aabd70SDimitry Andric auto Name = S->getBinaryAttrs().InstallName;
34599aabd70SDimitry Andric if (Name.empty())
34699aabd70SDimitry Andric continue;
34799aabd70SDimitry Andric InstallNames.insert(Name);
34899aabd70SDimitry Andric }
34999aabd70SDimitry Andric
35099aabd70SDimitry Andric File = createInterfaceFile(Slices, *InstallNames.begin());
3514df029ccSDimitry Andric for (StringRef IN : llvm::drop_begin(InstallNames))
3524df029ccSDimitry Andric File->addDocument(createInterfaceFile(Slices, IN));
35399aabd70SDimitry Andric
35499aabd70SDimitry Andric return File;
35599aabd70SDimitry Andric }
356