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 GlobalVariableTemplateRecord *APISet::addGlobalVariableTemplate( 58 StringRef Name, StringRef USR, PresumedLoc Loc, 59 AvailabilitySet Availability, LinkageInfo Linkage, 60 const DocComment &Comment, DeclarationFragments Declaration, 61 DeclarationFragments SubHeading, Template Template, 62 bool IsFromSystemHeader) { 63 return addTopLevelRecord(USRBasedLookupTable, GlobalVariableTemplates, USR, 64 Name, Loc, std::move(Availability), Linkage, Comment, 65 Declaration, SubHeading, Template, 66 IsFromSystemHeader); 67 } 68 69 GlobalFunctionRecord *APISet::addGlobalFunction( 70 StringRef Name, StringRef USR, PresumedLoc Loc, 71 AvailabilitySet Availabilities, LinkageInfo Linkage, 72 const DocComment &Comment, DeclarationFragments Fragments, 73 DeclarationFragments SubHeading, FunctionSignature Signature, 74 bool IsFromSystemHeader) { 75 return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, 76 std::move(Availabilities), Linkage, Comment, 77 Fragments, SubHeading, Signature, 78 IsFromSystemHeader); 79 } 80 81 GlobalFunctionTemplateRecord *APISet::addGlobalFunctionTemplate( 82 StringRef Name, StringRef USR, PresumedLoc Loc, 83 AvailabilitySet Availability, LinkageInfo Linkage, 84 const DocComment &Comment, DeclarationFragments Declaration, 85 DeclarationFragments SubHeading, FunctionSignature Signature, 86 Template Template, bool IsFromSystemHeader) { 87 return addTopLevelRecord(USRBasedLookupTable, GlobalFunctionTemplates, USR, 88 Name, Loc, std::move(Availability), Linkage, Comment, 89 Declaration, SubHeading, Signature, Template, 90 IsFromSystemHeader); 91 } 92 93 GlobalFunctionTemplateSpecializationRecord * 94 APISet::addGlobalFunctionTemplateSpecialization( 95 StringRef Name, StringRef USR, PresumedLoc Loc, 96 AvailabilitySet Availability, LinkageInfo Linkage, 97 const DocComment &Comment, DeclarationFragments Declaration, 98 DeclarationFragments SubHeading, FunctionSignature Signature, 99 bool IsFromSystemHeader) { 100 return addTopLevelRecord( 101 USRBasedLookupTable, GlobalFunctionTemplateSpecializations, USR, Name, 102 Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, 103 Signature, IsFromSystemHeader); 104 } 105 106 EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, 107 StringRef USR, PresumedLoc Loc, 108 AvailabilitySet Availabilities, 109 const DocComment &Comment, 110 DeclarationFragments Declaration, 111 DeclarationFragments SubHeading, 112 bool IsFromSystemHeader) { 113 auto Record = std::make_unique<EnumConstantRecord>( 114 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 115 SubHeading, IsFromSystemHeader); 116 Record->ParentInformation = APIRecord::HierarchyInformation( 117 Enum->USR, Enum->Name, Enum->getKind(), Enum); 118 USRBasedLookupTable.insert({USR, Record.get()}); 119 return Enum->Constants.emplace_back(std::move(Record)).get(); 120 } 121 122 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, 123 AvailabilitySet Availabilities, 124 const DocComment &Comment, 125 DeclarationFragments Declaration, 126 DeclarationFragments SubHeading, 127 bool IsFromSystemHeader) { 128 return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, 129 std::move(Availabilities), Comment, Declaration, 130 SubHeading, IsFromSystemHeader); 131 } 132 133 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name, 134 StringRef USR, PresumedLoc Loc, 135 AvailabilitySet Availabilities, 136 const DocComment &Comment, 137 DeclarationFragments Declaration, 138 DeclarationFragments SubHeading, 139 bool IsFromSystemHeader) { 140 auto Record = std::make_unique<StructFieldRecord>( 141 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 142 SubHeading, IsFromSystemHeader); 143 Record->ParentInformation = APIRecord::HierarchyInformation( 144 Struct->USR, Struct->Name, Struct->getKind(), Struct); 145 USRBasedLookupTable.insert({USR, Record.get()}); 146 return Struct->Fields.emplace_back(std::move(Record)).get(); 147 } 148 149 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, 150 AvailabilitySet Availabilities, 151 const DocComment &Comment, 152 DeclarationFragments Declaration, 153 DeclarationFragments SubHeading, 154 bool IsFromSystemHeader) { 155 return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc, 156 std::move(Availabilities), Comment, Declaration, 157 SubHeading, IsFromSystemHeader); 158 } 159 160 StaticFieldRecord * 161 APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, 162 AvailabilitySet Availabilities, LinkageInfo Linkage, 163 const DocComment &Comment, 164 DeclarationFragments Declaration, 165 DeclarationFragments SubHeading, SymbolReference Context, 166 AccessControl Access, bool IsFromSystemHeader) { 167 return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc, 168 std::move(Availabilities), Linkage, Comment, 169 Declaration, SubHeading, Context, Access, 170 IsFromSystemHeader); 171 } 172 173 CXXFieldRecord * 174 APISet::addCXXField(CXXClassRecord *CXXClass, StringRef Name, StringRef USR, 175 PresumedLoc Loc, AvailabilitySet Availabilities, 176 const DocComment &Comment, DeclarationFragments Declaration, 177 DeclarationFragments SubHeading, AccessControl Access, 178 bool IsFromSystemHeader) { 179 auto Record = std::make_unique<CXXFieldRecord>( 180 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 181 SubHeading, Access, IsFromSystemHeader); 182 Record->ParentInformation = APIRecord::HierarchyInformation( 183 CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass); 184 USRBasedLookupTable.insert({USR, Record.get()}); 185 return CXXClass->Fields.emplace_back(std::move(Record)).get(); 186 } 187 188 CXXClassRecord * 189 APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc, 190 AvailabilitySet Availabilities, const DocComment &Comment, 191 DeclarationFragments Declaration, 192 DeclarationFragments SubHeading, APIRecord::RecordKind Kind, 193 bool IsFromSystemHeader) { 194 return addTopLevelRecord(USRBasedLookupTable, CXXClasses, USR, Name, Loc, 195 std::move(Availabilities), Comment, Declaration, 196 SubHeading, Kind, IsFromSystemHeader); 197 } 198 199 ClassTemplateRecord *APISet::addClassTemplate( 200 StringRef Name, StringRef USR, PresumedLoc Loc, 201 AvailabilitySet Availability, const DocComment &Comment, 202 DeclarationFragments Declaration, DeclarationFragments SubHeading, 203 Template Template, bool IsFromSystemHeader) { 204 205 return addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc, 206 std::move(Availability), Comment, Declaration, 207 SubHeading, Template, IsFromSystemHeader); 208 } 209 210 ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization( 211 StringRef Name, StringRef USR, PresumedLoc Loc, 212 AvailabilitySet Availability, const DocComment &Comment, 213 DeclarationFragments Declaration, DeclarationFragments SubHeading, 214 bool IsFromSystemHeader) { 215 return addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations, 216 USR, Name, Loc, std::move(Availability), Comment, 217 Declaration, SubHeading, IsFromSystemHeader); 218 } 219 220 ClassTemplatePartialSpecializationRecord * 221 APISet::addClassTemplatePartialSpecialization( 222 StringRef Name, StringRef USR, PresumedLoc Loc, 223 AvailabilitySet Availability, const DocComment &Comment, 224 DeclarationFragments Declaration, DeclarationFragments SubHeading, 225 Template Template, bool IsFromSystemHeader) { 226 return addTopLevelRecord(USRBasedLookupTable, 227 ClassTemplatePartialSpecializations, USR, Name, Loc, 228 std::move(Availability), Comment, Declaration, 229 SubHeading, Template, IsFromSystemHeader); 230 } 231 232 GlobalVariableTemplateSpecializationRecord * 233 APISet::addGlobalVariableTemplateSpecialization( 234 StringRef Name, StringRef USR, PresumedLoc Loc, 235 AvailabilitySet Availability, LinkageInfo Linkage, 236 const DocComment &Comment, DeclarationFragments Declaration, 237 DeclarationFragments SubHeading, bool IsFromSystemHeader) { 238 return addTopLevelRecord(USRBasedLookupTable, 239 GlobalVariableTemplateSpecializations, USR, Name, 240 Loc, std::move(Availability), Linkage, Comment, 241 Declaration, SubHeading, IsFromSystemHeader); 242 } 243 244 GlobalVariableTemplatePartialSpecializationRecord * 245 APISet::addGlobalVariableTemplatePartialSpecialization( 246 StringRef Name, StringRef USR, PresumedLoc Loc, 247 AvailabilitySet Availability, LinkageInfo Linkage, 248 const DocComment &Comment, DeclarationFragments Declaration, 249 DeclarationFragments SubHeading, Template Template, 250 bool IsFromSystemHeader) { 251 return addTopLevelRecord( 252 USRBasedLookupTable, GlobalVariableTemplatePartialSpecializations, USR, 253 Name, Loc, std::move(Availability), Linkage, Comment, Declaration, 254 SubHeading, Template, IsFromSystemHeader); 255 } 256 257 ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR, 258 PresumedLoc Loc, AvailabilitySet Availability, 259 const DocComment &Comment, 260 DeclarationFragments Declaration, 261 DeclarationFragments SubHeading, 262 Template Template, bool IsFromSystemHeader) { 263 return addTopLevelRecord(USRBasedLookupTable, Concepts, USR, Name, Loc, 264 std::move(Availability), Comment, Declaration, 265 SubHeading, Template, IsFromSystemHeader); 266 } 267 268 CXXMethodRecord *APISet::addCXXMethod( 269 CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR, 270 PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment, 271 DeclarationFragments Declaration, DeclarationFragments SubHeading, 272 FunctionSignature Signature, bool IsStatic, AccessControl Access, 273 bool IsFromSystemHeader) { 274 std::unique_ptr<CXXMethodRecord> Record; 275 if (IsStatic) 276 Record = std::make_unique<CXXStaticMethodRecord>( 277 USR, Name, Loc, std::move(Availability), Comment, Declaration, 278 SubHeading, Signature, Access, IsFromSystemHeader); 279 else 280 Record = std::make_unique<CXXInstanceMethodRecord>( 281 USR, Name, Loc, std::move(Availability), Comment, Declaration, 282 SubHeading, Signature, Access, IsFromSystemHeader); 283 284 Record->ParentInformation = APIRecord::HierarchyInformation( 285 CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), 286 CXXClassRecord); 287 USRBasedLookupTable.insert({USR, Record.get()}); 288 return CXXClassRecord->Methods.emplace_back(std::move(Record)).get(); 289 } 290 291 CXXMethodRecord *APISet::addCXXSpecialMethod( 292 CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR, 293 PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment, 294 DeclarationFragments Declaration, DeclarationFragments SubHeading, 295 FunctionSignature Signature, bool IsConstructor, AccessControl Access, 296 bool IsFromSystemHeader) { 297 std::unique_ptr<CXXMethodRecord> Record; 298 if (IsConstructor) 299 Record = std::make_unique<CXXConstructorRecord>( 300 USR, Name, Loc, std::move(Availability), Comment, Declaration, 301 SubHeading, Signature, Access, IsFromSystemHeader); 302 else 303 Record = std::make_unique<CXXDestructorRecord>( 304 USR, Name, Loc, std::move(Availability), Comment, Declaration, 305 SubHeading, Signature, Access, IsFromSystemHeader); 306 307 Record->ParentInformation = APIRecord::HierarchyInformation( 308 CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), 309 CXXClassRecord); 310 USRBasedLookupTable.insert({USR, Record.get()}); 311 return CXXClassRecord->Methods.emplace_back(std::move(Record)).get(); 312 } 313 314 ObjCCategoryRecord *APISet::addObjCCategory( 315 StringRef Name, StringRef USR, PresumedLoc Loc, 316 AvailabilitySet Availabilities, const DocComment &Comment, 317 DeclarationFragments Declaration, DeclarationFragments SubHeading, 318 SymbolReference Interface, bool IsFromSystemHeader, 319 bool IsFromExternalModule) { 320 // Create the category record. 321 auto *Record = 322 addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, 323 std::move(Availabilities), Comment, Declaration, 324 SubHeading, Interface, IsFromSystemHeader); 325 326 Record->IsFromExternalModule = IsFromExternalModule; 327 328 auto It = ObjCInterfaces.find(Interface.USR); 329 if (It != ObjCInterfaces.end()) 330 It->second->Categories.push_back(Record); 331 332 return Record; 333 } 334 335 ObjCInterfaceRecord * 336 APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, 337 AvailabilitySet Availabilities, LinkageInfo Linkage, 338 const DocComment &Comment, 339 DeclarationFragments Declaration, 340 DeclarationFragments SubHeading, 341 SymbolReference SuperClass, bool IsFromSystemHeader) { 342 return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, 343 std::move(Availabilities), Linkage, Comment, 344 Declaration, SubHeading, SuperClass, 345 IsFromSystemHeader); 346 } 347 348 ObjCMethodRecord *APISet::addObjCMethod( 349 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 350 PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 351 DeclarationFragments Declaration, DeclarationFragments SubHeading, 352 FunctionSignature Signature, bool IsInstanceMethod, 353 bool IsFromSystemHeader) { 354 std::unique_ptr<ObjCMethodRecord> Record; 355 if (IsInstanceMethod) 356 Record = std::make_unique<ObjCInstanceMethodRecord>( 357 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 358 SubHeading, Signature, IsFromSystemHeader); 359 else 360 Record = std::make_unique<ObjCClassMethodRecord>( 361 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 362 SubHeading, Signature, IsFromSystemHeader); 363 364 Record->ParentInformation = APIRecord::HierarchyInformation( 365 Container->USR, Container->Name, Container->getKind(), Container); 366 USRBasedLookupTable.insert({USR, Record.get()}); 367 return Container->Methods.emplace_back(std::move(Record)).get(); 368 } 369 370 ObjCPropertyRecord *APISet::addObjCProperty( 371 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 372 PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 373 DeclarationFragments Declaration, DeclarationFragments SubHeading, 374 ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, 375 StringRef SetterName, bool IsOptional, bool IsInstanceProperty, 376 bool IsFromSystemHeader) { 377 std::unique_ptr<ObjCPropertyRecord> Record; 378 if (IsInstanceProperty) 379 Record = std::make_unique<ObjCInstancePropertyRecord>( 380 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 381 SubHeading, Attributes, GetterName, SetterName, IsOptional, 382 IsFromSystemHeader); 383 else 384 Record = std::make_unique<ObjCClassPropertyRecord>( 385 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 386 SubHeading, Attributes, GetterName, SetterName, IsOptional, 387 IsFromSystemHeader); 388 Record->ParentInformation = APIRecord::HierarchyInformation( 389 Container->USR, Container->Name, Container->getKind(), Container); 390 USRBasedLookupTable.insert({USR, Record.get()}); 391 return Container->Properties.emplace_back(std::move(Record)).get(); 392 } 393 394 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( 395 ObjCContainerRecord *Container, StringRef Name, StringRef USR, 396 PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 397 DeclarationFragments Declaration, DeclarationFragments SubHeading, 398 ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { 399 auto Record = std::make_unique<ObjCInstanceVariableRecord>( 400 USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 401 SubHeading, Access, IsFromSystemHeader); 402 Record->ParentInformation = APIRecord::HierarchyInformation( 403 Container->USR, Container->Name, Container->getKind(), Container); 404 USRBasedLookupTable.insert({USR, Record.get()}); 405 return Container->Ivars.emplace_back(std::move(Record)).get(); 406 } 407 408 ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, 409 PresumedLoc Loc, 410 AvailabilitySet Availabilities, 411 const DocComment &Comment, 412 DeclarationFragments Declaration, 413 DeclarationFragments SubHeading, 414 bool IsFromSystemHeader) { 415 return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, 416 std::move(Availabilities), Comment, Declaration, 417 SubHeading, IsFromSystemHeader); 418 } 419 420 MacroDefinitionRecord * 421 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, 422 DeclarationFragments Declaration, 423 DeclarationFragments SubHeading, 424 bool IsFromSystemHeader) { 425 return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, 426 Declaration, SubHeading, IsFromSystemHeader); 427 } 428 429 TypedefRecord * 430 APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, 431 AvailabilitySet Availabilities, const DocComment &Comment, 432 DeclarationFragments Declaration, 433 DeclarationFragments SubHeading, 434 SymbolReference UnderlyingType, bool IsFromSystemHeader) { 435 return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, 436 std::move(Availabilities), Comment, Declaration, 437 SubHeading, UnderlyingType, IsFromSystemHeader); 438 } 439 440 APIRecord *APISet::findRecordForUSR(StringRef USR) const { 441 if (USR.empty()) 442 return nullptr; 443 444 return USRBasedLookupTable.lookup(USR); 445 } 446 447 StringRef APISet::recordUSR(const Decl *D) { 448 SmallString<128> USR; 449 index::generateUSRForDecl(D, USR); 450 return copyString(USR); 451 } 452 453 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, 454 const SourceManager &SM) { 455 SmallString<128> USR; 456 index::generateUSRForMacro(Name, SL, SM, USR); 457 return copyString(USR); 458 } 459 460 StringRef APISet::copyString(StringRef String) { 461 if (String.empty()) 462 return {}; 463 464 // No need to allocate memory and copy if the string has already been stored. 465 if (StringAllocator.identifyObject(String.data())) 466 return String; 467 468 void *Ptr = StringAllocator.Allocate(String.size(), 1); 469 memcpy(Ptr, String.data(), String.size()); 470 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 471 } 472 473 APIRecord::~APIRecord() {} 474 ObjCContainerRecord::~ObjCContainerRecord() {} 475 ObjCMethodRecord::~ObjCMethodRecord() {} 476 ObjCPropertyRecord::~ObjCPropertyRecord() {} 477 CXXMethodRecord::~CXXMethodRecord() {} 478 479 void GlobalFunctionRecord::anchor() {} 480 void GlobalVariableRecord::anchor() {} 481 void EnumConstantRecord::anchor() {} 482 void EnumRecord::anchor() {} 483 void StructFieldRecord::anchor() {} 484 void StructRecord::anchor() {} 485 void CXXFieldRecord::anchor() {} 486 void CXXClassRecord::anchor() {} 487 void CXXConstructorRecord::anchor() {} 488 void CXXDestructorRecord::anchor() {} 489 void CXXInstanceMethodRecord::anchor() {} 490 void CXXStaticMethodRecord::anchor() {} 491 void ObjCInstancePropertyRecord::anchor() {} 492 void ObjCClassPropertyRecord::anchor() {} 493 void ObjCInstanceVariableRecord::anchor() {} 494 void ObjCInstanceMethodRecord::anchor() {} 495 void ObjCClassMethodRecord::anchor() {} 496 void ObjCCategoryRecord::anchor() {} 497 void ObjCInterfaceRecord::anchor() {} 498 void ObjCProtocolRecord::anchor() {} 499 void MacroDefinitionRecord::anchor() {} 500 void TypedefRecord::anchor() {} 501