1 //===- ExtractAPI/API.cpp ---------------------------------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
10 /// This file implements the APIRecord and derived record structs,
11 /// and the APISet class.
13 //===----------------------------------------------------------------------===//
15 #include "clang/ExtractAPI/API.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/ErrorHandling.h"
20 using namespace clang::extractapi
;
23 SymbolReference::SymbolReference(const APIRecord
*R
)
24 : Name(R
->Name
), USR(R
->USR
), Record(R
) {}
26 APIRecord
*APIRecord::castFromRecordContext(const RecordContext
*Ctx
) {
27 switch (Ctx
->getKind()) {
28 #define RECORD_CONTEXT(CLASS, KIND) \
30 return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx));
31 #include "clang/ExtractAPI/APIRecords.inc"
34 // llvm_unreachable("RecordContext derived class isn't propertly
39 RecordContext
*APIRecord::castToRecordContext(const APIRecord
*Record
) {
42 switch (Record
->getKind()) {
43 #define RECORD_CONTEXT(CLASS, KIND) \
45 return static_cast<CLASS *>(const_cast<APIRecord *>(Record));
46 #include "clang/ExtractAPI/APIRecords.inc"
49 // llvm_unreachable("RecordContext derived class isn't propertly
54 bool RecordContext::IsWellFormed() const {
55 // Check that First and Last are both null or both non-null.
56 return (First
== nullptr) == (Last
== nullptr);
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)
65 // If we don't have an empty chain append Other's chain into ours.
67 Last
->NextInContext
= Other
.First
;
73 for (auto *StolenRecord
= Other
.First
; StolenRecord
!= nullptr;
74 StolenRecord
= StolenRecord
->getNextInContext())
75 StolenRecord
->Parent
= SymbolReference(cast
<APIRecord
>(this));
77 // Delete Other's chain to ensure we don't accidentally traverse it.
78 Other
.First
= nullptr;
82 void RecordContext::addToRecordChain(APIRecord
*Record
) const {
83 assert(IsWellFormed());
90 Last
->NextInContext
= Record
;
94 void RecordContext::removeFromRecordChain(APIRecord
*Record
) {
95 APIRecord
*Prev
= nullptr;
96 for (APIRecord
*Curr
= First
; Curr
!= Record
; Curr
= Curr
->NextInContext
)
100 Prev
->NextInContext
= Record
->NextInContext
;
102 First
= Record
->NextInContext
;
107 Record
->NextInContext
= nullptr;
110 APIRecord
*APISet::findRecordForUSR(StringRef USR
) const {
114 auto FindIt
= USRBasedLookupTable
.find(USR
);
115 if (FindIt
!= USRBasedLookupTable
.end())
116 return FindIt
->getSecond().get();
121 StringRef
APISet::copyString(StringRef String
) {
125 // No need to allocate memory and copy if the string has already been stored.
126 if (Allocator
.identifyObject(String
.data()))
129 void *Ptr
= Allocator
.Allocate(String
.size(), 1);
130 memcpy(Ptr
, String
.data(), String
.size());
131 return StringRef(reinterpret_cast<const char *>(Ptr
), String
.size());
134 SymbolReference
APISet::createSymbolReference(StringRef Name
, StringRef USR
,
136 return SymbolReference(copyString(Name
), copyString(USR
), copyString(Source
));
139 void APISet::removeRecord(StringRef USR
) {
140 auto Result
= USRBasedLookupTable
.find(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
);
146 ParentRecord
= findRecordForUSR(ParentReference
.USR
);
148 if (auto *ParentCtx
= llvm::cast_if_present
<RecordContext
>(ParentRecord
)) {
149 ParentCtx
->removeFromRecordChain(Record
);
150 if (auto *RecordAsCtx
= llvm::dyn_cast
<RecordContext
>(Record
))
151 ParentCtx
->stealRecordChain(*RecordAsCtx
);
153 auto *It
= llvm::find(TopLevelRecords
, Record
);
154 if (It
!= TopLevelRecords
.end())
155 TopLevelRecords
.erase(It
);
156 if (auto *RecordAsCtx
= llvm::dyn_cast
<RecordContext
>(Record
)) {
157 for (const auto *Child
= RecordAsCtx
->First
; Child
!= nullptr;
158 Child
= Child
->getNextInContext())
159 TopLevelRecords
.push_back(Child
);
162 USRBasedLookupTable
.erase(Result
);
166 void APISet::removeRecord(APIRecord
*Record
) { removeRecord(Record
->USR
); }
168 APIRecord::~APIRecord() {}
169 TagRecord::~TagRecord() {}
170 RecordRecord::~RecordRecord() {}
171 RecordFieldRecord::~RecordFieldRecord() {}
172 ObjCContainerRecord::~ObjCContainerRecord() {}
173 ObjCMethodRecord::~ObjCMethodRecord() {}
174 ObjCPropertyRecord::~ObjCPropertyRecord() {}
175 CXXMethodRecord::~CXXMethodRecord() {}
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() {}