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
20using namespace clang::extractapi;
21using namespace llvm;
22
23SymbolReference::SymbolReference(const APIRecord *R)
24 : Name(R->Name), USR(R->USR), Record(R) {}
25
26APIRecord *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
39RecordContext *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
54bool RecordContext::IsWellFormed() const {
55 // Check that First and Last are both null or both non-null.
56 return (First == nullptr) == (Last == nullptr);
57}
58
59void 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
82void 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
94void 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
110APIRecord *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
121StringRef 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
134SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR,
135 StringRef Source) {
136 return SymbolReference(copyString(String: Name), copyString(String: USR), copyString(String: Source));
137}
138
139void 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
166void APISet::removeRecord(APIRecord *Record) { removeRecord(USR: Record->USR); }
167
168APIRecord::~APIRecord() {}
169TagRecord::~TagRecord() {}
170RecordRecord::~RecordRecord() {}
171RecordFieldRecord::~RecordFieldRecord() {}
172ObjCContainerRecord::~ObjCContainerRecord() {}
173ObjCMethodRecord::~ObjCMethodRecord() {}
174ObjCPropertyRecord::~ObjCPropertyRecord() {}
175CXXMethodRecord::~CXXMethodRecord() {}
176
177void GlobalFunctionRecord::anchor() {}
178void GlobalVariableRecord::anchor() {}
179void EnumConstantRecord::anchor() {}
180void EnumRecord::anchor() {}
181void StructFieldRecord::anchor() {}
182void StructRecord::anchor() {}
183void UnionFieldRecord::anchor() {}
184void UnionRecord::anchor() {}
185void CXXFieldRecord::anchor() {}
186void CXXClassRecord::anchor() {}
187void CXXConstructorRecord::anchor() {}
188void CXXDestructorRecord::anchor() {}
189void CXXInstanceMethodRecord::anchor() {}
190void CXXStaticMethodRecord::anchor() {}
191void ObjCInstancePropertyRecord::anchor() {}
192void ObjCClassPropertyRecord::anchor() {}
193void ObjCInstanceVariableRecord::anchor() {}
194void ObjCInstanceMethodRecord::anchor() {}
195void ObjCClassMethodRecord::anchor() {}
196void ObjCCategoryRecord::anchor() {}
197void ObjCInterfaceRecord::anchor() {}
198void ObjCProtocolRecord::anchor() {}
199void MacroDefinitionRecord::anchor() {}
200void TypedefRecord::anchor() {}
201

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/ExtractAPI/API.cpp