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>(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(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(String.data())) 127 return String; 128 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()); 132 } 133 134 SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, 135 StringRef Source) { 136 return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); 137 } 138 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); 145 if (!ParentRecord) 146 ParentRecord = findRecordForUSR(ParentReference.USR); 147 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); 152 } else { 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); 160 } 161 } 162 USRBasedLookupTable.erase(Result); 163 } 164 } 165 166 void APISet::removeRecord(APIRecord *Record) { removeRecord(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