1 //===- ExtractAPI/ExtractAPIVisitor.h ---------------------------*- 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 defines the ExtractAPVisitor AST visitation interface. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H 15 #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H 16 17 #include "llvm/ADT/FunctionExtras.h" 18 19 #include "clang/AST/ASTContext.h" 20 #include "clang/AST/ParentMapContext.h" 21 #include "clang/AST/RecursiveASTVisitor.h" 22 #include "clang/Basic/SourceManager.h" 23 #include "clang/ExtractAPI/API.h" 24 #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" 25 #include "llvm/ADT/StringRef.h" 26 #include <type_traits> 27 28 namespace clang { 29 namespace extractapi { 30 namespace impl { 31 32 template <typename Derived> 33 class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> { 34 protected: 35 ExtractAPIVisitorBase(ASTContext &Context, APISet &API) 36 : Context(Context), API(API) {} 37 38 public: 39 const APISet &getAPI() const { return API; } 40 41 bool VisitVarDecl(const VarDecl *Decl); 42 43 bool VisitFunctionDecl(const FunctionDecl *Decl); 44 45 bool VisitEnumDecl(const EnumDecl *Decl); 46 47 bool VisitRecordDecl(const RecordDecl *Decl); 48 49 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl); 50 51 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl); 52 53 bool VisitTypedefNameDecl(const TypedefNameDecl *Decl); 54 55 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl); 56 57 bool shouldDeclBeIncluded(const Decl *Decl) const; 58 59 const RawComment *fetchRawCommentForDecl(const Decl *Decl) const; 60 61 protected: 62 /// Collect API information for the enum constants and associate with the 63 /// parent enum. 64 void recordEnumConstants(EnumRecord *EnumRecord, 65 const EnumDecl::enumerator_range Constants); 66 67 /// Collect API information for the struct fields and associate with the 68 /// parent struct. 69 void recordStructFields(StructRecord *StructRecord, 70 const RecordDecl::field_range Fields); 71 72 /// Collect API information for the Objective-C methods and associate with the 73 /// parent container. 74 void recordObjCMethods(ObjCContainerRecord *Container, 75 const ObjCContainerDecl::method_range Methods); 76 77 void recordObjCProperties(ObjCContainerRecord *Container, 78 const ObjCContainerDecl::prop_range Properties); 79 80 void recordObjCInstanceVariables( 81 ObjCContainerRecord *Container, 82 const llvm::iterator_range< 83 DeclContext::specific_decl_iterator<ObjCIvarDecl>> 84 Ivars); 85 86 void recordObjCProtocols(ObjCContainerRecord *Container, 87 ObjCInterfaceDecl::protocol_range Protocols); 88 89 ASTContext &Context; 90 APISet &API; 91 92 StringRef getTypedefName(const TagDecl *Decl) { 93 if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) 94 return TypedefDecl->getName(); 95 96 return {}; 97 } 98 99 bool isInSystemHeader(const Decl *D) { 100 return Context.getSourceManager().isInSystemHeader(D->getLocation()); 101 } 102 103 private: 104 Derived &getDerivedExtractAPIVisitor() { 105 return *static_cast<Derived *>(this); 106 } 107 }; 108 109 template <typename T> 110 static void modifyRecords(const T &Records, const StringRef &Name) { 111 for (const auto &Record : Records) { 112 if (Name == Record.second.get()->Name) { 113 auto &DeclFragment = Record.second->Declaration; 114 DeclFragment.insert(DeclFragment.begin(), " ", 115 DeclarationFragments::FragmentKind::Text); 116 DeclFragment.insert(DeclFragment.begin(), "typedef", 117 DeclarationFragments::FragmentKind::Keyword, "", 118 nullptr); 119 DeclFragment.insert(--DeclFragment.end(), " { ... } ", 120 DeclarationFragments::FragmentKind::Text); 121 DeclFragment.insert(--DeclFragment.end(), Name, 122 DeclarationFragments::FragmentKind::Identifier); 123 break; 124 } 125 } 126 } 127 128 template <typename Derived> 129 bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) { 130 // skip function parameters. 131 if (isa<ParmVarDecl>(Decl)) 132 return true; 133 134 // Skip non-global variables in records (struct/union/class). 135 if (Decl->getDeclContext()->isRecord()) 136 return true; 137 138 // Skip local variables inside function or method. 139 if (!Decl->isDefinedOutsideFunctionOrMethod()) 140 return true; 141 142 // If this is a template but not specialization or instantiation, skip. 143 if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 144 Decl->getTemplateSpecializationKind() == TSK_Undeclared) 145 return true; 146 147 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 148 return true; 149 150 // Collect symbol information. 151 StringRef Name = Decl->getName(); 152 StringRef USR = API.recordUSR(Decl); 153 PresumedLoc Loc = 154 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 155 LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 156 DocComment Comment; 157 if (auto *RawComment = 158 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 159 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 160 Context.getDiagnostics()); 161 162 // Build declaration fragments and sub-heading for the variable. 163 DeclarationFragments Declaration = 164 DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 165 DeclarationFragments SubHeading = 166 DeclarationFragmentsBuilder::getSubHeading(Decl); 167 168 // Add the global variable record to the API set. 169 API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, 170 Declaration, SubHeading, isInSystemHeader(Decl)); 171 return true; 172 } 173 174 template <typename Derived> 175 bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl( 176 const FunctionDecl *Decl) { 177 if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 178 // Skip member function in class templates. 179 if (Method->getParent()->getDescribedClassTemplate() != nullptr) 180 return true; 181 182 // Skip methods in records. 183 for (const auto &P : Context.getParents(*Method)) { 184 if (P.template get<CXXRecordDecl>()) 185 return true; 186 } 187 188 // Skip ConstructorDecl and DestructorDecl. 189 if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 190 return true; 191 } 192 193 // Skip templated functions. 194 switch (Decl->getTemplatedKind()) { 195 case FunctionDecl::TK_NonTemplate: 196 case FunctionDecl::TK_DependentNonTemplate: 197 break; 198 case FunctionDecl::TK_MemberSpecialization: 199 case FunctionDecl::TK_FunctionTemplateSpecialization: 200 if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 201 if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 202 return true; 203 } 204 break; 205 case FunctionDecl::TK_FunctionTemplate: 206 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 207 return true; 208 } 209 210 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 211 return true; 212 213 // Collect symbol information. 214 StringRef Name = Decl->getName(); 215 StringRef USR = API.recordUSR(Decl); 216 PresumedLoc Loc = 217 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 218 LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 219 DocComment Comment; 220 if (auto *RawComment = 221 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 222 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 223 Context.getDiagnostics()); 224 225 // Build declaration fragments, sub-heading, and signature of the function. 226 DeclarationFragments Declaration = 227 DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 228 DeclarationFragments SubHeading = 229 DeclarationFragmentsBuilder::getSubHeading(Decl); 230 FunctionSignature Signature = 231 DeclarationFragmentsBuilder::getFunctionSignature(Decl); 232 233 // Add the function record to the API set. 234 API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, 235 Declaration, SubHeading, Signature, 236 isInSystemHeader(Decl)); 237 return true; 238 } 239 240 template <typename Derived> 241 bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) { 242 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 243 return true; 244 245 SmallString<128> QualifiedNameBuffer; 246 // Collect symbol information. 247 StringRef Name = Decl->getName(); 248 if (Name.empty()) 249 Name = getTypedefName(Decl); 250 if (Name.empty()) { 251 llvm::raw_svector_ostream OS(QualifiedNameBuffer); 252 Decl->printQualifiedName(OS); 253 Name = QualifiedNameBuffer.str(); 254 } 255 256 StringRef USR = API.recordUSR(Decl); 257 PresumedLoc Loc = 258 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 259 DocComment Comment; 260 if (auto *RawComment = 261 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 262 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 263 Context.getDiagnostics()); 264 265 // Build declaration fragments and sub-heading for the enum. 266 DeclarationFragments Declaration = 267 DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 268 DeclarationFragments SubHeading = 269 DeclarationFragmentsBuilder::getSubHeading(Decl); 270 271 EnumRecord *EnumRecord = 272 API.addEnum(API.copyString(Name), USR, Loc, AvailabilitySet(Decl), 273 Comment, Declaration, SubHeading, isInSystemHeader(Decl)); 274 275 // Now collect information about the enumerators in this enum. 276 getDerivedExtractAPIVisitor().recordEnumConstants(EnumRecord, 277 Decl->enumerators()); 278 279 return true; 280 } 281 282 template <typename Derived> 283 bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) { 284 // Skip C++ structs/classes/unions 285 // TODO: support C++ records 286 if (isa<CXXRecordDecl>(Decl)) 287 return true; 288 289 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 290 return true; 291 292 // Collect symbol information. 293 StringRef Name = Decl->getName(); 294 if (Name.empty()) 295 Name = getTypedefName(Decl); 296 if (Name.empty()) 297 return true; 298 299 StringRef USR = API.recordUSR(Decl); 300 PresumedLoc Loc = 301 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 302 DocComment Comment; 303 if (auto *RawComment = 304 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 305 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 306 Context.getDiagnostics()); 307 308 // Build declaration fragments and sub-heading for the struct. 309 DeclarationFragments Declaration = 310 DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 311 DeclarationFragments SubHeading = 312 DeclarationFragmentsBuilder::getSubHeading(Decl); 313 314 StructRecord *StructRecord = 315 API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, 316 SubHeading, isInSystemHeader(Decl)); 317 318 // Now collect information about the fields in this struct. 319 getDerivedExtractAPIVisitor().recordStructFields(StructRecord, 320 Decl->fields()); 321 322 return true; 323 } 324 325 template <typename Derived> 326 bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl( 327 const ObjCInterfaceDecl *Decl) { 328 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 329 return true; 330 331 // Collect symbol information. 332 StringRef Name = Decl->getName(); 333 StringRef USR = API.recordUSR(Decl); 334 PresumedLoc Loc = 335 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 336 LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 337 DocComment Comment; 338 if (auto *RawComment = 339 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 340 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 341 Context.getDiagnostics()); 342 343 // Build declaration fragments and sub-heading for the interface. 344 DeclarationFragments Declaration = 345 DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 346 DeclarationFragments SubHeading = 347 DeclarationFragmentsBuilder::getSubHeading(Decl); 348 349 // Collect super class information. 350 SymbolReference SuperClass; 351 if (const auto *SuperClassDecl = Decl->getSuperClass()) { 352 SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 353 SuperClass.USR = API.recordUSR(SuperClassDecl); 354 } 355 356 ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( 357 Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, 358 SubHeading, SuperClass, isInSystemHeader(Decl)); 359 360 // Record all methods (selectors). This doesn't include automatically 361 // synthesized property methods. 362 getDerivedExtractAPIVisitor().recordObjCMethods(ObjCInterfaceRecord, 363 Decl->methods()); 364 getDerivedExtractAPIVisitor().recordObjCProperties(ObjCInterfaceRecord, 365 Decl->properties()); 366 getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCInterfaceRecord, 367 Decl->ivars()); 368 getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCInterfaceRecord, 369 Decl->protocols()); 370 371 return true; 372 } 373 374 template <typename Derived> 375 bool ExtractAPIVisitorBase<Derived>::VisitObjCProtocolDecl( 376 const ObjCProtocolDecl *Decl) { 377 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 378 return true; 379 380 // Collect symbol information. 381 StringRef Name = Decl->getName(); 382 StringRef USR = API.recordUSR(Decl); 383 PresumedLoc Loc = 384 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 385 DocComment Comment; 386 if (auto *RawComment = 387 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 388 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 389 Context.getDiagnostics()); 390 391 // Build declaration fragments and sub-heading for the protocol. 392 DeclarationFragments Declaration = 393 DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 394 DeclarationFragments SubHeading = 395 DeclarationFragmentsBuilder::getSubHeading(Decl); 396 397 ObjCProtocolRecord *ObjCProtocolRecord = 398 API.addObjCProtocol(Name, USR, Loc, AvailabilitySet(Decl), Comment, 399 Declaration, SubHeading, isInSystemHeader(Decl)); 400 401 getDerivedExtractAPIVisitor().recordObjCMethods(ObjCProtocolRecord, 402 Decl->methods()); 403 getDerivedExtractAPIVisitor().recordObjCProperties(ObjCProtocolRecord, 404 Decl->properties()); 405 getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCProtocolRecord, 406 Decl->protocols()); 407 408 return true; 409 } 410 411 template <typename Derived> 412 bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl( 413 const TypedefNameDecl *Decl) { 414 // Skip ObjC Type Parameter for now. 415 if (isa<ObjCTypeParamDecl>(Decl)) 416 return true; 417 418 if (!Decl->isDefinedOutsideFunctionOrMethod()) 419 return true; 420 421 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 422 return true; 423 424 // Add the notion of typedef for tag type (struct or enum) of the same name. 425 if (const ElaboratedType *ET = 426 dyn_cast<ElaboratedType>(Decl->getUnderlyingType())) { 427 if (const TagType *TagTy = dyn_cast<TagType>(ET->desugar())) { 428 if (Decl->getName() == TagTy->getDecl()->getName()) { 429 if (TagTy->getDecl()->isStruct()) { 430 modifyRecords(API.getStructs(), Decl->getName()); 431 } 432 if (TagTy->getDecl()->isEnum()) { 433 modifyRecords(API.getEnums(), Decl->getName()); 434 } 435 } 436 } 437 } 438 439 PresumedLoc Loc = 440 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 441 StringRef Name = Decl->getName(); 442 StringRef USR = API.recordUSR(Decl); 443 DocComment Comment; 444 if (auto *RawComment = 445 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 446 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 447 Context.getDiagnostics()); 448 449 QualType Type = Decl->getUnderlyingType(); 450 SymbolReference SymRef = 451 TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, 452 API); 453 454 API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment, 455 DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), 456 DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, 457 isInSystemHeader(Decl)); 458 459 return true; 460 } 461 462 template <typename Derived> 463 bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl( 464 const ObjCCategoryDecl *Decl) { 465 if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) 466 return true; 467 468 StringRef Name = Decl->getName(); 469 StringRef USR = API.recordUSR(Decl); 470 PresumedLoc Loc = 471 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 472 DocComment Comment; 473 if (auto *RawComment = 474 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) 475 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 476 Context.getDiagnostics()); 477 // Build declaration fragments and sub-heading for the category. 478 DeclarationFragments Declaration = 479 DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); 480 DeclarationFragments SubHeading = 481 DeclarationFragmentsBuilder::getSubHeading(Decl); 482 483 const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); 484 SymbolReference Interface(InterfaceDecl->getName(), 485 API.recordUSR(InterfaceDecl)); 486 487 ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( 488 Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, 489 Interface, isInSystemHeader(Decl)); 490 491 getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord, 492 Decl->methods()); 493 getDerivedExtractAPIVisitor().recordObjCProperties(ObjCCategoryRecord, 494 Decl->properties()); 495 getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCCategoryRecord, 496 Decl->ivars()); 497 getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCCategoryRecord, 498 Decl->protocols()); 499 500 return true; 501 } 502 503 /// Collect API information for the enum constants and associate with the 504 /// parent enum. 505 template <typename Derived> 506 void ExtractAPIVisitorBase<Derived>::recordEnumConstants( 507 EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) { 508 for (const auto *Constant : Constants) { 509 // Collect symbol information. 510 StringRef Name = Constant->getName(); 511 StringRef USR = API.recordUSR(Constant); 512 PresumedLoc Loc = 513 Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 514 DocComment Comment; 515 if (auto *RawComment = 516 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Constant)) 517 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 518 Context.getDiagnostics()); 519 520 // Build declaration fragments and sub-heading for the enum constant. 521 DeclarationFragments Declaration = 522 DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 523 DeclarationFragments SubHeading = 524 DeclarationFragmentsBuilder::getSubHeading(Constant); 525 526 API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant), 527 Comment, Declaration, SubHeading, 528 isInSystemHeader(Constant)); 529 } 530 } 531 532 /// Collect API information for the struct fields and associate with the 533 /// parent struct. 534 template <typename Derived> 535 void ExtractAPIVisitorBase<Derived>::recordStructFields( 536 StructRecord *StructRecord, const RecordDecl::field_range Fields) { 537 for (const auto *Field : Fields) { 538 // Collect symbol information. 539 StringRef Name = Field->getName(); 540 StringRef USR = API.recordUSR(Field); 541 PresumedLoc Loc = 542 Context.getSourceManager().getPresumedLoc(Field->getLocation()); 543 DocComment Comment; 544 if (auto *RawComment = 545 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Field)) 546 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 547 Context.getDiagnostics()); 548 549 // Build declaration fragments and sub-heading for the struct field. 550 DeclarationFragments Declaration = 551 DeclarationFragmentsBuilder::getFragmentsForField(Field); 552 DeclarationFragments SubHeading = 553 DeclarationFragmentsBuilder::getSubHeading(Field); 554 555 API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field), 556 Comment, Declaration, SubHeading, 557 isInSystemHeader(Field)); 558 } 559 } 560 561 /// Collect API information for the Objective-C methods and associate with the 562 /// parent container. 563 template <typename Derived> 564 void ExtractAPIVisitorBase<Derived>::recordObjCMethods( 565 ObjCContainerRecord *Container, 566 const ObjCContainerDecl::method_range Methods) { 567 for (const auto *Method : Methods) { 568 // Don't record selectors for properties. 569 if (Method->isPropertyAccessor()) 570 continue; 571 572 StringRef Name = API.copyString(Method->getSelector().getAsString()); 573 StringRef USR = API.recordUSR(Method); 574 PresumedLoc Loc = 575 Context.getSourceManager().getPresumedLoc(Method->getLocation()); 576 DocComment Comment; 577 if (auto *RawComment = 578 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Method)) 579 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 580 Context.getDiagnostics()); 581 582 // Build declaration fragments, sub-heading, and signature for the method. 583 DeclarationFragments Declaration = 584 DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 585 DeclarationFragments SubHeading = 586 DeclarationFragmentsBuilder::getSubHeading(Method); 587 FunctionSignature Signature = 588 DeclarationFragmentsBuilder::getFunctionSignature(Method); 589 590 API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method), 591 Comment, Declaration, SubHeading, Signature, 592 Method->isInstanceMethod(), isInSystemHeader(Method)); 593 } 594 } 595 596 template <typename Derived> 597 void ExtractAPIVisitorBase<Derived>::recordObjCProperties( 598 ObjCContainerRecord *Container, 599 const ObjCContainerDecl::prop_range Properties) { 600 for (const auto *Property : Properties) { 601 StringRef Name = Property->getName(); 602 StringRef USR = API.recordUSR(Property); 603 PresumedLoc Loc = 604 Context.getSourceManager().getPresumedLoc(Property->getLocation()); 605 DocComment Comment; 606 if (auto *RawComment = 607 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Property)) 608 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 609 Context.getDiagnostics()); 610 611 // Build declaration fragments and sub-heading for the property. 612 DeclarationFragments Declaration = 613 DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 614 DeclarationFragments SubHeading = 615 DeclarationFragmentsBuilder::getSubHeading(Property); 616 617 StringRef GetterName = 618 API.copyString(Property->getGetterName().getAsString()); 619 StringRef SetterName = 620 API.copyString(Property->getSetterName().getAsString()); 621 622 // Get the attributes for property. 623 unsigned Attributes = ObjCPropertyRecord::NoAttr; 624 if (Property->getPropertyAttributes() & 625 ObjCPropertyAttribute::kind_readonly) 626 Attributes |= ObjCPropertyRecord::ReadOnly; 627 628 API.addObjCProperty( 629 Container, Name, USR, Loc, AvailabilitySet(Property), Comment, 630 Declaration, SubHeading, 631 static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName, 632 SetterName, Property->isOptional(), 633 !(Property->getPropertyAttributes() & 634 ObjCPropertyAttribute::kind_class), 635 isInSystemHeader(Property)); 636 } 637 } 638 639 template <typename Derived> 640 void ExtractAPIVisitorBase<Derived>::recordObjCInstanceVariables( 641 ObjCContainerRecord *Container, 642 const llvm::iterator_range< 643 DeclContext::specific_decl_iterator<ObjCIvarDecl>> 644 Ivars) { 645 for (const auto *Ivar : Ivars) { 646 StringRef Name = Ivar->getName(); 647 StringRef USR = API.recordUSR(Ivar); 648 PresumedLoc Loc = 649 Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 650 DocComment Comment; 651 if (auto *RawComment = 652 getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Ivar)) 653 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 654 Context.getDiagnostics()); 655 656 // Build declaration fragments and sub-heading for the instance variable. 657 DeclarationFragments Declaration = 658 DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 659 DeclarationFragments SubHeading = 660 DeclarationFragmentsBuilder::getSubHeading(Ivar); 661 662 ObjCInstanceVariableRecord::AccessControl Access = 663 Ivar->getCanonicalAccessControl(); 664 665 API.addObjCInstanceVariable(Container, Name, USR, Loc, 666 AvailabilitySet(Ivar), Comment, Declaration, 667 SubHeading, Access, isInSystemHeader(Ivar)); 668 } 669 } 670 671 template <typename Derived> 672 void ExtractAPIVisitorBase<Derived>::recordObjCProtocols( 673 ObjCContainerRecord *Container, 674 ObjCInterfaceDecl::protocol_range Protocols) { 675 for (const auto *Protocol : Protocols) 676 Container->Protocols.emplace_back(Protocol->getName(), 677 API.recordUSR(Protocol)); 678 } 679 680 } // namespace impl 681 682 /// The RecursiveASTVisitor to traverse symbol declarations and collect API 683 /// information. 684 template <typename Derived = void> 685 class ExtractAPIVisitor 686 : public impl::ExtractAPIVisitorBase<std::conditional_t< 687 std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>> { 688 using Base = impl::ExtractAPIVisitorBase<std::conditional_t< 689 std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>>; 690 691 public: 692 ExtractAPIVisitor(ASTContext &Context, APISet &API) : Base(Context, API) {} 693 694 bool shouldDeclBeIncluded(const Decl *D) const { return true; } 695 const RawComment *fetchRawCommentForDecl(const Decl *D) const { 696 return this->Context.getRawCommentForDeclNoCache(D); 697 } 698 }; 699 700 } // namespace extractapi 701 } // namespace clang 702 703 #endif // LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H 704