xref: /freebsd-src/contrib/llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===- RecordsSlice.cpp --------------------------------------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric //
95f757f3fSDimitry Andric // Implements the Records Slice APIs.
105f757f3fSDimitry Andric //
115f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
125f757f3fSDimitry Andric 
135f757f3fSDimitry Andric #include "llvm/TextAPI/RecordsSlice.h"
14cb14a3feSDimitry Andric #include "llvm/ADT/SetVector.h"
15*0fca6ea1SDimitry Andric #include "llvm/TextAPI/InterfaceFile.h"
165f757f3fSDimitry Andric #include "llvm/TextAPI/Record.h"
175f757f3fSDimitry Andric #include "llvm/TextAPI/Symbol.h"
185f757f3fSDimitry Andric #include <utility>
195f757f3fSDimitry Andric 
205f757f3fSDimitry Andric using namespace llvm;
215f757f3fSDimitry Andric using namespace llvm::MachO;
225f757f3fSDimitry Andric 
235f757f3fSDimitry Andric Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
245f757f3fSDimitry Andric                                 GlobalRecord::Kind GV, RecordLinkage Linkage) {
255f757f3fSDimitry Andric   // Find a specific Record type to capture.
26*0fca6ea1SDimitry Andric   auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);
275f757f3fSDimitry Andric   Name = APIName;
285f757f3fSDimitry Andric   switch (SymKind) {
29*0fca6ea1SDimitry Andric   case EncodeKind::GlobalSymbol:
305f757f3fSDimitry Andric     return addGlobal(Name, Linkage, GV, Flags);
31*0fca6ea1SDimitry Andric   case EncodeKind::ObjectiveCClass:
32*0fca6ea1SDimitry Andric     return addObjCInterface(Name, Linkage, InterfaceType);
33*0fca6ea1SDimitry Andric   case EncodeKind::ObjectiveCClassEHType: {
34*0fca6ea1SDimitry Andric     ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType);
35*0fca6ea1SDimitry Andric     // When classes without ehtype are used in try/catch blocks
36*0fca6ea1SDimitry Andric     // a weak-defined symbol is exported.
37*0fca6ea1SDimitry Andric     if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
38*0fca6ea1SDimitry Andric       updateFlags(Rec, SymbolFlags::WeakDefined);
39*0fca6ea1SDimitry Andric     return Rec;
40*0fca6ea1SDimitry Andric   }
41*0fca6ea1SDimitry Andric   case EncodeKind::ObjectiveCInstanceVariable: {
425f757f3fSDimitry Andric     auto [Super, IVar] = Name.split('.');
435f757f3fSDimitry Andric     // Attempt to find super class.
445f757f3fSDimitry Andric     ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
455f757f3fSDimitry Andric     // If not found, create extension since there is no mapped class symbol.
465f757f3fSDimitry Andric     if (Container == nullptr)
475f757f3fSDimitry Andric       Container = addObjCCategory(Super, {});
485f757f3fSDimitry Andric     return addObjCIVar(Container, IVar, Linkage);
495f757f3fSDimitry Andric   }
505f757f3fSDimitry Andric   }
515f757f3fSDimitry Andric 
525f757f3fSDimitry Andric   llvm_unreachable("unexpected symbol kind when adding to Record Slice");
535f757f3fSDimitry Andric }
545f757f3fSDimitry Andric 
555f757f3fSDimitry Andric ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
565f757f3fSDimitry Andric                                                  StringRef Name) const {
575f757f3fSDimitry Andric   StringRef Super = IsIVar ? Name.split('.').first : Name;
585f757f3fSDimitry Andric   ObjCContainerRecord *Container = findObjCInterface(Super);
595f757f3fSDimitry Andric   // Ivars can only exist with extensions, if they did not come from
605f757f3fSDimitry Andric   // class.
615f757f3fSDimitry Andric   if (Container == nullptr)
625f757f3fSDimitry Andric     Container = findObjCCategory(Super, "");
635f757f3fSDimitry Andric   return Container;
645f757f3fSDimitry Andric }
655f757f3fSDimitry Andric 
665f757f3fSDimitry Andric template <typename R, typename C = RecordMap<R>, typename K = StringRef>
675f757f3fSDimitry Andric R *findRecord(K Key, const C &Container) {
685f757f3fSDimitry Andric   const auto *Record = Container.find(Key);
695f757f3fSDimitry Andric   if (Record == Container.end())
705f757f3fSDimitry Andric     return nullptr;
715f757f3fSDimitry Andric   return Record->second.get();
725f757f3fSDimitry Andric }
735f757f3fSDimitry Andric 
745f757f3fSDimitry Andric GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
755f757f3fSDimitry Andric                                        GlobalRecord::Kind GV) const {
765f757f3fSDimitry Andric   auto *Record = findRecord<GlobalRecord>(Name, Globals);
775f757f3fSDimitry Andric   if (!Record)
785f757f3fSDimitry Andric     return nullptr;
795f757f3fSDimitry Andric 
805f757f3fSDimitry Andric   switch (GV) {
815f757f3fSDimitry Andric   case GlobalRecord::Kind::Variable: {
825f757f3fSDimitry Andric     if (!Record->isVariable())
835f757f3fSDimitry Andric       return nullptr;
845f757f3fSDimitry Andric     break;
855f757f3fSDimitry Andric   }
865f757f3fSDimitry Andric   case GlobalRecord::Kind::Function: {
875f757f3fSDimitry Andric     if (!Record->isFunction())
885f757f3fSDimitry Andric       return nullptr;
895f757f3fSDimitry Andric     break;
905f757f3fSDimitry Andric   }
915f757f3fSDimitry Andric   case GlobalRecord::Kind::Unknown:
925f757f3fSDimitry Andric     return Record;
935f757f3fSDimitry Andric   }
945f757f3fSDimitry Andric 
955f757f3fSDimitry Andric   return Record;
965f757f3fSDimitry Andric }
975f757f3fSDimitry Andric 
98*0fca6ea1SDimitry Andric RecordLinkage
99*0fca6ea1SDimitry Andric ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const {
100*0fca6ea1SDimitry Andric   assert(CurrType <= ObjCIFSymbolKind::EHType &&
101*0fca6ea1SDimitry Andric          "expected single ObjCIFSymbolKind enum value");
102*0fca6ea1SDimitry Andric   if (CurrType == ObjCIFSymbolKind::Class)
103*0fca6ea1SDimitry Andric     return Linkages.Class;
104*0fca6ea1SDimitry Andric 
105*0fca6ea1SDimitry Andric   if (CurrType == ObjCIFSymbolKind::MetaClass)
106*0fca6ea1SDimitry Andric     return Linkages.MetaClass;
107*0fca6ea1SDimitry Andric 
108*0fca6ea1SDimitry Andric   if (CurrType == ObjCIFSymbolKind::EHType)
109*0fca6ea1SDimitry Andric     return Linkages.EHType;
110*0fca6ea1SDimitry Andric 
111*0fca6ea1SDimitry Andric   llvm_unreachable("unexpected ObjCIFSymbolKind");
112*0fca6ea1SDimitry Andric }
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType,
115*0fca6ea1SDimitry Andric                                                   RecordLinkage Link) {
116*0fca6ea1SDimitry Andric   if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class)
117*0fca6ea1SDimitry Andric     Linkages.Class = std::max(Link, Linkages.Class);
118*0fca6ea1SDimitry Andric   if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass)
119*0fca6ea1SDimitry Andric     Linkages.MetaClass = std::max(Link, Linkages.MetaClass);
120*0fca6ea1SDimitry Andric   if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType)
121*0fca6ea1SDimitry Andric     Linkages.EHType = std::max(Link, Linkages.EHType);
122*0fca6ea1SDimitry Andric 
123*0fca6ea1SDimitry Andric   // Obj-C Classes represent multiple symbols that could have competing
124*0fca6ea1SDimitry Andric   // linkages, in this case assign the largest one, when querying the linkage of
125*0fca6ea1SDimitry Andric   // the record itself. This allows visitors pick whether they want to account
126*0fca6ea1SDimitry Andric   // for complete symbol information.
127*0fca6ea1SDimitry Andric   Linkage =
128*0fca6ea1SDimitry Andric       std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType));
129*0fca6ea1SDimitry Andric }
130*0fca6ea1SDimitry Andric 
1315f757f3fSDimitry Andric ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
1325f757f3fSDimitry Andric   return findRecord<ObjCInterfaceRecord>(Name, Classes);
1335f757f3fSDimitry Andric }
1345f757f3fSDimitry Andric 
1355f757f3fSDimitry Andric ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
1365f757f3fSDimitry Andric                                                    StringRef Category) const {
1375f757f3fSDimitry Andric   return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
1385f757f3fSDimitry Andric                                         Categories);
1395f757f3fSDimitry Andric }
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
1425f757f3fSDimitry Andric   return findRecord<ObjCIVarRecord>(IVar, IVars);
1435f757f3fSDimitry Andric }
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
1465f757f3fSDimitry Andric                                            StringRef Name) const {
1475f757f3fSDimitry Andric   // If scoped name, the name of the container is known.
1485f757f3fSDimitry Andric   if (IsScopedName) {
1495f757f3fSDimitry Andric     // IVar does not exist if there is not a container assigned to it.
1505f757f3fSDimitry Andric     auto *Container = findContainer(/*IsIVar=*/true, Name);
1515f757f3fSDimitry Andric     if (!Container)
1525f757f3fSDimitry Andric       return nullptr;
1535f757f3fSDimitry Andric 
1545f757f3fSDimitry Andric     StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
1555f757f3fSDimitry Andric     return Container->findObjCIVar(IVar);
1565f757f3fSDimitry Andric   }
1575f757f3fSDimitry Andric 
1585f757f3fSDimitry Andric   // Otherwise traverse through containers and attempt to find IVar.
1595f757f3fSDimitry Andric   auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
1605f757f3fSDimitry Andric     for (const auto &[_, Container] : Records) {
1615f757f3fSDimitry Andric       if (auto *IVarR = Container->findObjCIVar(Name))
1625f757f3fSDimitry Andric         return IVarR;
1635f757f3fSDimitry Andric     }
1645f757f3fSDimitry Andric     return nullptr;
1655f757f3fSDimitry Andric   };
1665f757f3fSDimitry Andric 
1675f757f3fSDimitry Andric   if (auto *IVarRecord = getIVar(Classes))
1685f757f3fSDimitry Andric     return IVarRecord;
1695f757f3fSDimitry Andric 
1705f757f3fSDimitry Andric   return getIVar(Categories);
1715f757f3fSDimitry Andric }
1725f757f3fSDimitry Andric 
1735f757f3fSDimitry Andric GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
174*0fca6ea1SDimitry Andric                                       GlobalRecord::Kind GV, SymbolFlags Flags,
175*0fca6ea1SDimitry Andric                                       bool Inlined) {
1765f757f3fSDimitry Andric   if (GV == GlobalRecord::Kind::Function)
1775f757f3fSDimitry Andric     Flags |= SymbolFlags::Text;
1785f757f3fSDimitry Andric   else if (GV == GlobalRecord::Kind::Variable)
1795f757f3fSDimitry Andric     Flags |= SymbolFlags::Data;
1805f757f3fSDimitry Andric 
1815f757f3fSDimitry Andric   Name = copyString(Name);
1825f757f3fSDimitry Andric   auto Result = Globals.insert({Name, nullptr});
1835f757f3fSDimitry Andric   if (Result.second)
1845f757f3fSDimitry Andric     Result.first->second =
185*0fca6ea1SDimitry Andric         std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV, Inlined);
186cb14a3feSDimitry Andric   else {
1875f757f3fSDimitry Andric     updateLinkage(Result.first->second.get(), Linkage);
188cb14a3feSDimitry Andric     updateFlags(Result.first->second.get(), Flags);
189cb14a3feSDimitry Andric   }
1905f757f3fSDimitry Andric   return Result.first->second.get();
1915f757f3fSDimitry Andric }
1925f757f3fSDimitry Andric 
1935f757f3fSDimitry Andric ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
1945f757f3fSDimitry Andric                                                     RecordLinkage Linkage,
195*0fca6ea1SDimitry Andric                                                     ObjCIFSymbolKind SymType) {
1965f757f3fSDimitry Andric   Name = copyString(Name);
1975f757f3fSDimitry Andric   auto Result = Classes.insert({Name, nullptr});
198*0fca6ea1SDimitry Andric   if (Result.second)
1995f757f3fSDimitry Andric     Result.first->second =
200*0fca6ea1SDimitry Andric         std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType);
201*0fca6ea1SDimitry Andric   else
202*0fca6ea1SDimitry Andric     Result.first->second->updateLinkageForSymbols(SymType, Linkage);
2035f757f3fSDimitry Andric   return Result.first->second.get();
2045f757f3fSDimitry Andric }
205*0fca6ea1SDimitry Andric 
206cb14a3feSDimitry Andric SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
207cb14a3feSDimitry Andric   // Add Linkage properties into Flags.
208cb14a3feSDimitry Andric   switch (Linkage) {
209cb14a3feSDimitry Andric   case RecordLinkage::Rexported:
210cb14a3feSDimitry Andric     Flags |= SymbolFlags::Rexported;
211cb14a3feSDimitry Andric     return Flags;
212cb14a3feSDimitry Andric   case RecordLinkage::Undefined:
213cb14a3feSDimitry Andric     Flags |= SymbolFlags::Undefined;
214cb14a3feSDimitry Andric     return Flags;
215cb14a3feSDimitry Andric   default:
216cb14a3feSDimitry Andric     return Flags;
217cb14a3feSDimitry Andric   }
218cb14a3feSDimitry Andric }
2195f757f3fSDimitry Andric 
2205f757f3fSDimitry Andric bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
2215f757f3fSDimitry Andric   auto Result = Categories.insert({Name, Record});
2225f757f3fSDimitry Andric   return Result.second;
2235f757f3fSDimitry Andric }
2245f757f3fSDimitry Andric 
2255f757f3fSDimitry Andric ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
2265f757f3fSDimitry Andric                                                   StringRef Category) {
2275f757f3fSDimitry Andric   Category = copyString(Category);
228*0fca6ea1SDimitry Andric   ClassToExtend = copyString(ClassToExtend);
2295f757f3fSDimitry Andric 
2305f757f3fSDimitry Andric   // Add owning record first into record slice.
2315f757f3fSDimitry Andric   auto Result =
2325f757f3fSDimitry Andric       Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
2335f757f3fSDimitry Andric   if (Result.second)
2345f757f3fSDimitry Andric     Result.first->second =
2355f757f3fSDimitry Andric         std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
2365f757f3fSDimitry Andric 
2375f757f3fSDimitry Andric   // Then add reference to it in in the class.
2385f757f3fSDimitry Andric   if (auto *ObjCClass = findObjCInterface(ClassToExtend))
2395f757f3fSDimitry Andric     ObjCClass->addObjCCategory(Result.first->second.get());
2405f757f3fSDimitry Andric 
2415f757f3fSDimitry Andric   return Result.first->second.get();
2425f757f3fSDimitry Andric }
2435f757f3fSDimitry Andric 
244cb14a3feSDimitry Andric std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
245cb14a3feSDimitry Andric   std::vector<ObjCIVarRecord *> Records;
246cb14a3feSDimitry Andric   llvm::for_each(IVars,
247cb14a3feSDimitry Andric                  [&](auto &Record) { Records.push_back(Record.second.get()); });
248cb14a3feSDimitry Andric   return Records;
249cb14a3feSDimitry Andric }
250cb14a3feSDimitry Andric 
251cb14a3feSDimitry Andric std::vector<ObjCCategoryRecord *>
252cb14a3feSDimitry Andric ObjCInterfaceRecord::getObjCCategories() const {
253cb14a3feSDimitry Andric   std::vector<ObjCCategoryRecord *> Records;
254cb14a3feSDimitry Andric   llvm::for_each(Categories,
255cb14a3feSDimitry Andric                  [&](auto &Record) { Records.push_back(Record.second); });
256cb14a3feSDimitry Andric   return Records;
257cb14a3feSDimitry Andric }
258cb14a3feSDimitry Andric 
2595f757f3fSDimitry Andric ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
2605f757f3fSDimitry Andric                                                  RecordLinkage Linkage) {
2615f757f3fSDimitry Andric   auto Result = IVars.insert({IVar, nullptr});
2625f757f3fSDimitry Andric   if (Result.second)
263cb14a3feSDimitry Andric     Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
2645f757f3fSDimitry Andric   return Result.first->second.get();
2655f757f3fSDimitry Andric }
2665f757f3fSDimitry Andric 
2675f757f3fSDimitry Andric ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
2685f757f3fSDimitry Andric                                           StringRef Name,
2695f757f3fSDimitry Andric                                           RecordLinkage Linkage) {
2705f757f3fSDimitry Andric   Name = copyString(Name);
2715f757f3fSDimitry Andric   ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
2725f757f3fSDimitry Andric   updateLinkage(Record, Linkage);
2735f757f3fSDimitry Andric   return Record;
2745f757f3fSDimitry Andric }
2755f757f3fSDimitry Andric 
2765f757f3fSDimitry Andric StringRef RecordsSlice::copyString(StringRef String) {
2775f757f3fSDimitry Andric   if (String.empty())
2785f757f3fSDimitry Andric     return {};
2795f757f3fSDimitry Andric 
2805f757f3fSDimitry Andric   if (StringAllocator.identifyObject(String.data()))
2815f757f3fSDimitry Andric     return String;
2825f757f3fSDimitry Andric 
2835f757f3fSDimitry Andric   void *Ptr = StringAllocator.Allocate(String.size(), 1);
2845f757f3fSDimitry Andric   memcpy(Ptr, String.data(), String.size());
2855f757f3fSDimitry Andric   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
2865f757f3fSDimitry Andric }
2875f757f3fSDimitry Andric 
2885f757f3fSDimitry Andric RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
2895f757f3fSDimitry Andric   if (!hasBinaryAttrs())
2905f757f3fSDimitry Andric     BA = std::make_unique<BinaryAttrs>();
2915f757f3fSDimitry Andric   return *BA;
2925f757f3fSDimitry Andric }
293cb14a3feSDimitry Andric 
294cb14a3feSDimitry Andric void RecordsSlice::visit(RecordVisitor &V) const {
295cb14a3feSDimitry Andric   for (auto &G : Globals)
296cb14a3feSDimitry Andric     V.visitGlobal(*G.second);
297cb14a3feSDimitry Andric   for (auto &C : Classes)
298cb14a3feSDimitry Andric     V.visitObjCInterface(*C.second);
299cb14a3feSDimitry Andric   for (auto &Cat : Categories)
300cb14a3feSDimitry Andric     V.visitObjCCategory(*Cat.second);
301cb14a3feSDimitry Andric }
302cb14a3feSDimitry Andric 
303cb14a3feSDimitry Andric static std::unique_ptr<InterfaceFile>
304cb14a3feSDimitry Andric createInterfaceFile(const Records &Slices, StringRef InstallName) {
305cb14a3feSDimitry Andric   // Pickup symbols first.
306cb14a3feSDimitry Andric   auto Symbols = std::make_unique<SymbolSet>();
307cb14a3feSDimitry Andric   for (auto &S : Slices) {
308cb14a3feSDimitry Andric     if (S->empty())
309cb14a3feSDimitry Andric       continue;
310cb14a3feSDimitry Andric     auto &BA = S->getBinaryAttrs();
311cb14a3feSDimitry Andric     if (BA.InstallName != InstallName)
312cb14a3feSDimitry Andric       continue;
313cb14a3feSDimitry Andric 
314cb14a3feSDimitry Andric     SymbolConverter Converter(Symbols.get(), S->getTarget(),
315cb14a3feSDimitry Andric                               !BA.TwoLevelNamespace);
316cb14a3feSDimitry Andric     S->visit(Converter);
317cb14a3feSDimitry Andric   }
318cb14a3feSDimitry Andric 
319cb14a3feSDimitry Andric   auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
320cb14a3feSDimitry Andric   File->setInstallName(InstallName);
321cb14a3feSDimitry Andric   // Assign other attributes.
322cb14a3feSDimitry Andric   for (auto &S : Slices) {
323cb14a3feSDimitry Andric     if (S->empty())
324cb14a3feSDimitry Andric       continue;
325cb14a3feSDimitry Andric     auto &BA = S->getBinaryAttrs();
326cb14a3feSDimitry Andric     if (BA.InstallName != InstallName)
327cb14a3feSDimitry Andric       continue;
328cb14a3feSDimitry Andric     const Target &Targ = S->getTarget();
329cb14a3feSDimitry Andric     File->addTarget(Targ);
330*0fca6ea1SDimitry Andric     File->setFromBinaryAttrs(BA, Targ);
331cb14a3feSDimitry Andric   }
332cb14a3feSDimitry Andric 
333cb14a3feSDimitry Andric   return File;
334cb14a3feSDimitry Andric }
335cb14a3feSDimitry Andric 
336cb14a3feSDimitry Andric std::unique_ptr<InterfaceFile>
337cb14a3feSDimitry Andric llvm::MachO::convertToInterfaceFile(const Records &Slices) {
338cb14a3feSDimitry Andric   std::unique_ptr<InterfaceFile> File;
339cb14a3feSDimitry Andric   if (Slices.empty())
340cb14a3feSDimitry Andric     return File;
341cb14a3feSDimitry Andric 
342cb14a3feSDimitry Andric   SetVector<StringRef> InstallNames;
343cb14a3feSDimitry Andric   for (auto &S : Slices) {
344cb14a3feSDimitry Andric     auto Name = S->getBinaryAttrs().InstallName;
345cb14a3feSDimitry Andric     if (Name.empty())
346cb14a3feSDimitry Andric       continue;
347cb14a3feSDimitry Andric     InstallNames.insert(Name);
348cb14a3feSDimitry Andric   }
349cb14a3feSDimitry Andric 
350cb14a3feSDimitry Andric   File = createInterfaceFile(Slices, *InstallNames.begin());
3517a6dacacSDimitry Andric   for (StringRef IN : llvm::drop_begin(InstallNames))
3527a6dacacSDimitry Andric     File->addDocument(createInterfaceFile(Slices, IN));
353cb14a3feSDimitry Andric 
354cb14a3feSDimitry Andric   return File;
355cb14a3feSDimitry Andric }
356