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(DenseMap<StringRef, APIRecord *> &USRLookupTable, 31 APISet::RecordMap<RecordTy> &RecordMap, 32 StringRef USR, CtorArgsTy &&...CtorArgs) { 33 auto Result = RecordMap.insert({USR, nullptr}); 34 35 // Create the record if it does not already exist 36 if (Result.second) 37 Result.first->second = 38 std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...); 39 40 auto *Record = Result.first->second.get(); 41 USRLookupTable.insert({USR, Record}); 42 return Record; 43 } 44 45 } // namespace 46 47 GlobalVariableRecord * 48 APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, 49 AvailabilitySet Availabilities, LinkageInfo Linkage, 50 const DocComment &Comment, DeclarationFragments Fragments, 51 DeclarationFragments SubHeading, bool IsFromSystemHeader) { 52 return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc, 53 std::move(Availabilities), Linkage, Comment, 54 Fragments, SubHeading, IsFromSystemHeader); 55 } 56 57 GlobalFunctionRecord *APISet::addGlobalFunction( 58 StringRef Name, StringRef USR, PresumedLoc Loc, 59 AvailabilitySet Availabilities, LinkageInfo Linkage, 60 const DocComment &Comment, DeclarationFragments Fragments, 61 DeclarationFragments SubHeading, FunctionSignature Signature, 62 bool IsFromSystemHeader) { 63 return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, 64 std::move(Availabilities), Linkage, Comment, 65 Fragments, SubHeading, Signature, 66 IsFromSystemHeader); 67 } 68 69 EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, 70 StringRef USR, PresumedLoc Loc, 71 AvailabilitySet Availabilities, 72 const DocComment &Comment, 73 DeclarationFragments Declaration, 74 DeclarationFragments SubHeading, 75 bool IsFromSystemHeader) { 76 auto Record = std::make_unique<EnumConstantRecord>( 77 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 78 SubHeading, IsFromSystemHeader); 79 Record->ParentInformation = APIRecord::HierarchyInformation( 80 Enum->USR, Enum->Name, Enum->getKind(), Enum); 81 USRBasedLookupTable.insert({USR, Record.get()}); 82 return Enum->Constants.emplace_back(std::move(Record)).get(); 83 } 84 85 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, 86 AvailabilitySet Availabilities, 87 const DocComment &Comment, 88 DeclarationFragments Declaration, 89 DeclarationFragments SubHeading, 90 bool IsFromSystemHeader) { 91 return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, 92 std::move(Availabilities), Comment, Declaration, 93 SubHeading, IsFromSystemHeader); 94 } 95 96 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name, 97 StringRef USR, PresumedLoc Loc, 98 AvailabilitySet Availabilities, 99 const DocComment &Comment, 100 DeclarationFragments Declaration, 101 DeclarationFragments SubHeading, 102 bool IsFromSystemHeader) { 103 auto Record = std::make_unique<StructFieldRecord>( 104 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 105 SubHeading, IsFromSystemHeader); 106 Record->ParentInformation = APIRecord::HierarchyInformation( 107 Struct->USR, Struct->Name, Struct->getKind(), Struct); 108 USRBasedLookupTable.insert({USR, Record.get()}); 109 return Struct->Fields.emplace_back(std::move(Record)).get(); 110 } 111 112 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, 113 AvailabilitySet Availabilities, 114 const DocComment &Comment, 115 DeclarationFragments Declaration, 116 DeclarationFragments SubHeading, 117 bool IsFromSystemHeader) { 118 return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc, 119 std::move(Availabilities), Comment, Declaration, 120 SubHeading, IsFromSystemHeader); 121 } 122 123 StaticFieldRecord * 124 APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, 125 AvailabilitySet Availabilities, LinkageInfo Linkage, 126 const DocComment &Comment, 127 DeclarationFragments Declaration, 128 DeclarationFragments SubHeading, SymbolReference Context, 129 AccessControl Access, bool IsFromSystemHeader) { 130 return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc, 131 std::move(Availabilities), Linkage, Comment, 132 Declaration, SubHeading, Context, Access, 133 IsFromSystemHeader); 134 } 135 136 CXXFieldRecord * 137 APISet::addCXXField(CXXClassRecord *CXXClass, StringRef Name, StringRef USR, 138 PresumedLoc Loc, AvailabilitySet Availabilities, 139 const DocComment &Comment, DeclarationFragments Declaration, 140 DeclarationFragments SubHeading, AccessControl Access, 141 bool IsFromSystemHeader) { 142 auto Record = std::make_unique<CXXFieldRecord>( 143 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 144 SubHeading, Access, IsFromSystemHeader); 145 Record->ParentInformation = APIRecord::HierarchyInformation( 146 CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass); 147 USRBasedLookupTable.insert({USR, Record.get()}); 148 return CXXClass->Fields.emplace_back(std::move(Record)).get(); 149 } 150 151 CXXClassRecord * 152 APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc, 153 AvailabilitySet Availabilities, const DocComment &Comment, 154 DeclarationFragments Declaration, 155 DeclarationFragments SubHeading, APIRecord::RecordKind Kind, 156 bool IsFromSystemHeader) { 157 return addTopLevelRecord(USRBasedLookupTable, CXXClasses, USR, Name, Loc, 158 std::move(Availabilities), Comment, Declaration, 159 SubHeading, Kind, IsFromSystemHeader); 160 } 161 162 CXXMethodRecord *APISet::addCXXMethod( 163 CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR, 164 PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment, 165 DeclarationFragments Declaration, DeclarationFragments SubHeading, 166 FunctionSignature Signature, bool IsStatic, AccessControl Access, 167 bool IsFromSystemHeader) { 168 std::unique_ptr<CXXMethodRecord> Record; 169 if (IsStatic) 170 Record = std::make_unique<CXXStaticMethodRecord>( 171 USR, Name, Loc, std::move(Availability), Comment, Declaration, 172 SubHeading, Signature, Access, IsFromSystemHeader); 173 else 174 Record = std::make_unique<CXXInstanceMethodRecord>( 175 USR, Name, Loc, std::move(Availability), Comment, Declaration, 176 SubHeading, Signature, Access, IsFromSystemHeader); 177 178 Record->ParentInformation = APIRecord::HierarchyInformation( 179 CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), 180 CXXClassRecord); 181 USRBasedLookupTable.insert({USR, Record.get()}); 182 return CXXClassRecord->Methods.emplace_back(std::move(Record)).get(); 183 } 184 185 CXXMethodRecord *APISet::addCXXSpecialMethod( 186 CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR, 187 PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment, 188 DeclarationFragments Declaration, DeclarationFragments SubHeading, 189 FunctionSignature Signature, bool IsConstructor, AccessControl Access, 190 bool IsFromSystemHeader) { 191 std::unique_ptr<CXXMethodRecord> Record; 192 if (IsConstructor) 193 Record = std::make_unique<CXXConstructorRecord>( 194 USR, Name, Loc, std::move(Availability), Comment, Declaration, 195 SubHeading, Signature, Access, IsFromSystemHeader); 196 else 197 Record = std::make_unique<CXXDestructorRecord>( 198 USR, Name, Loc, std::move(Availability), Comment, Declaration, 199 SubHeading, Signature, Access, IsFromSystemHeader); 200 201 Record->ParentInformation = APIRecord::HierarchyInformation( 202 CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), 203 CXXClassRecord); 204 USRBasedLookupTable.insert({USR, Record.get()}); 205 return CXXClassRecord->Methods.emplace_back(std::move(Record)).get(); 206 } 207 208 ObjCCategoryRecord *APISet::addObjCCategory( 209 StringRef Name, StringRef USR, PresumedLoc Loc, 210 AvailabilitySet Availabilities, const DocComment &Comment, 211 DeclarationFragments Declaration, DeclarationFragments SubHeading, 212 SymbolReference Interface, bool IsFromSystemHeader, 213 bool IsFromExternalModule) { 214 // Create the category record. 215 auto *Record = 216 addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, 217 std::move(Availabilities), Comment, Declaration, 218 SubHeading, Interface, IsFromSystemHeader); 219 220 Record->IsFromExternalModule = IsFromExternalModule; 221 222 auto It = ObjCInterfaces.find(Interface.USR); 223 if (It != ObjCInterfaces.end()) 224 It->second->Categories.push_back(Record); 225 226 return Record; 227 } 228 229 ObjCInterfaceRecord * 230 APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, 231 AvailabilitySet Availabilities, LinkageInfo Linkage, 232 const DocComment &Comment, 233 DeclarationFragments Declaration, 234 DeclarationFragments SubHeading, 235 SymbolReference SuperClass, bool IsFromSystemHeader) { 236 return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, 237 std::move(Availabilities), Linkage, Comment, 238 Declaration, SubHeading, SuperClass, 239 IsFromSystemHeader); 240 } 241 242 ObjCMethodRecord *APISet::addObjCMethod( 243 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 244 PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 245 DeclarationFragments Declaration, DeclarationFragments SubHeading, 246 FunctionSignature Signature, bool IsInstanceMethod, 247 bool IsFromSystemHeader) { 248 std::unique_ptr<ObjCMethodRecord> Record; 249 if (IsInstanceMethod) 250 Record = std::make_unique<ObjCInstanceMethodRecord>( 251 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 252 SubHeading, Signature, IsFromSystemHeader); 253 else 254 Record = std::make_unique<ObjCClassMethodRecord>( 255 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 256 SubHeading, Signature, IsFromSystemHeader); 257 258 Record->ParentInformation = APIRecord::HierarchyInformation( 259 Container->USR, Container->Name, Container->getKind(), Container); 260 USRBasedLookupTable.insert({USR, Record.get()}); 261 return Container->Methods.emplace_back(std::move(Record)).get(); 262 } 263 264 ObjCPropertyRecord *APISet::addObjCProperty( 265 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 266 PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 267 DeclarationFragments Declaration, DeclarationFragments SubHeading, 268 ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, 269 StringRef SetterName, bool IsOptional, bool IsInstanceProperty, 270 bool IsFromSystemHeader) { 271 std::unique_ptr<ObjCPropertyRecord> Record; 272 if (IsInstanceProperty) 273 Record = std::make_unique<ObjCInstancePropertyRecord>( 274 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 275 SubHeading, Attributes, GetterName, SetterName, IsOptional, 276 IsFromSystemHeader); 277 else 278 Record = std::make_unique<ObjCClassPropertyRecord>( 279 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 280 SubHeading, Attributes, GetterName, SetterName, IsOptional, 281 IsFromSystemHeader); 282 Record->ParentInformation = APIRecord::HierarchyInformation( 283 Container->USR, Container->Name, Container->getKind(), Container); 284 USRBasedLookupTable.insert({USR, Record.get()}); 285 return Container->Properties.emplace_back(std::move(Record)).get(); 286 } 287 288 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( 289 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 290 PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 291 DeclarationFragments Declaration, DeclarationFragments SubHeading, 292 ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { 293 auto Record = std::make_unique<ObjCInstanceVariableRecord>( 294 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 295 SubHeading, Access, IsFromSystemHeader); 296 Record->ParentInformation = APIRecord::HierarchyInformation( 297 Container->USR, Container->Name, Container->getKind(), Container); 298 USRBasedLookupTable.insert({USR, Record.get()}); 299 return Container->Ivars.emplace_back(std::move(Record)).get(); 300 } 301 302 ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, 303 PresumedLoc Loc, 304 AvailabilitySet Availabilities, 305 const DocComment &Comment, 306 DeclarationFragments Declaration, 307 DeclarationFragments SubHeading, 308 bool IsFromSystemHeader) { 309 return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, 310 std::move(Availabilities), Comment, Declaration, 311 SubHeading, IsFromSystemHeader); 312 } 313 314 MacroDefinitionRecord * 315 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, 316 DeclarationFragments Declaration, 317 DeclarationFragments SubHeading, 318 bool IsFromSystemHeader) { 319 return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, 320 Declaration, SubHeading, IsFromSystemHeader); 321 } 322 323 TypedefRecord * 324 APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, 325 AvailabilitySet Availabilities, const DocComment &Comment, 326 DeclarationFragments Declaration, 327 DeclarationFragments SubHeading, 328 SymbolReference UnderlyingType, bool IsFromSystemHeader) { 329 return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, 330 std::move(Availabilities), Comment, Declaration, 331 SubHeading, UnderlyingType, IsFromSystemHeader); 332 } 333 334 APIRecord *APISet::findRecordForUSR(StringRef USR) const { 335 if (USR.empty()) 336 return nullptr; 337 338 return USRBasedLookupTable.lookup(USR); 339 } 340 341 StringRef APISet::recordUSR(const Decl *D) { 342 SmallString<128> USR; 343 index::generateUSRForDecl(D, USR); 344 return copyString(USR); 345 } 346 347 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, 348 const SourceManager &SM) { 349 SmallString<128> USR; 350 index::generateUSRForMacro(Name, SL, SM, USR); 351 return copyString(USR); 352 } 353 354 StringRef APISet::copyString(StringRef String) { 355 if (String.empty()) 356 return {}; 357 358 // No need to allocate memory and copy if the string has already been stored. 359 if (StringAllocator.identifyObject(String.data())) 360 return String; 361 362 void *Ptr = StringAllocator.Allocate(String.size(), 1); 363 memcpy(Ptr, String.data(), String.size()); 364 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 365 } 366 367 APIRecord::~APIRecord() {} 368 ObjCContainerRecord::~ObjCContainerRecord() {} 369 ObjCMethodRecord::~ObjCMethodRecord() {} 370 ObjCPropertyRecord::~ObjCPropertyRecord() {} 371 CXXMethodRecord::~CXXMethodRecord() {} 372 373 void GlobalFunctionRecord::anchor() {} 374 void GlobalVariableRecord::anchor() {} 375 void EnumConstantRecord::anchor() {} 376 void EnumRecord::anchor() {} 377 void StructFieldRecord::anchor() {} 378 void StructRecord::anchor() {} 379 void CXXFieldRecord::anchor() {} 380 void CXXClassRecord::anchor() {} 381 void CXXConstructorRecord::anchor() {} 382 void CXXDestructorRecord::anchor() {} 383 void CXXInstanceMethodRecord::anchor() {} 384 void CXXStaticMethodRecord::anchor() {} 385 void ObjCInstancePropertyRecord::anchor() {} 386 void ObjCClassPropertyRecord::anchor() {} 387 void ObjCInstanceVariableRecord::anchor() {} 388 void ObjCInstanceMethodRecord::anchor() {} 389 void ObjCClassMethodRecord::anchor() {} 390 void ObjCCategoryRecord::anchor() {} 391 void ObjCInterfaceRecord::anchor() {} 392 void ObjCProtocolRecord::anchor() {} 393 void MacroDefinitionRecord::anchor() {} 394 void TypedefRecord::anchor() {} 395