1 //===- RecordsSlice.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Implements the Records Slice APIs.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/TextAPI/RecordsSlice.h"
14 #include "llvm/ADT/SetVector.h"
15 #include "llvm/TextAPI/Record.h"
16 #include "llvm/TextAPI/Symbol.h"
20 using namespace llvm::MachO
;
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
);
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
);
45 llvm_unreachable("unexpected symbol kind when adding to Record Slice");
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
54 if (Container
== nullptr)
55 Container
= findObjCCategory(Super
, "");
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())
64 return Record
->second
.get();
67 GlobalRecord
*RecordsSlice::findGlobal(StringRef Name
,
68 GlobalRecord::Kind GV
) const {
69 auto *Record
= findRecord
<GlobalRecord
>(Name
, Globals
);
74 case GlobalRecord::Kind::Variable
: {
75 if (!Record
->isVariable())
79 case GlobalRecord::Kind::Function
: {
80 if (!Record
->isFunction())
84 case GlobalRecord::Kind::Unknown
:
91 ObjCInterfaceRecord
*RecordsSlice::findObjCInterface(StringRef Name
) const {
92 return findRecord
<ObjCInterfaceRecord
>(Name
, Classes
);
95 ObjCCategoryRecord
*RecordsSlice::findObjCCategory(StringRef ClassToExtend
,
96 StringRef Category
) const {
97 return findRecord
<ObjCCategoryRecord
>(std::make_pair(ClassToExtend
, Category
),
101 ObjCIVarRecord
*ObjCContainerRecord::findObjCIVar(StringRef IVar
) const {
102 return findRecord
<ObjCIVarRecord
>(IVar
, IVars
);
105 ObjCIVarRecord
*RecordsSlice::findObjCIVar(bool IsScopedName
,
106 StringRef Name
) const {
107 // If scoped name, the name of the container is known.
109 // IVar does not exist if there is not a container assigned to it.
110 auto *Container
= findContainer(/*IsIVar=*/true, Name
);
114 StringRef IVar
= Name
.substr(Name
.find_first_of('.') + 1);
115 return Container
->findObjCIVar(IVar
);
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
))
127 if (auto *IVarRecord
= getIVar(Classes
))
130 return getIVar(Categories
);
133 GlobalRecord
*RecordsSlice::addGlobal(StringRef Name
, RecordLinkage Linkage
,
134 GlobalRecord::Kind GV
,
136 if (GV
== GlobalRecord::Kind::Function
)
137 Flags
|= SymbolFlags::Text
;
138 else if (GV
== GlobalRecord::Kind::Variable
)
139 Flags
|= SymbolFlags::Data
;
141 Name
= copyString(Name
);
142 auto Result
= Globals
.insert({Name
, nullptr});
144 Result
.first
->second
=
145 std::make_unique
<GlobalRecord
>(Name
, Linkage
, Flags
, GV
);
147 updateLinkage(Result
.first
->second
.get(), Linkage
);
148 updateFlags(Result
.first
->second
.get(), Flags
);
150 return Result
.first
->second
.get();
153 ObjCInterfaceRecord
*RecordsSlice::addObjCInterface(StringRef Name
,
154 RecordLinkage Linkage
,
156 Name
= copyString(Name
);
157 auto Result
= Classes
.insert({Name
, nullptr});
159 Result
.first
->second
=
160 std::make_unique
<ObjCInterfaceRecord
>(Name
, Linkage
, HasEHType
);
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
);
168 return Result
.first
->second
.get();
170 SymbolFlags
Record::mergeFlags(SymbolFlags Flags
, RecordLinkage Linkage
) {
171 // Add Linkage properties into Flags.
173 case RecordLinkage::Rexported
:
174 Flags
|= SymbolFlags::Rexported
;
176 case RecordLinkage::Undefined
:
177 Flags
|= SymbolFlags::Undefined
;
184 bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord
*Record
) {
185 auto Result
= Categories
.insert({Name
, Record
});
186 return Result
.second
;
189 ObjCCategoryRecord
*RecordsSlice::addObjCCategory(StringRef ClassToExtend
,
190 StringRef Category
) {
191 Category
= copyString(Category
);
193 // Add owning record first into record slice.
195 Categories
.insert({std::make_pair(ClassToExtend
, Category
), nullptr});
197 Result
.first
->second
=
198 std::make_unique
<ObjCCategoryRecord
>(ClassToExtend
, Category
);
200 // Then add reference to it in in the class.
201 if (auto *ObjCClass
= findObjCInterface(ClassToExtend
))
202 ObjCClass
->addObjCCategory(Result
.first
->second
.get());
204 return Result
.first
->second
.get();
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()); });
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
); });
222 ObjCIVarRecord
*ObjCContainerRecord::addObjCIVar(StringRef IVar
,
223 RecordLinkage Linkage
) {
224 auto Result
= IVars
.insert({IVar
, nullptr});
226 Result
.first
->second
= std::make_unique
<ObjCIVarRecord
>(IVar
, Linkage
);
227 return Result
.first
->second
.get();
230 ObjCIVarRecord
*RecordsSlice::addObjCIVar(ObjCContainerRecord
*Container
,
232 RecordLinkage Linkage
) {
233 Name
= copyString(Name
);
234 ObjCIVarRecord
*Record
= Container
->addObjCIVar(Name
, Linkage
);
235 updateLinkage(Record
, Linkage
);
239 StringRef
RecordsSlice::copyString(StringRef String
) {
243 if (StringAllocator
.identifyObject(String
.data()))
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());
251 RecordsSlice::BinaryAttrs
&RecordsSlice::getBinaryAttrs() {
252 if (!hasBinaryAttrs())
253 BA
= std::make_unique
<BinaryAttrs
>();
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
);
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
) {
273 auto &BA
= S
->getBinaryAttrs();
274 if (BA
.InstallName
!= InstallName
)
277 SymbolConverter
Converter(Symbols
.get(), S
->getTarget(),
278 !BA
.TwoLevelNamespace
);
282 auto File
= std::make_unique
<InterfaceFile
>(std::move(Symbols
));
283 File
->setInstallName(InstallName
);
284 // Assign other attributes.
285 for (auto &S
: Slices
) {
288 auto &BA
= S
->getBinaryAttrs();
289 if (BA
.InstallName
!= InstallName
)
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
);
320 std::unique_ptr
<InterfaceFile
>
321 llvm::MachO::convertToInterfaceFile(const Records
&Slices
) {
322 std::unique_ptr
<InterfaceFile
> File
;
326 SetVector
<StringRef
> InstallNames
;
327 for (auto &S
: Slices
) {
328 auto Name
= S
->getBinaryAttrs().InstallName
;
331 InstallNames
.insert(Name
);
334 File
= createInterfaceFile(Slices
, *InstallNames
.begin());
335 for (StringRef IN
: llvm::drop_begin(InstallNames
))
336 File
->addDocument(createInterfaceFile(Slices
, IN
));