1b04b8975SCyndy Ishida //===- RecordsSlice.cpp --------------------------------------------------===// 2b04b8975SCyndy Ishida // 3b04b8975SCyndy Ishida // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b04b8975SCyndy Ishida // See https://llvm.org/LICENSE.txt for license information. 5b04b8975SCyndy Ishida // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b04b8975SCyndy Ishida // 7b04b8975SCyndy Ishida //===----------------------------------------------------------------------===// 8b04b8975SCyndy Ishida // 9b04b8975SCyndy Ishida // Implements the Records Slice APIs. 10b04b8975SCyndy Ishida // 11b04b8975SCyndy Ishida //===----------------------------------------------------------------------===// 12b04b8975SCyndy Ishida 13b04b8975SCyndy Ishida #include "llvm/TextAPI/RecordsSlice.h" 145ea15fabSCyndy Ishida #include "llvm/ADT/SetVector.h" 153a080a01SCyndy Ishida #include "llvm/TextAPI/InterfaceFile.h" 16b04b8975SCyndy Ishida #include "llvm/TextAPI/Record.h" 17b04b8975SCyndy Ishida #include "llvm/TextAPI/Symbol.h" 18b04b8975SCyndy Ishida #include <utility> 19b04b8975SCyndy Ishida 20b04b8975SCyndy Ishida using namespace llvm; 21b04b8975SCyndy Ishida using namespace llvm::MachO; 22b04b8975SCyndy Ishida 23b04b8975SCyndy Ishida Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags, 24b04b8975SCyndy Ishida GlobalRecord::Kind GV, RecordLinkage Linkage) { 25b04b8975SCyndy Ishida // Find a specific Record type to capture. 264460fa88SCyndy Ishida auto [APIName, SymKind, InterfaceType] = parseSymbol(Name); 27b04b8975SCyndy Ishida Name = APIName; 28b04b8975SCyndy Ishida switch (SymKind) { 29d9a9872eSCyndy Ishida case EncodeKind::GlobalSymbol: 30b04b8975SCyndy Ishida return addGlobal(Name, Linkage, GV, Flags); 31d9a9872eSCyndy Ishida case EncodeKind::ObjectiveCClass: 324460fa88SCyndy Ishida return addObjCInterface(Name, Linkage, InterfaceType); 334460fa88SCyndy Ishida case EncodeKind::ObjectiveCClassEHType: { 344460fa88SCyndy Ishida ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType); 354460fa88SCyndy Ishida // When classes without ehtype are used in try/catch blocks 364460fa88SCyndy Ishida // a weak-defined symbol is exported. 374460fa88SCyndy Ishida if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined) 384460fa88SCyndy Ishida updateFlags(Rec, SymbolFlags::WeakDefined); 394460fa88SCyndy Ishida return Rec; 404460fa88SCyndy Ishida } 41d9a9872eSCyndy Ishida case EncodeKind::ObjectiveCInstanceVariable: { 42b04b8975SCyndy Ishida auto [Super, IVar] = Name.split('.'); 43b04b8975SCyndy Ishida // Attempt to find super class. 44b04b8975SCyndy Ishida ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super); 45b04b8975SCyndy Ishida // If not found, create extension since there is no mapped class symbol. 46b04b8975SCyndy Ishida if (Container == nullptr) 47b04b8975SCyndy Ishida Container = addObjCCategory(Super, {}); 48b04b8975SCyndy Ishida return addObjCIVar(Container, IVar, Linkage); 49b04b8975SCyndy Ishida } 50b04b8975SCyndy Ishida } 51b04b8975SCyndy Ishida 52b04b8975SCyndy Ishida llvm_unreachable("unexpected symbol kind when adding to Record Slice"); 53b04b8975SCyndy Ishida } 54b04b8975SCyndy Ishida 55b04b8975SCyndy Ishida ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar, 56b04b8975SCyndy Ishida StringRef Name) const { 57b04b8975SCyndy Ishida StringRef Super = IsIVar ? Name.split('.').first : Name; 58b04b8975SCyndy Ishida ObjCContainerRecord *Container = findObjCInterface(Super); 59b04b8975SCyndy Ishida // Ivars can only exist with extensions, if they did not come from 60b04b8975SCyndy Ishida // class. 61b04b8975SCyndy Ishida if (Container == nullptr) 62b04b8975SCyndy Ishida Container = findObjCCategory(Super, ""); 63b04b8975SCyndy Ishida return Container; 64b04b8975SCyndy Ishida } 65b04b8975SCyndy Ishida 66b04b8975SCyndy Ishida template <typename R, typename C = RecordMap<R>, typename K = StringRef> 67b04b8975SCyndy Ishida R *findRecord(K Key, const C &Container) { 68b04b8975SCyndy Ishida const auto *Record = Container.find(Key); 69b04b8975SCyndy Ishida if (Record == Container.end()) 70b04b8975SCyndy Ishida return nullptr; 71b04b8975SCyndy Ishida return Record->second.get(); 72b04b8975SCyndy Ishida } 73b04b8975SCyndy Ishida 74b04b8975SCyndy Ishida GlobalRecord *RecordsSlice::findGlobal(StringRef Name, 75b04b8975SCyndy Ishida GlobalRecord::Kind GV) const { 76b04b8975SCyndy Ishida auto *Record = findRecord<GlobalRecord>(Name, Globals); 77b04b8975SCyndy Ishida if (!Record) 78b04b8975SCyndy Ishida return nullptr; 79b04b8975SCyndy Ishida 80b04b8975SCyndy Ishida switch (GV) { 81b04b8975SCyndy Ishida case GlobalRecord::Kind::Variable: { 82b04b8975SCyndy Ishida if (!Record->isVariable()) 83b04b8975SCyndy Ishida return nullptr; 84b04b8975SCyndy Ishida break; 85b04b8975SCyndy Ishida } 86b04b8975SCyndy Ishida case GlobalRecord::Kind::Function: { 87b04b8975SCyndy Ishida if (!Record->isFunction()) 88b04b8975SCyndy Ishida return nullptr; 89b04b8975SCyndy Ishida break; 90b04b8975SCyndy Ishida } 91b04b8975SCyndy Ishida case GlobalRecord::Kind::Unknown: 92b04b8975SCyndy Ishida return Record; 93b04b8975SCyndy Ishida } 94b04b8975SCyndy Ishida 95b04b8975SCyndy Ishida return Record; 96b04b8975SCyndy Ishida } 97b04b8975SCyndy Ishida 984460fa88SCyndy Ishida RecordLinkage 994460fa88SCyndy Ishida ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const { 1004460fa88SCyndy Ishida assert(CurrType <= ObjCIFSymbolKind::EHType && 1014460fa88SCyndy Ishida "expected single ObjCIFSymbolKind enum value"); 1024460fa88SCyndy Ishida if (CurrType == ObjCIFSymbolKind::Class) 1034460fa88SCyndy Ishida return Linkages.Class; 1044460fa88SCyndy Ishida 1054460fa88SCyndy Ishida if (CurrType == ObjCIFSymbolKind::MetaClass) 1064460fa88SCyndy Ishida return Linkages.MetaClass; 1074460fa88SCyndy Ishida 1084460fa88SCyndy Ishida if (CurrType == ObjCIFSymbolKind::EHType) 1094460fa88SCyndy Ishida return Linkages.EHType; 1104460fa88SCyndy Ishida 1114460fa88SCyndy Ishida llvm_unreachable("unexpected ObjCIFSymbolKind"); 1124460fa88SCyndy Ishida } 1134460fa88SCyndy Ishida 1144460fa88SCyndy Ishida void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType, 1154460fa88SCyndy Ishida RecordLinkage Link) { 1164460fa88SCyndy Ishida if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class) 1174460fa88SCyndy Ishida Linkages.Class = std::max(Link, Linkages.Class); 1184460fa88SCyndy Ishida if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass) 1194460fa88SCyndy Ishida Linkages.MetaClass = std::max(Link, Linkages.MetaClass); 1204460fa88SCyndy Ishida if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType) 1214460fa88SCyndy Ishida Linkages.EHType = std::max(Link, Linkages.EHType); 1224460fa88SCyndy Ishida 1234460fa88SCyndy Ishida // Obj-C Classes represent multiple symbols that could have competing 1244460fa88SCyndy Ishida // linkages, in this case assign the largest one, when querying the linkage of 1254460fa88SCyndy Ishida // the record itself. This allows visitors pick whether they want to account 1264460fa88SCyndy Ishida // for complete symbol information. 1274460fa88SCyndy Ishida Linkage = 1284460fa88SCyndy Ishida std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType)); 1294460fa88SCyndy Ishida } 1304460fa88SCyndy Ishida 131b04b8975SCyndy Ishida ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const { 132b04b8975SCyndy Ishida return findRecord<ObjCInterfaceRecord>(Name, Classes); 133b04b8975SCyndy Ishida } 134b04b8975SCyndy Ishida 135b04b8975SCyndy Ishida ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend, 136b04b8975SCyndy Ishida StringRef Category) const { 137b04b8975SCyndy Ishida return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category), 138b04b8975SCyndy Ishida Categories); 139b04b8975SCyndy Ishida } 140b04b8975SCyndy Ishida 141b04b8975SCyndy Ishida ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const { 142b04b8975SCyndy Ishida return findRecord<ObjCIVarRecord>(IVar, IVars); 143b04b8975SCyndy Ishida } 144b04b8975SCyndy Ishida 145b04b8975SCyndy Ishida ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName, 146b04b8975SCyndy Ishida StringRef Name) const { 147b04b8975SCyndy Ishida // If scoped name, the name of the container is known. 148b04b8975SCyndy Ishida if (IsScopedName) { 149b04b8975SCyndy Ishida // IVar does not exist if there is not a container assigned to it. 150b04b8975SCyndy Ishida auto *Container = findContainer(/*IsIVar=*/true, Name); 151b04b8975SCyndy Ishida if (!Container) 152b04b8975SCyndy Ishida return nullptr; 153b04b8975SCyndy Ishida 154b04b8975SCyndy Ishida StringRef IVar = Name.substr(Name.find_first_of('.') + 1); 155b04b8975SCyndy Ishida return Container->findObjCIVar(IVar); 156b04b8975SCyndy Ishida } 157b04b8975SCyndy Ishida 158b04b8975SCyndy Ishida // Otherwise traverse through containers and attempt to find IVar. 159b04b8975SCyndy Ishida auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * { 160b04b8975SCyndy Ishida for (const auto &[_, Container] : Records) { 161b04b8975SCyndy Ishida if (auto *IVarR = Container->findObjCIVar(Name)) 162b04b8975SCyndy Ishida return IVarR; 163b04b8975SCyndy Ishida } 164b04b8975SCyndy Ishida return nullptr; 165b04b8975SCyndy Ishida }; 166b04b8975SCyndy Ishida 167b04b8975SCyndy Ishida if (auto *IVarRecord = getIVar(Classes)) 168b04b8975SCyndy Ishida return IVarRecord; 169b04b8975SCyndy Ishida 170b04b8975SCyndy Ishida return getIVar(Categories); 171b04b8975SCyndy Ishida } 172b04b8975SCyndy Ishida 173b04b8975SCyndy Ishida GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage, 17450ae8a2aSCyndy Ishida GlobalRecord::Kind GV, SymbolFlags Flags, 17550ae8a2aSCyndy Ishida bool Inlined) { 176b04b8975SCyndy Ishida if (GV == GlobalRecord::Kind::Function) 177b04b8975SCyndy Ishida Flags |= SymbolFlags::Text; 178b04b8975SCyndy Ishida else if (GV == GlobalRecord::Kind::Variable) 179b04b8975SCyndy Ishida Flags |= SymbolFlags::Data; 180b04b8975SCyndy Ishida 181b04b8975SCyndy Ishida Name = copyString(Name); 182b04b8975SCyndy Ishida auto Result = Globals.insert({Name, nullptr}); 183b04b8975SCyndy Ishida if (Result.second) 184b04b8975SCyndy Ishida Result.first->second = 18550ae8a2aSCyndy Ishida std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV, Inlined); 1865ea15fabSCyndy Ishida else { 187b04b8975SCyndy Ishida updateLinkage(Result.first->second.get(), Linkage); 1885ea15fabSCyndy Ishida updateFlags(Result.first->second.get(), Flags); 1895ea15fabSCyndy Ishida } 190b04b8975SCyndy Ishida return Result.first->second.get(); 191b04b8975SCyndy Ishida } 192b04b8975SCyndy Ishida 193b04b8975SCyndy Ishida ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name, 194b04b8975SCyndy Ishida RecordLinkage Linkage, 1954460fa88SCyndy Ishida ObjCIFSymbolKind SymType) { 196b04b8975SCyndy Ishida Name = copyString(Name); 197b04b8975SCyndy Ishida auto Result = Classes.insert({Name, nullptr}); 1984460fa88SCyndy Ishida if (Result.second) 199b04b8975SCyndy Ishida Result.first->second = 2004460fa88SCyndy Ishida std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType); 2014460fa88SCyndy Ishida else 2024460fa88SCyndy Ishida Result.first->second->updateLinkageForSymbols(SymType, Linkage); 203b04b8975SCyndy Ishida return Result.first->second.get(); 204b04b8975SCyndy Ishida } 2054460fa88SCyndy Ishida 2065ea15fabSCyndy Ishida SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) { 2075ea15fabSCyndy Ishida // Add Linkage properties into Flags. 2085ea15fabSCyndy Ishida switch (Linkage) { 2095ea15fabSCyndy Ishida case RecordLinkage::Rexported: 2105ea15fabSCyndy Ishida Flags |= SymbolFlags::Rexported; 2115ea15fabSCyndy Ishida return Flags; 2125ea15fabSCyndy Ishida case RecordLinkage::Undefined: 2135ea15fabSCyndy Ishida Flags |= SymbolFlags::Undefined; 2145ea15fabSCyndy Ishida return Flags; 2155ea15fabSCyndy Ishida default: 2165ea15fabSCyndy Ishida return Flags; 2175ea15fabSCyndy Ishida } 2185ea15fabSCyndy Ishida } 219b04b8975SCyndy Ishida 220b04b8975SCyndy Ishida bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) { 221b04b8975SCyndy Ishida auto Result = Categories.insert({Name, Record}); 222b04b8975SCyndy Ishida return Result.second; 223b04b8975SCyndy Ishida } 224b04b8975SCyndy Ishida 225b04b8975SCyndy Ishida ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend, 226b04b8975SCyndy Ishida StringRef Category) { 227b04b8975SCyndy Ishida Category = copyString(Category); 22810ccde30SCyndy Ishida ClassToExtend = copyString(ClassToExtend); 229b04b8975SCyndy Ishida 230b04b8975SCyndy Ishida // Add owning record first into record slice. 231b04b8975SCyndy Ishida auto Result = 232b04b8975SCyndy Ishida Categories.insert({std::make_pair(ClassToExtend, Category), nullptr}); 233b04b8975SCyndy Ishida if (Result.second) 234b04b8975SCyndy Ishida Result.first->second = 235b04b8975SCyndy Ishida std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category); 236b04b8975SCyndy Ishida 237b04b8975SCyndy Ishida // Then add reference to it in in the class. 238b04b8975SCyndy Ishida if (auto *ObjCClass = findObjCInterface(ClassToExtend)) 239b04b8975SCyndy Ishida ObjCClass->addObjCCategory(Result.first->second.get()); 240b04b8975SCyndy Ishida 241b04b8975SCyndy Ishida return Result.first->second.get(); 242b04b8975SCyndy Ishida } 243b04b8975SCyndy Ishida 2445ea15fabSCyndy Ishida std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const { 2455ea15fabSCyndy Ishida std::vector<ObjCIVarRecord *> Records; 246*d2f0d991SKazu Hirata Records.reserve(IVars.size()); 247*d2f0d991SKazu Hirata for (const auto &Record : IVars) 248*d2f0d991SKazu Hirata Records.push_back(Record.second.get()); 2495ea15fabSCyndy Ishida return Records; 2505ea15fabSCyndy Ishida } 2515ea15fabSCyndy Ishida 2525ea15fabSCyndy Ishida std::vector<ObjCCategoryRecord *> 2535ea15fabSCyndy Ishida ObjCInterfaceRecord::getObjCCategories() const { 2545ea15fabSCyndy Ishida std::vector<ObjCCategoryRecord *> Records; 255*d2f0d991SKazu Hirata Records.reserve(Categories.size()); 256*d2f0d991SKazu Hirata for (const auto &Record : Categories) 257*d2f0d991SKazu Hirata Records.push_back(Record.second); 2585ea15fabSCyndy Ishida return Records; 2595ea15fabSCyndy Ishida } 2605ea15fabSCyndy Ishida 261b04b8975SCyndy Ishida ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar, 262b04b8975SCyndy Ishida RecordLinkage Linkage) { 263b04b8975SCyndy Ishida auto Result = IVars.insert({IVar, nullptr}); 264b04b8975SCyndy Ishida if (Result.second) 2655ea15fabSCyndy Ishida Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage); 266b04b8975SCyndy Ishida return Result.first->second.get(); 267b04b8975SCyndy Ishida } 268b04b8975SCyndy Ishida 269b04b8975SCyndy Ishida ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container, 270b04b8975SCyndy Ishida StringRef Name, 271b04b8975SCyndy Ishida RecordLinkage Linkage) { 272b04b8975SCyndy Ishida Name = copyString(Name); 273b04b8975SCyndy Ishida ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage); 274b04b8975SCyndy Ishida updateLinkage(Record, Linkage); 275b04b8975SCyndy Ishida return Record; 276b04b8975SCyndy Ishida } 277b04b8975SCyndy Ishida 278b04b8975SCyndy Ishida StringRef RecordsSlice::copyString(StringRef String) { 279b04b8975SCyndy Ishida if (String.empty()) 280b04b8975SCyndy Ishida return {}; 281b04b8975SCyndy Ishida 282b04b8975SCyndy Ishida if (StringAllocator.identifyObject(String.data())) 283b04b8975SCyndy Ishida return String; 284b04b8975SCyndy Ishida 285b04b8975SCyndy Ishida void *Ptr = StringAllocator.Allocate(String.size(), 1); 286b04b8975SCyndy Ishida memcpy(Ptr, String.data(), String.size()); 287b04b8975SCyndy Ishida return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 288b04b8975SCyndy Ishida } 289b04b8975SCyndy Ishida 290b04b8975SCyndy Ishida RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() { 291b04b8975SCyndy Ishida if (!hasBinaryAttrs()) 292b04b8975SCyndy Ishida BA = std::make_unique<BinaryAttrs>(); 293b04b8975SCyndy Ishida return *BA; 294b04b8975SCyndy Ishida } 2955ea15fabSCyndy Ishida 2965ea15fabSCyndy Ishida void RecordsSlice::visit(RecordVisitor &V) const { 2975ea15fabSCyndy Ishida for (auto &G : Globals) 2985ea15fabSCyndy Ishida V.visitGlobal(*G.second); 2995ea15fabSCyndy Ishida for (auto &C : Classes) 3005ea15fabSCyndy Ishida V.visitObjCInterface(*C.second); 3015ea15fabSCyndy Ishida for (auto &Cat : Categories) 3025ea15fabSCyndy Ishida V.visitObjCCategory(*Cat.second); 3035ea15fabSCyndy Ishida } 3045ea15fabSCyndy Ishida 3055ea15fabSCyndy Ishida static std::unique_ptr<InterfaceFile> 3065ea15fabSCyndy Ishida createInterfaceFile(const Records &Slices, StringRef InstallName) { 3075ea15fabSCyndy Ishida // Pickup symbols first. 3085ea15fabSCyndy Ishida auto Symbols = std::make_unique<SymbolSet>(); 3095ea15fabSCyndy Ishida for (auto &S : Slices) { 3105ea15fabSCyndy Ishida if (S->empty()) 3115ea15fabSCyndy Ishida continue; 3125ea15fabSCyndy Ishida auto &BA = S->getBinaryAttrs(); 3135ea15fabSCyndy Ishida if (BA.InstallName != InstallName) 3145ea15fabSCyndy Ishida continue; 3155ea15fabSCyndy Ishida 3165ea15fabSCyndy Ishida SymbolConverter Converter(Symbols.get(), S->getTarget(), 3175ea15fabSCyndy Ishida !BA.TwoLevelNamespace); 3185ea15fabSCyndy Ishida S->visit(Converter); 3195ea15fabSCyndy Ishida } 3205ea15fabSCyndy Ishida 3215ea15fabSCyndy Ishida auto File = std::make_unique<InterfaceFile>(std::move(Symbols)); 3225ea15fabSCyndy Ishida File->setInstallName(InstallName); 3235ea15fabSCyndy Ishida // Assign other attributes. 3245ea15fabSCyndy Ishida for (auto &S : Slices) { 3255ea15fabSCyndy Ishida if (S->empty()) 3265ea15fabSCyndy Ishida continue; 3275ea15fabSCyndy Ishida auto &BA = S->getBinaryAttrs(); 3285ea15fabSCyndy Ishida if (BA.InstallName != InstallName) 3295ea15fabSCyndy Ishida continue; 3305ea15fabSCyndy Ishida const Target &Targ = S->getTarget(); 3315ea15fabSCyndy Ishida File->addTarget(Targ); 3323a080a01SCyndy Ishida File->setFromBinaryAttrs(BA, Targ); 3335ea15fabSCyndy Ishida } 3345ea15fabSCyndy Ishida 3355ea15fabSCyndy Ishida return File; 3365ea15fabSCyndy Ishida } 3375ea15fabSCyndy Ishida 3385ea15fabSCyndy Ishida std::unique_ptr<InterfaceFile> 3395ea15fabSCyndy Ishida llvm::MachO::convertToInterfaceFile(const Records &Slices) { 3405ea15fabSCyndy Ishida std::unique_ptr<InterfaceFile> File; 3415ea15fabSCyndy Ishida if (Slices.empty()) 3425ea15fabSCyndy Ishida return File; 3435ea15fabSCyndy Ishida 3445ea15fabSCyndy Ishida SetVector<StringRef> InstallNames; 3455ea15fabSCyndy Ishida for (auto &S : Slices) { 3465ea15fabSCyndy Ishida auto Name = S->getBinaryAttrs().InstallName; 3475ea15fabSCyndy Ishida if (Name.empty()) 3485ea15fabSCyndy Ishida continue; 3495ea15fabSCyndy Ishida InstallNames.insert(Name); 3505ea15fabSCyndy Ishida } 3515ea15fabSCyndy Ishida 3525ea15fabSCyndy Ishida File = createInterfaceFile(Slices, *InstallNames.begin()); 35396f14ea6SKazu Hirata for (StringRef IN : llvm::drop_begin(InstallNames)) 35496f14ea6SKazu Hirata File->addDocument(createInterfaceFile(Slices, IN)); 3555ea15fabSCyndy Ishida 3565ea15fabSCyndy Ishida return File; 3575ea15fabSCyndy Ishida } 358