1 | //===- ExtractAPI/API.cpp ---------------------------------------*- C++ -*-===// |
---|---|
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 | /// \file |
10 | /// This file implements the APIRecord and derived record structs, |
11 | /// and the APISet class. |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "clang/ExtractAPI/API.h" |
16 | #include "llvm/ADT/StringRef.h" |
17 | #include "llvm/Support/ErrorHandling.h" |
18 | #include <memory> |
19 | |
20 | using namespace clang::extractapi; |
21 | using namespace llvm; |
22 | |
23 | SymbolReference::SymbolReference(const APIRecord *R) |
24 | : Name(R->Name), USR(R->USR), Record(R) {} |
25 | |
26 | APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { |
27 | switch (Ctx->getKind()) { |
28 | #define RECORD_CONTEXT(CLASS, KIND) \ |
29 | case KIND: \ |
30 | return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx)); |
31 | #include "clang/ExtractAPI/APIRecords.inc" |
32 | default: |
33 | return nullptr; |
34 | // llvm_unreachable("RecordContext derived class isn't propertly |
35 | // implemented"); |
36 | } |
37 | } |
38 | |
39 | RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { |
40 | if (!Record) |
41 | return nullptr; |
42 | switch (Record->getKind()) { |
43 | #define RECORD_CONTEXT(CLASS, KIND) \ |
44 | case KIND: \ |
45 | return static_cast<CLASS *>(const_cast<APIRecord *>(Record)); |
46 | #include "clang/ExtractAPI/APIRecords.inc" |
47 | default: |
48 | return nullptr; |
49 | // llvm_unreachable("RecordContext derived class isn't propertly |
50 | // implemented"); |
51 | } |
52 | } |
53 | |
54 | bool RecordContext::IsWellFormed() const { |
55 | // Check that First and Last are both null or both non-null. |
56 | return (First == nullptr) == (Last == nullptr); |
57 | } |
58 | |
59 | void RecordContext::stealRecordChain(RecordContext &Other) { |
60 | assert(IsWellFormed()); |
61 | // Other's record chain is empty, nothing to do |
62 | if (Other.First == nullptr && Other.Last == nullptr) |
63 | return; |
64 | |
65 | // If we don't have an empty chain append Other's chain into ours. |
66 | if (First) |
67 | Last->NextInContext = Other.First; |
68 | else |
69 | First = Other.First; |
70 | |
71 | Last = Other.Last; |
72 | |
73 | for (auto *StolenRecord = Other.First; StolenRecord != nullptr; |
74 | StolenRecord = StolenRecord->getNextInContext()) |
75 | StolenRecord->Parent = SymbolReference(cast<APIRecord>(Val: this)); |
76 | |
77 | // Delete Other's chain to ensure we don't accidentally traverse it. |
78 | Other.First = nullptr; |
79 | Other.Last = nullptr; |
80 | } |
81 | |
82 | void RecordContext::addToRecordChain(APIRecord *Record) const { |
83 | assert(IsWellFormed()); |
84 | if (!First) { |
85 | First = Record; |
86 | Last = Record; |
87 | return; |
88 | } |
89 | |
90 | Last->NextInContext = Record; |
91 | Last = Record; |
92 | } |
93 | |
94 | void RecordContext::removeFromRecordChain(APIRecord *Record) { |
95 | APIRecord *Prev = nullptr; |
96 | for (APIRecord *Curr = First; Curr != Record; Curr = Curr->NextInContext) |
97 | Prev = Curr; |
98 | |
99 | if (Prev) |
100 | Prev->NextInContext = Record->NextInContext; |
101 | else |
102 | First = Record->NextInContext; |
103 | |
104 | if (Last == Record) |
105 | Last = Prev; |
106 | |
107 | Record->NextInContext = nullptr; |
108 | } |
109 | |
110 | APIRecord *APISet::findRecordForUSR(StringRef USR) const { |
111 | if (USR.empty()) |
112 | return nullptr; |
113 | |
114 | auto FindIt = USRBasedLookupTable.find(Val: USR); |
115 | if (FindIt != USRBasedLookupTable.end()) |
116 | return FindIt->getSecond().get(); |
117 | |
118 | return nullptr; |
119 | } |
120 | |
121 | StringRef APISet::copyString(StringRef String) { |
122 | if (String.empty()) |
123 | return {}; |
124 | |
125 | // No need to allocate memory and copy if the string has already been stored. |
126 | if (Allocator.identifyObject(Ptr: String.data())) |
127 | return String; |
128 | |
129 | void *Ptr = Allocator.Allocate(Size: String.size(), Alignment: 1); |
130 | memcpy(dest: Ptr, src: String.data(), n: String.size()); |
131 | return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); |
132 | } |
133 | |
134 | SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, |
135 | StringRef Source) { |
136 | return SymbolReference(copyString(String: Name), copyString(String: USR), copyString(String: Source)); |
137 | } |
138 | |
139 | void APISet::removeRecord(StringRef USR) { |
140 | auto Result = USRBasedLookupTable.find(Val: USR); |
141 | if (Result != USRBasedLookupTable.end()) { |
142 | auto *Record = Result->getSecond().get(); |
143 | auto &ParentReference = Record->Parent; |
144 | auto *ParentRecord = const_cast<APIRecord *>(ParentReference.Record); |
145 | if (!ParentRecord) |
146 | ParentRecord = findRecordForUSR(USR: ParentReference.USR); |
147 | |
148 | if (auto *ParentCtx = llvm::cast_if_present<RecordContext>(Val: ParentRecord)) { |
149 | ParentCtx->removeFromRecordChain(Record); |
150 | if (auto *RecordAsCtx = llvm::dyn_cast<RecordContext>(Val: Record)) |
151 | ParentCtx->stealRecordChain(Other&: *RecordAsCtx); |
152 | } else { |
153 | auto *It = llvm::find(Range&: TopLevelRecords, Val: Record); |
154 | if (It != TopLevelRecords.end()) |
155 | TopLevelRecords.erase(CI: It); |
156 | if (auto *RecordAsCtx = llvm::dyn_cast<RecordContext>(Val: Record)) { |
157 | for (const auto *Child = RecordAsCtx->First; Child != nullptr; |
158 | Child = Child->getNextInContext()) |
159 | TopLevelRecords.push_back(Elt: Child); |
160 | } |
161 | } |
162 | USRBasedLookupTable.erase(I: Result); |
163 | } |
164 | } |
165 | |
166 | void APISet::removeRecord(APIRecord *Record) { removeRecord(USR: Record->USR); } |
167 | |
168 | APIRecord::~APIRecord() {} |
169 | TagRecord::~TagRecord() {} |
170 | RecordRecord::~RecordRecord() {} |
171 | RecordFieldRecord::~RecordFieldRecord() {} |
172 | ObjCContainerRecord::~ObjCContainerRecord() {} |
173 | ObjCMethodRecord::~ObjCMethodRecord() {} |
174 | ObjCPropertyRecord::~ObjCPropertyRecord() {} |
175 | CXXMethodRecord::~CXXMethodRecord() {} |
176 | |
177 | void GlobalFunctionRecord::anchor() {} |
178 | void GlobalVariableRecord::anchor() {} |
179 | void EnumConstantRecord::anchor() {} |
180 | void EnumRecord::anchor() {} |
181 | void StructFieldRecord::anchor() {} |
182 | void StructRecord::anchor() {} |
183 | void UnionFieldRecord::anchor() {} |
184 | void UnionRecord::anchor() {} |
185 | void CXXFieldRecord::anchor() {} |
186 | void CXXClassRecord::anchor() {} |
187 | void CXXConstructorRecord::anchor() {} |
188 | void CXXDestructorRecord::anchor() {} |
189 | void CXXInstanceMethodRecord::anchor() {} |
190 | void CXXStaticMethodRecord::anchor() {} |
191 | void ObjCInstancePropertyRecord::anchor() {} |
192 | void ObjCClassPropertyRecord::anchor() {} |
193 | void ObjCInstanceVariableRecord::anchor() {} |
194 | void ObjCInstanceMethodRecord::anchor() {} |
195 | void ObjCClassMethodRecord::anchor() {} |
196 | void ObjCCategoryRecord::anchor() {} |
197 | void ObjCInterfaceRecord::anchor() {} |
198 | void ObjCProtocolRecord::anchor() {} |
199 | void MacroDefinitionRecord::anchor() {} |
200 | void TypedefRecord::anchor() {} |
201 |
Definitions
- SymbolReference
- castFromRecordContext
- castToRecordContext
- IsWellFormed
- stealRecordChain
- addToRecordChain
- removeFromRecordChain
- findRecordForUSR
- copyString
- createSymbolReference
- removeRecord
- removeRecord
- ~APIRecord
- ~TagRecord
- ~RecordRecord
- ~RecordFieldRecord
- ~ObjCContainerRecord
- ~ObjCMethodRecord
- ~ObjCPropertyRecord
- ~CXXMethodRecord
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
- anchor
Improve your Profiling and Debugging skills
Find out more