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/CommentCommandTraits.h" 17 #include "clang/AST/CommentLexer.h" 18 #include "clang/AST/RawCommentList.h" 19 #include "clang/Index/USRGeneration.h" 20 #include "llvm/ADT/STLFunctionalExtras.h" 21 #include "llvm/ADT/StringRef.h" 22 #include <memory> 23 24 using namespace clang::extractapi; 25 using namespace llvm; 26 27 namespace { 28 29 template <typename RecordTy, typename... CtorArgsTy> 30 RecordTy *addTopLevelRecord(APISet::RecordMap<RecordTy> &RecordMap, 31 StringRef Name, CtorArgsTy &&...CtorArgs) { 32 auto Result = RecordMap.insert({Name, nullptr}); 33 34 // Create the record if it does not already exist 35 if (Result.second) 36 Result.first->second = 37 std::make_unique<RecordTy>(Name, std::forward<CtorArgsTy>(CtorArgs)...); 38 39 return Result.first->second.get(); 40 } 41 42 } // namespace 43 44 GlobalRecord *APISet::addGlobal(GVKind Kind, StringRef Name, StringRef USR, 45 PresumedLoc Loc, 46 const AvailabilityInfo &Availability, 47 LinkageInfo Linkage, const DocComment &Comment, 48 DeclarationFragments Fragments, 49 DeclarationFragments SubHeading, 50 FunctionSignature Signature) { 51 return addTopLevelRecord(Globals, Name, USR, Loc, Availability, Linkage, 52 Comment, Fragments, SubHeading, Kind, Signature); 53 } 54 55 GlobalRecord * 56 APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, 57 const AvailabilityInfo &Availability, LinkageInfo Linkage, 58 const DocComment &Comment, DeclarationFragments Fragments, 59 DeclarationFragments SubHeading) { 60 return addGlobal(GVKind::Variable, Name, USR, Loc, Availability, Linkage, 61 Comment, Fragments, SubHeading, {}); 62 } 63 64 GlobalRecord * 65 APISet::addFunction(StringRef Name, StringRef USR, PresumedLoc Loc, 66 const AvailabilityInfo &Availability, LinkageInfo Linkage, 67 const DocComment &Comment, DeclarationFragments Fragments, 68 DeclarationFragments SubHeading, 69 FunctionSignature Signature) { 70 return addGlobal(GVKind::Function, Name, USR, Loc, Availability, Linkage, 71 Comment, Fragments, SubHeading, Signature); 72 } 73 74 EnumConstantRecord *APISet::addEnumConstant( 75 EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc, 76 const AvailabilityInfo &Availability, const DocComment &Comment, 77 DeclarationFragments Declaration, DeclarationFragments SubHeading) { 78 auto Record = std::make_unique<EnumConstantRecord>( 79 Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 80 return Enum->Constants.emplace_back(std::move(Record)).get(); 81 } 82 83 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, 84 const AvailabilityInfo &Availability, 85 const DocComment &Comment, 86 DeclarationFragments Declaration, 87 DeclarationFragments SubHeading) { 88 return addTopLevelRecord(Enums, Name, USR, Loc, Availability, Comment, 89 Declaration, SubHeading); 90 } 91 92 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name, 93 StringRef USR, PresumedLoc Loc, 94 const AvailabilityInfo &Availability, 95 const DocComment &Comment, 96 DeclarationFragments Declaration, 97 DeclarationFragments SubHeading) { 98 auto Record = std::make_unique<StructFieldRecord>( 99 Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 100 return Struct->Fields.emplace_back(std::move(Record)).get(); 101 } 102 103 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, 104 const AvailabilityInfo &Availability, 105 const DocComment &Comment, 106 DeclarationFragments Declaration, 107 DeclarationFragments SubHeading) { 108 return addTopLevelRecord(Structs, Name, USR, Loc, Availability, Comment, 109 Declaration, SubHeading); 110 } 111 112 ObjCCategoryRecord *APISet::addObjCCategory( 113 StringRef Name, StringRef USR, PresumedLoc Loc, 114 const AvailabilityInfo &Availability, const DocComment &Comment, 115 DeclarationFragments Declaration, DeclarationFragments SubHeading, 116 SymbolReference Interface) { 117 // Create the category record. 118 auto *Record = addTopLevelRecord(ObjCCategories, Name, USR, Loc, Availability, 119 Comment, Declaration, SubHeading, Interface); 120 121 // If this category is extending a known interface, associate it with the 122 // ObjCInterfaceRecord. 123 auto It = ObjCInterfaces.find(Interface.Name); 124 if (It != ObjCInterfaces.end()) 125 It->second->Categories.push_back(Record); 126 127 return Record; 128 } 129 130 ObjCInterfaceRecord *APISet::addObjCInterface( 131 StringRef Name, StringRef USR, PresumedLoc Loc, 132 const AvailabilityInfo &Availability, LinkageInfo Linkage, 133 const DocComment &Comment, DeclarationFragments Declaration, 134 DeclarationFragments SubHeading, SymbolReference SuperClass) { 135 return addTopLevelRecord(ObjCInterfaces, Name, USR, Loc, Availability, 136 Linkage, Comment, Declaration, SubHeading, 137 SuperClass); 138 } 139 140 ObjCMethodRecord *APISet::addObjCMethod( 141 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 142 PresumedLoc Loc, const AvailabilityInfo &Availability, 143 const DocComment &Comment, DeclarationFragments Declaration, 144 DeclarationFragments SubHeading, FunctionSignature Signature, 145 bool IsInstanceMethod) { 146 auto Record = std::make_unique<ObjCMethodRecord>( 147 Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Signature, 148 IsInstanceMethod); 149 return Container->Methods.emplace_back(std::move(Record)).get(); 150 } 151 152 ObjCPropertyRecord *APISet::addObjCProperty( 153 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 154 PresumedLoc Loc, const AvailabilityInfo &Availability, 155 const DocComment &Comment, DeclarationFragments Declaration, 156 DeclarationFragments SubHeading, 157 ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, 158 StringRef SetterName, bool IsOptional) { 159 auto Record = std::make_unique<ObjCPropertyRecord>( 160 Name, USR, Loc, Availability, Comment, Declaration, SubHeading, 161 Attributes, GetterName, SetterName, IsOptional); 162 return Container->Properties.emplace_back(std::move(Record)).get(); 163 } 164 165 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( 166 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 167 PresumedLoc Loc, const AvailabilityInfo &Availability, 168 const DocComment &Comment, DeclarationFragments Declaration, 169 DeclarationFragments SubHeading, 170 ObjCInstanceVariableRecord::AccessControl Access) { 171 auto Record = std::make_unique<ObjCInstanceVariableRecord>( 172 Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Access); 173 return Container->Ivars.emplace_back(std::move(Record)).get(); 174 } 175 176 ObjCProtocolRecord *APISet::addObjCProtocol( 177 StringRef Name, StringRef USR, PresumedLoc Loc, 178 const AvailabilityInfo &Availability, const DocComment &Comment, 179 DeclarationFragments Declaration, DeclarationFragments SubHeading) { 180 return addTopLevelRecord(ObjCProtocols, Name, USR, Loc, Availability, Comment, 181 Declaration, SubHeading); 182 } 183 184 MacroDefinitionRecord * 185 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, 186 DeclarationFragments Declaration, 187 DeclarationFragments SubHeading) { 188 return addTopLevelRecord(Macros, Name, USR, Loc, Declaration, SubHeading); 189 } 190 191 TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR, 192 PresumedLoc Loc, 193 const AvailabilityInfo &Availability, 194 const DocComment &Comment, 195 DeclarationFragments Declaration, 196 DeclarationFragments SubHeading, 197 SymbolReference UnderlyingType) { 198 return addTopLevelRecord(Typedefs, Name, USR, Loc, Availability, Comment, 199 Declaration, SubHeading, UnderlyingType); 200 } 201 202 StringRef APISet::recordUSR(const Decl *D) { 203 SmallString<128> USR; 204 index::generateUSRForDecl(D, USR); 205 return copyString(USR); 206 } 207 208 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, 209 const SourceManager &SM) { 210 SmallString<128> USR; 211 index::generateUSRForMacro(Name, SL, SM, USR); 212 return copyString(USR); 213 } 214 215 StringRef APISet::copyString(StringRef String) { 216 if (String.empty()) 217 return {}; 218 219 // No need to allocate memory and copy if the string has already been stored. 220 if (StringAllocator.identifyObject(String.data())) 221 return String; 222 223 void *Ptr = StringAllocator.Allocate(String.size(), 1); 224 memcpy(Ptr, String.data(), String.size()); 225 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 226 } 227 228 APIRecord::~APIRecord() {} 229 230 ObjCContainerRecord::~ObjCContainerRecord() {} 231 232 void GlobalRecord::anchor() {} 233 void EnumConstantRecord::anchor() {} 234 void EnumRecord::anchor() {} 235 void StructFieldRecord::anchor() {} 236 void StructRecord::anchor() {} 237 void ObjCPropertyRecord::anchor() {} 238 void ObjCInstanceVariableRecord::anchor() {} 239 void ObjCMethodRecord::anchor() {} 240 void ObjCCategoryRecord::anchor() {} 241 void ObjCInterfaceRecord::anchor() {} 242 void ObjCProtocolRecord::anchor() {} 243 void MacroDefinitionRecord::anchor() {} 244 void TypedefRecord::anchor() {} 245