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