xref: /llvm-project/llvm/lib/TextAPI/RecordsSlice.cpp (revision b04b89753daf9751a81ffbcfbfbe6c610fb88af8)
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/TextAPI/Record.h"
15 #include "llvm/TextAPI/Symbol.h"
16 #include <utility>
17 
18 using namespace llvm;
19 using namespace llvm::MachO;
20 
21 Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
22                                 GlobalRecord::Kind GV, RecordLinkage Linkage) {
23   // Find a specific Record type to capture.
24   auto [APIName, SymKind] = parseSymbol(Name, Flags);
25   Name = APIName;
26   switch (SymKind) {
27   case SymbolKind::GlobalSymbol:
28     return addGlobal(Name, Linkage, GV, Flags);
29   case SymbolKind::ObjectiveCClass:
30     return addObjCInterface(Name, Linkage);
31   case SymbolKind::ObjectiveCClassEHType:
32     return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
33   case SymbolKind::ObjectiveCInstanceVariable: {
34     auto [Super, IVar] = Name.split('.');
35     // Attempt to find super class.
36     ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
37     // If not found, create extension since there is no mapped class symbol.
38     if (Container == nullptr)
39       Container = addObjCCategory(Super, {});
40     return addObjCIVar(Container, IVar, Linkage);
41   }
42   }
43 
44   llvm_unreachable("unexpected symbol kind when adding to Record Slice");
45 }
46 
47 ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
48                                                  StringRef Name) const {
49   StringRef Super = IsIVar ? Name.split('.').first : Name;
50   ObjCContainerRecord *Container = findObjCInterface(Super);
51   // Ivars can only exist with extensions, if they did not come from
52   // class.
53   if (Container == nullptr)
54     Container = findObjCCategory(Super, "");
55   return Container;
56 }
57 
58 template <typename R, typename C = RecordMap<R>, typename K = StringRef>
59 R *findRecord(K Key, const C &Container) {
60   const auto *Record = Container.find(Key);
61   if (Record == Container.end())
62     return nullptr;
63   return Record->second.get();
64 }
65 
66 GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
67                                        GlobalRecord::Kind GV) const {
68   auto *Record = findRecord<GlobalRecord>(Name, Globals);
69   if (!Record)
70     return nullptr;
71 
72   switch (GV) {
73   case GlobalRecord::Kind::Variable: {
74     if (!Record->isVariable())
75       return nullptr;
76     break;
77   }
78   case GlobalRecord::Kind::Function: {
79     if (!Record->isFunction())
80       return nullptr;
81     break;
82   }
83   case GlobalRecord::Kind::Unknown:
84     return Record;
85   }
86 
87   return Record;
88 }
89 
90 ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
91   return findRecord<ObjCInterfaceRecord>(Name, Classes);
92 }
93 
94 ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
95                                                    StringRef Category) const {
96   return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
97                                         Categories);
98 }
99 
100 ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
101   return findRecord<ObjCIVarRecord>(IVar, IVars);
102 }
103 
104 ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
105                                            StringRef Name) const {
106   // If scoped name, the name of the container is known.
107   if (IsScopedName) {
108     // IVar does not exist if there is not a container assigned to it.
109     auto *Container = findContainer(/*IsIVar=*/true, Name);
110     if (!Container)
111       return nullptr;
112 
113     StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
114     return Container->findObjCIVar(IVar);
115   }
116 
117   // Otherwise traverse through containers and attempt to find IVar.
118   auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
119     for (const auto &[_, Container] : Records) {
120       if (auto *IVarR = Container->findObjCIVar(Name))
121         return IVarR;
122     }
123     return nullptr;
124   };
125 
126   if (auto *IVarRecord = getIVar(Classes))
127     return IVarRecord;
128 
129   return getIVar(Categories);
130 }
131 
132 GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
133                                       GlobalRecord::Kind GV,
134                                       SymbolFlags Flags) {
135   if (GV == GlobalRecord::Kind::Function)
136     Flags |= SymbolFlags::Text;
137   else if (GV == GlobalRecord::Kind::Variable)
138     Flags |= SymbolFlags::Data;
139 
140   Name = copyString(Name);
141   auto Result = Globals.insert({Name, nullptr});
142   if (Result.second)
143     Result.first->second =
144         std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
145   else
146     updateLinkage(Result.first->second.get(), Linkage);
147   return Result.first->second.get();
148 }
149 
150 ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
151                                                     RecordLinkage Linkage,
152                                                     bool HasEHType) {
153   Name = copyString(Name);
154   auto Result = Classes.insert({Name, nullptr});
155   if (Result.second) {
156     Result.first->second =
157         std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
158   } else {
159     // ObjC classes represent multiple symbols that could have competing
160     // linkages, in those cases assign the largest one.
161     if (Linkage >= RecordLinkage::Rexported)
162       updateLinkage(Result.first->second.get(), Linkage);
163   }
164 
165   return Result.first->second.get();
166 }
167 
168 bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
169   auto Result = Categories.insert({Name, Record});
170   return Result.second;
171 }
172 
173 ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
174                                                   StringRef Category) {
175   Category = copyString(Category);
176 
177   // Add owning record first into record slice.
178   auto Result =
179       Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
180   if (Result.second)
181     Result.first->second =
182         std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
183 
184   // Then add reference to it in in the class.
185   if (auto *ObjCClass = findObjCInterface(ClassToExtend))
186     ObjCClass->addObjCCategory(Result.first->second.get());
187 
188   return Result.first->second.get();
189 }
190 
191 ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
192                                                  RecordLinkage Linkage) {
193   auto Result = IVars.insert({IVar, nullptr});
194   if (Result.second)
195     Result.first->second = std::make_unique<ObjCIVarRecord>(Name, Linkage);
196   return Result.first->second.get();
197 }
198 
199 ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
200                                           StringRef Name,
201                                           RecordLinkage Linkage) {
202   Name = copyString(Name);
203   ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
204   updateLinkage(Record, Linkage);
205   return Record;
206 }
207 
208 StringRef RecordsSlice::copyString(StringRef String) {
209   if (String.empty())
210     return {};
211 
212   if (StringAllocator.identifyObject(String.data()))
213     return String;
214 
215   void *Ptr = StringAllocator.Allocate(String.size(), 1);
216   memcpy(Ptr, String.data(), String.size());
217   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
218 }
219 
220 RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
221   if (!hasBinaryAttrs())
222     BA = std::make_unique<BinaryAttrs>();
223   return *BA;
224 }
225