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 "clang/AST/RawCommentList.h" 17 #include "clang/Index/USRGeneration.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/Support/ErrorHandling.h" 20 #include <memory> 21 22 using namespace clang::extractapi; 23 using namespace llvm; 24 25 SymbolReference::SymbolReference(const APIRecord *R) 26 : Name(R->Name), USR(R->USR), Record(R) {} 27 28 APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { 29 switch (Ctx->getKind()) { 30 #define RECORD_CONTEXT(CLASS, KIND) \ 31 case KIND: \ 32 return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx)); 33 #include "clang/ExtractAPI/APIRecords.inc" 34 default: 35 return nullptr; 36 // llvm_unreachable("RecordContext derived class isn't propertly 37 // implemented"); 38 } 39 } 40 41 RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { 42 if (!Record) 43 return nullptr; 44 switch (Record->getKind()) { 45 #define RECORD_CONTEXT(CLASS, KIND) \ 46 case KIND: \ 47 return static_cast<CLASS *>(const_cast<APIRecord *>(Record)); 48 #include "clang/ExtractAPI/APIRecords.inc" 49 default: 50 return nullptr; 51 // llvm_unreachable("RecordContext derived class isn't propertly 52 // implemented"); 53 } 54 } 55 56 bool RecordContext::IsWellFormed() const { 57 // Check that First and Last are both null or both non-null. 58 return (First == nullptr) == (Last == nullptr); 59 } 60 61 void RecordContext::stealRecordChain(RecordContext &Other) { 62 assert(IsWellFormed()); 63 // If we don't have an empty chain append Other's chain into ours. 64 if (First) 65 Last->NextInContext = Other.First; 66 else 67 First = Other.First; 68 69 Last = Other.Last; 70 71 // Delete Other's chain to ensure we don't accidentally traverse it. 72 Other.First = nullptr; 73 Other.Last = nullptr; 74 } 75 76 void RecordContext::addToRecordChain(APIRecord *Record) const { 77 assert(IsWellFormed()); 78 if (!First) { 79 First = Record; 80 Last = Record; 81 return; 82 } 83 84 Last->NextInContext = Record; 85 Last = Record; 86 } 87 88 APIRecord *APISet::findRecordForUSR(StringRef USR) const { 89 if (USR.empty()) 90 return nullptr; 91 92 auto FindIt = USRBasedLookupTable.find(USR); 93 if (FindIt != USRBasedLookupTable.end()) 94 return FindIt->getSecond().get(); 95 96 return nullptr; 97 } 98 99 StringRef APISet::copyString(StringRef String) { 100 if (String.empty()) 101 return {}; 102 103 // No need to allocate memory and copy if the string has already been stored. 104 if (Allocator.identifyObject(String.data())) 105 return String; 106 107 void *Ptr = Allocator.Allocate(String.size(), 1); 108 memcpy(Ptr, String.data(), String.size()); 109 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 110 } 111 112 SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, 113 StringRef Source) { 114 return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); 115 } 116 117 APIRecord::~APIRecord() {} 118 TagRecord::~TagRecord() {} 119 RecordRecord::~RecordRecord() {} 120 RecordFieldRecord::~RecordFieldRecord() {} 121 ObjCContainerRecord::~ObjCContainerRecord() {} 122 ObjCMethodRecord::~ObjCMethodRecord() {} 123 ObjCPropertyRecord::~ObjCPropertyRecord() {} 124 CXXMethodRecord::~CXXMethodRecord() {} 125 126 void GlobalFunctionRecord::anchor() {} 127 void GlobalVariableRecord::anchor() {} 128 void EnumConstantRecord::anchor() {} 129 void EnumRecord::anchor() {} 130 void StructFieldRecord::anchor() {} 131 void StructRecord::anchor() {} 132 void UnionFieldRecord::anchor() {} 133 void UnionRecord::anchor() {} 134 void CXXFieldRecord::anchor() {} 135 void CXXClassRecord::anchor() {} 136 void CXXConstructorRecord::anchor() {} 137 void CXXDestructorRecord::anchor() {} 138 void CXXInstanceMethodRecord::anchor() {} 139 void CXXStaticMethodRecord::anchor() {} 140 void ObjCInstancePropertyRecord::anchor() {} 141 void ObjCClassPropertyRecord::anchor() {} 142 void ObjCInstanceVariableRecord::anchor() {} 143 void ObjCInstanceMethodRecord::anchor() {} 144 void ObjCClassMethodRecord::anchor() {} 145 void ObjCCategoryRecord::anchor() {} 146 void ObjCInterfaceRecord::anchor() {} 147 void ObjCProtocolRecord::anchor() {} 148 void MacroDefinitionRecord::anchor() {} 149 void TypedefRecord::anchor() {} 150