1 //===- RecordsSlice.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 Records Slice APIs.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/TextAPI/RecordsSlice.h"
14 #include "llvm/ADT/SetVector.h"
15 #include "llvm/TextAPI/Record.h"
16 #include "llvm/TextAPI/Symbol.h"
17 #include <utility>
18 
19 using namespace llvm;
20 using namespace llvm::MachO;
21 
22 Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
23                                 GlobalRecord::Kind GV, RecordLinkage Linkage) {
24   // Find a specific Record type to capture.
25   auto [APIName, SymKind] = parseSymbol(Name, Flags);
26   Name = APIName;
27   switch (SymKind) {
28   case SymbolKind::GlobalSymbol:
29     return addGlobal(Name, Linkage, GV, Flags);
30   case SymbolKind::ObjectiveCClass:
31     return addObjCInterface(Name, Linkage);
32   case SymbolKind::ObjectiveCClassEHType:
33     return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
34   case SymbolKind::ObjectiveCInstanceVariable: {
35     auto [Super, IVar] = Name.split('.');
36     // Attempt to find super class.
37     ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
38     // If not found, create extension since there is no mapped class symbol.
39     if (Container == nullptr)
40       Container = addObjCCategory(Super, {});
41     return addObjCIVar(Container, IVar, Linkage);
42   }
43   }
44 
45   llvm_unreachable("unexpected symbol kind when adding to Record Slice");
46 }
47 
48 ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
49                                                  StringRef Name) const {
50   StringRef Super = IsIVar ? Name.split('.').first : Name;
51   ObjCContainerRecord *Container = findObjCInterface(Super);
52   // Ivars can only exist with extensions, if they did not come from
53   // class.
54   if (Container == nullptr)
55     Container = findObjCCategory(Super, "");
56   return Container;
57 }
58 
59 template <typename R, typename C = RecordMap<R>, typename K = StringRef>
60 R *findRecord(K Key, const C &Container) {
61   const auto *Record = Container.find(Key);
62   if (Record == Container.end())
63     return nullptr;
64   return Record->second.get();
65 }
66 
67 GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
68                                        GlobalRecord::Kind GV) const {
69   auto *Record = findRecord<GlobalRecord>(Name, Globals);
70   if (!Record)
71     return nullptr;
72 
73   switch (GV) {
74   case GlobalRecord::Kind::Variable: {
75     if (!Record->isVariable())
76       return nullptr;
77     break;
78   }
79   case GlobalRecord::Kind::Function: {
80     if (!Record->isFunction())
81       return nullptr;
82     break;
83   }
84   case GlobalRecord::Kind::Unknown:
85     return Record;
86   }
87 
88   return Record;
89 }
90 
91 ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
92   return findRecord<ObjCInterfaceRecord>(Name, Classes);
93 }
94 
95 ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
96                                                    StringRef Category) const {
97   return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
98                                         Categories);
99 }
100 
101 ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
102   return findRecord<ObjCIVarRecord>(IVar, IVars);
103 }
104 
105 ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
106                                            StringRef Name) const {
107   // If scoped name, the name of the container is known.
108   if (IsScopedName) {
109     // IVar does not exist if there is not a container assigned to it.
110     auto *Container = findContainer(/*IsIVar=*/true, Name);
111     if (!Container)
112       return nullptr;
113 
114     StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
115     return Container->findObjCIVar(IVar);
116   }
117 
118   // Otherwise traverse through containers and attempt to find IVar.
119   auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
120     for (const auto &[_, Container] : Records) {
121       if (auto *IVarR = Container->findObjCIVar(Name))
122         return IVarR;
123     }
124     return nullptr;
125   };
126 
127   if (auto *IVarRecord = getIVar(Classes))
128     return IVarRecord;
129 
130   return getIVar(Categories);
131 }
132 
133 GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
134                                       GlobalRecord::Kind GV,
135                                       SymbolFlags Flags) {
136   if (GV == GlobalRecord::Kind::Function)
137     Flags |= SymbolFlags::Text;
138   else if (GV == GlobalRecord::Kind::Variable)
139     Flags |= SymbolFlags::Data;
140 
141   Name = copyString(Name);
142   auto Result = Globals.insert({Name, nullptr});
143   if (Result.second)
144     Result.first->second =
145         std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
146   else {
147     updateLinkage(Result.first->second.get(), Linkage);
148     updateFlags(Result.first->second.get(), Flags);
149   }
150   return Result.first->second.get();
151 }
152 
153 ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
154                                                     RecordLinkage Linkage,
155                                                     bool HasEHType) {
156   Name = copyString(Name);
157   auto Result = Classes.insert({Name, nullptr});
158   if (Result.second) {
159     Result.first->second =
160         std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
161   } else {
162     // ObjC classes represent multiple symbols that could have competing
163     // linkages, in those cases assign the largest one.
164     if (Linkage >= RecordLinkage::Rexported)
165       updateLinkage(Result.first->second.get(), Linkage);
166   }
167 
168   return Result.first->second.get();
169 }
170 SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
171   // Add Linkage properties into Flags.
172   switch (Linkage) {
173   case RecordLinkage::Rexported:
174     Flags |= SymbolFlags::Rexported;
175     return Flags;
176   case RecordLinkage::Undefined:
177     Flags |= SymbolFlags::Undefined;
178     return Flags;
179   default:
180     return Flags;
181   }
182 }
183 
184 bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
185   auto Result = Categories.insert({Name, Record});
186   return Result.second;
187 }
188 
189 ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
190                                                   StringRef Category) {
191   Category = copyString(Category);
192 
193   // Add owning record first into record slice.
194   auto Result =
195       Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
196   if (Result.second)
197     Result.first->second =
198         std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
199 
200   // Then add reference to it in in the class.
201   if (auto *ObjCClass = findObjCInterface(ClassToExtend))
202     ObjCClass->addObjCCategory(Result.first->second.get());
203 
204   return Result.first->second.get();
205 }
206 
207 std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
208   std::vector<ObjCIVarRecord *> Records;
209   llvm::for_each(IVars,
210                  [&](auto &Record) { Records.push_back(Record.second.get()); });
211   return Records;
212 }
213 
214 std::vector<ObjCCategoryRecord *>
215 ObjCInterfaceRecord::getObjCCategories() const {
216   std::vector<ObjCCategoryRecord *> Records;
217   llvm::for_each(Categories,
218                  [&](auto &Record) { Records.push_back(Record.second); });
219   return Records;
220 }
221 
222 ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
223                                                  RecordLinkage Linkage) {
224   auto Result = IVars.insert({IVar, nullptr});
225   if (Result.second)
226     Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
227   return Result.first->second.get();
228 }
229 
230 ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
231                                           StringRef Name,
232                                           RecordLinkage Linkage) {
233   Name = copyString(Name);
234   ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
235   updateLinkage(Record, Linkage);
236   return Record;
237 }
238 
239 StringRef RecordsSlice::copyString(StringRef String) {
240   if (String.empty())
241     return {};
242 
243   if (StringAllocator.identifyObject(String.data()))
244     return String;
245 
246   void *Ptr = StringAllocator.Allocate(String.size(), 1);
247   memcpy(Ptr, String.data(), String.size());
248   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
249 }
250 
251 RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
252   if (!hasBinaryAttrs())
253     BA = std::make_unique<BinaryAttrs>();
254   return *BA;
255 }
256 
257 void RecordsSlice::visit(RecordVisitor &V) const {
258   for (auto &G : Globals)
259     V.visitGlobal(*G.second);
260   for (auto &C : Classes)
261     V.visitObjCInterface(*C.second);
262   for (auto &Cat : Categories)
263     V.visitObjCCategory(*Cat.second);
264 }
265 
266 static std::unique_ptr<InterfaceFile>
267 createInterfaceFile(const Records &Slices, StringRef InstallName) {
268   // Pickup symbols first.
269   auto Symbols = std::make_unique<SymbolSet>();
270   for (auto &S : Slices) {
271     if (S->empty())
272       continue;
273     auto &BA = S->getBinaryAttrs();
274     if (BA.InstallName != InstallName)
275       continue;
276 
277     SymbolConverter Converter(Symbols.get(), S->getTarget(),
278                               !BA.TwoLevelNamespace);
279     S->visit(Converter);
280   }
281 
282   auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
283   File->setInstallName(InstallName);
284   // Assign other attributes.
285   for (auto &S : Slices) {
286     if (S->empty())
287       continue;
288     auto &BA = S->getBinaryAttrs();
289     if (BA.InstallName != InstallName)
290       continue;
291     const Target &Targ = S->getTarget();
292     File->addTarget(Targ);
293     if (File->getFileType() == FileType::Invalid)
294       File->setFileType(BA.File);
295     if (BA.AppExtensionSafe && !File->isApplicationExtensionSafe())
296       File->setApplicationExtensionSafe();
297     if (BA.TwoLevelNamespace && !File->isTwoLevelNamespace())
298       File->setTwoLevelNamespace();
299     if (BA.OSLibNotForSharedCache && !File->isOSLibNotForSharedCache())
300       File->setOSLibNotForSharedCache();
301     if (File->getCurrentVersion().empty())
302       File->setCurrentVersion(BA.CurrentVersion);
303     if (File->getCompatibilityVersion().empty())
304       File->setCompatibilityVersion(BA.CompatVersion);
305     if (File->getSwiftABIVersion() == 0)
306       File->setSwiftABIVersion(BA.SwiftABI);
307     if (File->getPath().empty())
308       File->setPath(BA.Path);
309     if (!BA.ParentUmbrella.empty())
310       File->addParentUmbrella(Targ, BA.ParentUmbrella);
311     for (const auto &Client : BA.AllowableClients)
312       File->addAllowableClient(Client, Targ);
313     for (const auto &Lib : BA.RexportedLibraries)
314       File->addReexportedLibrary(Lib, Targ);
315   }
316 
317   return File;
318 }
319 
320 std::unique_ptr<InterfaceFile>
321 llvm::MachO::convertToInterfaceFile(const Records &Slices) {
322   std::unique_ptr<InterfaceFile> File;
323   if (Slices.empty())
324     return File;
325 
326   SetVector<StringRef> InstallNames;
327   for (auto &S : Slices) {
328     auto Name = S->getBinaryAttrs().InstallName;
329     if (Name.empty())
330       continue;
331     InstallNames.insert(Name);
332   }
333 
334   File = createInterfaceFile(Slices, *InstallNames.begin());
335   for (auto it = std::next(InstallNames.begin()); it != InstallNames.end();
336        ++it)
337     File->addDocument(createInterfaceFile(Slices, *it));
338 
339   return File;
340 }
341