1 //===- ExtractAPI/ExtractAPIVisitor.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 ExtractAPIVisitor an ASTVisitor to collect API 11 /// information. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/ExtractAPI/ExtractAPIVisitor.h" 16 17 #include "TypedefUnderlyingTypeResolver.h" 18 #include "clang/AST/ASTConsumer.h" 19 #include "clang/AST/ASTContext.h" 20 #include "clang/AST/Decl.h" 21 #include "clang/AST/DeclCXX.h" 22 #include "clang/AST/ParentMapContext.h" 23 #include "clang/AST/RawCommentList.h" 24 #include "clang/Basic/SourceLocation.h" 25 #include "clang/Basic/SourceManager.h" 26 #include "clang/Basic/TargetInfo.h" 27 #include "clang/ExtractAPI/API.h" 28 #include "clang/ExtractAPI/AvailabilityInfo.h" 29 #include "clang/ExtractAPI/DeclarationFragments.h" 30 #include "clang/Frontend/ASTConsumers.h" 31 #include "clang/Frontend/FrontendOptions.h" 32 #include "llvm/Support/raw_ostream.h" 33 34 using namespace clang; 35 using namespace extractapi; 36 37 namespace { 38 39 StringRef getTypedefName(const TagDecl *Decl) { 40 if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) 41 return TypedefDecl->getName(); 42 43 return {}; 44 } 45 46 template <class DeclTy> 47 bool isInSystemHeader(const ASTContext &Context, const DeclTy *D) { 48 return Context.getSourceManager().isInSystemHeader(D->getLocation()); 49 } 50 51 } // namespace 52 53 bool ExtractAPIVisitor::VisitVarDecl(const VarDecl *Decl) { 54 // skip function parameters. 55 if (isa<ParmVarDecl>(Decl)) 56 return true; 57 58 // Skip non-global variables in records (struct/union/class). 59 if (Decl->getDeclContext()->isRecord()) 60 return true; 61 62 // Skip local variables inside function or method. 63 if (!Decl->isDefinedOutsideFunctionOrMethod()) 64 return true; 65 66 // If this is a template but not specialization or instantiation, skip. 67 if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 68 Decl->getTemplateSpecializationKind() == TSK_Undeclared) 69 return true; 70 71 if (!LocationChecker(Decl->getLocation())) 72 return true; 73 74 // Collect symbol information. 75 StringRef Name = Decl->getName(); 76 StringRef USR = API.recordUSR(Decl); 77 PresumedLoc Loc = 78 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 79 LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 80 DocComment Comment; 81 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 82 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 83 Context.getDiagnostics()); 84 85 // Build declaration fragments and sub-heading for the variable. 86 DeclarationFragments Declaration = 87 DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 88 DeclarationFragments SubHeading = 89 DeclarationFragmentsBuilder::getSubHeading(Decl); 90 91 // Add the global variable record to the API set. 92 API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, 93 Declaration, SubHeading, isInSystemHeader(Context, Decl)); 94 return true; 95 } 96 97 bool ExtractAPIVisitor::VisitFunctionDecl(const FunctionDecl *Decl) { 98 if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 99 // Skip member function in class templates. 100 if (Method->getParent()->getDescribedClassTemplate() != nullptr) 101 return true; 102 103 // Skip methods in records. 104 for (auto P : Context.getParents(*Method)) { 105 if (P.get<CXXRecordDecl>()) 106 return true; 107 } 108 109 // Skip ConstructorDecl and DestructorDecl. 110 if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 111 return true; 112 } 113 114 // Skip templated functions. 115 switch (Decl->getTemplatedKind()) { 116 case FunctionDecl::TK_NonTemplate: 117 case FunctionDecl::TK_DependentNonTemplate: 118 break; 119 case FunctionDecl::TK_MemberSpecialization: 120 case FunctionDecl::TK_FunctionTemplateSpecialization: 121 if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 122 if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 123 return true; 124 } 125 break; 126 case FunctionDecl::TK_FunctionTemplate: 127 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 128 return true; 129 } 130 131 if (!LocationChecker(Decl->getLocation())) 132 return true; 133 134 // Collect symbol information. 135 StringRef Name = Decl->getName(); 136 StringRef USR = API.recordUSR(Decl); 137 PresumedLoc Loc = 138 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 139 LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 140 DocComment Comment; 141 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 142 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 143 Context.getDiagnostics()); 144 145 // Build declaration fragments, sub-heading, and signature of the function. 146 DeclarationFragments Declaration = 147 DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 148 DeclarationFragments SubHeading = 149 DeclarationFragmentsBuilder::getSubHeading(Decl); 150 FunctionSignature Signature = 151 DeclarationFragmentsBuilder::getFunctionSignature(Decl); 152 153 // Add the function record to the API set. 154 API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, 155 Declaration, SubHeading, Signature, 156 isInSystemHeader(Context, Decl)); 157 return true; 158 } 159 160 bool ExtractAPIVisitor::VisitEnumDecl(const EnumDecl *Decl) { 161 if (!Decl->isComplete()) 162 return true; 163 164 // Skip forward declaration. 165 if (!Decl->isThisDeclarationADefinition()) 166 return true; 167 168 if (!LocationChecker(Decl->getLocation())) 169 return true; 170 171 SmallString<128> QualifiedNameBuffer; 172 // Collect symbol information. 173 StringRef Name = Decl->getName(); 174 if (Name.empty()) 175 Name = getTypedefName(Decl); 176 if (Name.empty()) { 177 llvm::raw_svector_ostream OS(QualifiedNameBuffer); 178 Decl->printQualifiedName(OS); 179 Name = QualifiedNameBuffer.str(); 180 } 181 182 StringRef USR = API.recordUSR(Decl); 183 PresumedLoc Loc = 184 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 185 DocComment Comment; 186 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 187 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 188 Context.getDiagnostics()); 189 190 // Build declaration fragments and sub-heading for the enum. 191 DeclarationFragments Declaration = 192 DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 193 DeclarationFragments SubHeading = 194 DeclarationFragmentsBuilder::getSubHeading(Decl); 195 196 EnumRecord *EnumRecord = API.addEnum( 197 API.copyString(Name), USR, Loc, AvailabilitySet(Decl), Comment, 198 Declaration, SubHeading, isInSystemHeader(Context, Decl)); 199 200 // Now collect information about the enumerators in this enum. 201 recordEnumConstants(EnumRecord, Decl->enumerators()); 202 203 return true; 204 } 205 206 bool ExtractAPIVisitor::VisitRecordDecl(const RecordDecl *Decl) { 207 if (!Decl->isCompleteDefinition()) 208 return true; 209 210 // Skip C++ structs/classes/unions 211 // TODO: support C++ records 212 if (isa<CXXRecordDecl>(Decl)) 213 return true; 214 215 if (!LocationChecker(Decl->getLocation())) 216 return true; 217 218 // Collect symbol information. 219 StringRef Name = Decl->getName(); 220 if (Name.empty()) 221 Name = getTypedefName(Decl); 222 if (Name.empty()) 223 return true; 224 225 StringRef USR = API.recordUSR(Decl); 226 PresumedLoc Loc = 227 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 228 DocComment Comment; 229 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 230 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 231 Context.getDiagnostics()); 232 233 // Build declaration fragments and sub-heading for the struct. 234 DeclarationFragments Declaration = 235 DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 236 DeclarationFragments SubHeading = 237 DeclarationFragmentsBuilder::getSubHeading(Decl); 238 239 StructRecord *StructRecord = 240 API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, 241 SubHeading, isInSystemHeader(Context, Decl)); 242 243 // Now collect information about the fields in this struct. 244 recordStructFields(StructRecord, Decl->fields()); 245 246 return true; 247 } 248 249 bool ExtractAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { 250 // Skip forward declaration for classes (@class) 251 if (!Decl->isThisDeclarationADefinition()) 252 return true; 253 254 if (!LocationChecker(Decl->getLocation())) 255 return true; 256 257 // Collect symbol information. 258 StringRef Name = Decl->getName(); 259 StringRef USR = API.recordUSR(Decl); 260 PresumedLoc Loc = 261 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 262 LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 263 DocComment Comment; 264 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 265 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 266 Context.getDiagnostics()); 267 268 // Build declaration fragments and sub-heading for the interface. 269 DeclarationFragments Declaration = 270 DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 271 DeclarationFragments SubHeading = 272 DeclarationFragmentsBuilder::getSubHeading(Decl); 273 274 // Collect super class information. 275 SymbolReference SuperClass; 276 if (const auto *SuperClassDecl = Decl->getSuperClass()) { 277 SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 278 SuperClass.USR = API.recordUSR(SuperClassDecl); 279 } 280 281 ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( 282 Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, 283 SubHeading, SuperClass, isInSystemHeader(Context, Decl)); 284 285 // Record all methods (selectors). This doesn't include automatically 286 // synthesized property methods. 287 recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); 288 recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); 289 recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); 290 recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); 291 292 return true; 293 } 294 295 bool ExtractAPIVisitor::VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { 296 // Skip forward declaration for protocols (@protocol). 297 if (!Decl->isThisDeclarationADefinition()) 298 return true; 299 300 if (!LocationChecker(Decl->getLocation())) 301 return true; 302 303 // Collect symbol information. 304 StringRef Name = Decl->getName(); 305 StringRef USR = API.recordUSR(Decl); 306 PresumedLoc Loc = 307 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 308 DocComment Comment; 309 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 310 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 311 Context.getDiagnostics()); 312 313 // Build declaration fragments and sub-heading for the protocol. 314 DeclarationFragments Declaration = 315 DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 316 DeclarationFragments SubHeading = 317 DeclarationFragmentsBuilder::getSubHeading(Decl); 318 319 ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( 320 Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, 321 isInSystemHeader(Context, Decl)); 322 323 recordObjCMethods(ObjCProtocolRecord, Decl->methods()); 324 recordObjCProperties(ObjCProtocolRecord, Decl->properties()); 325 recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); 326 327 return true; 328 } 329 330 bool ExtractAPIVisitor::VisitTypedefNameDecl(const TypedefNameDecl *Decl) { 331 // Skip ObjC Type Parameter for now. 332 if (isa<ObjCTypeParamDecl>(Decl)) 333 return true; 334 335 if (!Decl->isDefinedOutsideFunctionOrMethod()) 336 return true; 337 338 if (!LocationChecker(Decl->getLocation())) 339 return true; 340 341 PresumedLoc Loc = 342 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 343 StringRef Name = Decl->getName(); 344 StringRef USR = API.recordUSR(Decl); 345 DocComment Comment; 346 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 347 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 348 Context.getDiagnostics()); 349 350 QualType Type = Decl->getUnderlyingType(); 351 SymbolReference SymRef = 352 TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, 353 API); 354 355 API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment, 356 DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), 357 DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, 358 isInSystemHeader(Context, Decl)); 359 360 return true; 361 } 362 363 bool ExtractAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) { 364 // Collect symbol information. 365 StringRef Name = Decl->getName(); 366 StringRef USR = API.recordUSR(Decl); 367 PresumedLoc Loc = 368 Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 369 DocComment Comment; 370 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 371 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 372 Context.getDiagnostics()); 373 // Build declaration fragments and sub-heading for the category. 374 DeclarationFragments Declaration = 375 DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); 376 DeclarationFragments SubHeading = 377 DeclarationFragmentsBuilder::getSubHeading(Decl); 378 379 const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); 380 SymbolReference Interface(InterfaceDecl->getName(), 381 API.recordUSR(InterfaceDecl)); 382 383 ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( 384 Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, 385 Interface, isInSystemHeader(Context, Decl)); 386 387 recordObjCMethods(ObjCCategoryRecord, Decl->methods()); 388 recordObjCProperties(ObjCCategoryRecord, Decl->properties()); 389 recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars()); 390 recordObjCProtocols(ObjCCategoryRecord, Decl->protocols()); 391 392 return true; 393 } 394 395 /// Collect API information for the enum constants and associate with the 396 /// parent enum. 397 void ExtractAPIVisitor::recordEnumConstants( 398 EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) { 399 for (const auto *Constant : Constants) { 400 // Collect symbol information. 401 StringRef Name = Constant->getName(); 402 StringRef USR = API.recordUSR(Constant); 403 PresumedLoc Loc = 404 Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 405 DocComment Comment; 406 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) 407 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 408 Context.getDiagnostics()); 409 410 // Build declaration fragments and sub-heading for the enum constant. 411 DeclarationFragments Declaration = 412 DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 413 DeclarationFragments SubHeading = 414 DeclarationFragmentsBuilder::getSubHeading(Constant); 415 416 API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant), 417 Comment, Declaration, SubHeading, 418 isInSystemHeader(Context, Constant)); 419 } 420 } 421 422 /// Collect API information for the struct fields and associate with the 423 /// parent struct. 424 void ExtractAPIVisitor::recordStructFields( 425 StructRecord *StructRecord, const RecordDecl::field_range Fields) { 426 for (const auto *Field : Fields) { 427 // Collect symbol information. 428 StringRef Name = Field->getName(); 429 StringRef USR = API.recordUSR(Field); 430 PresumedLoc Loc = 431 Context.getSourceManager().getPresumedLoc(Field->getLocation()); 432 DocComment Comment; 433 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) 434 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 435 Context.getDiagnostics()); 436 437 // Build declaration fragments and sub-heading for the struct field. 438 DeclarationFragments Declaration = 439 DeclarationFragmentsBuilder::getFragmentsForField(Field); 440 DeclarationFragments SubHeading = 441 DeclarationFragmentsBuilder::getSubHeading(Field); 442 443 API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field), 444 Comment, Declaration, SubHeading, 445 isInSystemHeader(Context, Field)); 446 } 447 } 448 449 /// Collect API information for the Objective-C methods and associate with the 450 /// parent container. 451 void ExtractAPIVisitor::recordObjCMethods( 452 ObjCContainerRecord *Container, 453 const ObjCContainerDecl::method_range Methods) { 454 for (const auto *Method : Methods) { 455 // Don't record selectors for properties. 456 if (Method->isPropertyAccessor()) 457 continue; 458 459 StringRef Name = API.copyString(Method->getSelector().getAsString()); 460 StringRef USR = API.recordUSR(Method); 461 PresumedLoc Loc = 462 Context.getSourceManager().getPresumedLoc(Method->getLocation()); 463 DocComment Comment; 464 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) 465 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 466 Context.getDiagnostics()); 467 468 // Build declaration fragments, sub-heading, and signature for the method. 469 DeclarationFragments Declaration = 470 DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 471 DeclarationFragments SubHeading = 472 DeclarationFragmentsBuilder::getSubHeading(Method); 473 FunctionSignature Signature = 474 DeclarationFragmentsBuilder::getFunctionSignature(Method); 475 476 API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method), 477 Comment, Declaration, SubHeading, Signature, 478 Method->isInstanceMethod(), 479 isInSystemHeader(Context, Method)); 480 } 481 } 482 483 void ExtractAPIVisitor::recordObjCProperties( 484 ObjCContainerRecord *Container, 485 const ObjCContainerDecl::prop_range Properties) { 486 for (const auto *Property : Properties) { 487 StringRef Name = Property->getName(); 488 StringRef USR = API.recordUSR(Property); 489 PresumedLoc Loc = 490 Context.getSourceManager().getPresumedLoc(Property->getLocation()); 491 DocComment Comment; 492 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) 493 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 494 Context.getDiagnostics()); 495 496 // Build declaration fragments and sub-heading for the property. 497 DeclarationFragments Declaration = 498 DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 499 DeclarationFragments SubHeading = 500 DeclarationFragmentsBuilder::getSubHeading(Property); 501 502 StringRef GetterName = 503 API.copyString(Property->getGetterName().getAsString()); 504 StringRef SetterName = 505 API.copyString(Property->getSetterName().getAsString()); 506 507 // Get the attributes for property. 508 unsigned Attributes = ObjCPropertyRecord::NoAttr; 509 if (Property->getPropertyAttributes() & 510 ObjCPropertyAttribute::kind_readonly) 511 Attributes |= ObjCPropertyRecord::ReadOnly; 512 513 API.addObjCProperty( 514 Container, Name, USR, Loc, AvailabilitySet(Property), Comment, 515 Declaration, SubHeading, 516 static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName, 517 SetterName, Property->isOptional(), 518 !(Property->getPropertyAttributes() & 519 ObjCPropertyAttribute::kind_class), 520 isInSystemHeader(Context, Property)); 521 } 522 } 523 524 void ExtractAPIVisitor::recordObjCInstanceVariables( 525 ObjCContainerRecord *Container, 526 const llvm::iterator_range< 527 DeclContext::specific_decl_iterator<ObjCIvarDecl>> 528 Ivars) { 529 for (const auto *Ivar : Ivars) { 530 StringRef Name = Ivar->getName(); 531 StringRef USR = API.recordUSR(Ivar); 532 PresumedLoc Loc = 533 Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 534 DocComment Comment; 535 if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) 536 Comment = RawComment->getFormattedLines(Context.getSourceManager(), 537 Context.getDiagnostics()); 538 539 // Build declaration fragments and sub-heading for the instance variable. 540 DeclarationFragments Declaration = 541 DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 542 DeclarationFragments SubHeading = 543 DeclarationFragmentsBuilder::getSubHeading(Ivar); 544 545 ObjCInstanceVariableRecord::AccessControl Access = 546 Ivar->getCanonicalAccessControl(); 547 548 API.addObjCInstanceVariable( 549 Container, Name, USR, Loc, AvailabilitySet(Ivar), Comment, Declaration, 550 SubHeading, Access, isInSystemHeader(Context, Ivar)); 551 } 552 } 553 554 void ExtractAPIVisitor::recordObjCProtocols( 555 ObjCContainerRecord *Container, 556 ObjCInterfaceDecl::protocol_range Protocols) { 557 for (const auto *Protocol : Protocols) 558 Container->Protocols.emplace_back(Protocol->getName(), 559 API.recordUSR(Protocol)); 560 } 561