//===- ExtractAPI/ExtractAPIVisitor.h ---------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file defines the ExtractAPVisitor AST visitation interface. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include namespace clang { namespace extractapi { namespace impl { template class ExtractAPIVisitorBase : public RecursiveASTVisitor { using Base = RecursiveASTVisitor; protected: ExtractAPIVisitorBase(ASTContext &Context, APISet &API) : Context(Context), API(API) {} public: const APISet &getAPI() const { return API; } bool VisitVarDecl(const VarDecl *Decl); bool VisitFunctionDecl(const FunctionDecl *Decl); bool VisitEnumDecl(const EnumDecl *Decl); bool WalkUpFromFunctionDecl(const FunctionDecl *Decl); bool WalkUpFromRecordDecl(const RecordDecl *Decl); bool WalkUpFromCXXRecordDecl(const CXXRecordDecl *Decl); bool WalkUpFromCXXMethodDecl(const CXXMethodDecl *Decl); bool WalkUpFromClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *Decl); bool WalkUpFromClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *Decl); bool WalkUpFromVarTemplateDecl(const VarTemplateDecl *Decl); bool WalkUpFromVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *Decl); bool WalkUpFromVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *Decl); bool WalkUpFromFunctionTemplateDecl(const FunctionTemplateDecl *Decl); bool WalkUpFromNamespaceDecl(const NamespaceDecl *Decl); bool VisitNamespaceDecl(const NamespaceDecl *Decl); bool TraverseRecordDecl(RecordDecl *Decl); bool VisitRecordDecl(const RecordDecl *Decl); bool TraverseCXXRecordDecl(CXXRecordDecl *Decl); bool VisitCXXRecordDecl(const CXXRecordDecl *Decl); bool VisitCXXMethodDecl(const CXXMethodDecl *Decl); bool VisitFieldDecl(const FieldDecl *Decl); bool VisitCXXConversionDecl(const CXXConversionDecl *Decl); bool VisitCXXConstructorDecl(const CXXConstructorDecl *Decl); bool VisitCXXDestructorDecl(const CXXDestructorDecl *Decl); bool VisitConceptDecl(const ConceptDecl *Decl); bool VisitClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *Decl); bool VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *Decl); bool VisitVarTemplateDecl(const VarTemplateDecl *Decl); bool VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *Decl); bool VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *Decl); bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *Decl); bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl); bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl); bool VisitTypedefNameDecl(const TypedefNameDecl *Decl); bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl); bool shouldDeclBeIncluded(const Decl *Decl) const; const RawComment *fetchRawCommentForDecl(const Decl *Decl) const; protected: /// Collect API information for the enum constants and associate with the /// parent enum. void recordEnumConstants(SymbolReference Container, const EnumDecl::enumerator_range Constants); /// Collect API information for the Objective-C methods and associate with the /// parent container. void recordObjCMethods(ObjCContainerRecord *Container, const ObjCContainerDecl::method_range Methods); void recordObjCProperties(ObjCContainerRecord *Container, const ObjCContainerDecl::prop_range Properties); void recordObjCInstanceVariables( ObjCContainerRecord *Container, const llvm::iterator_range< DeclContext::specific_decl_iterator> Ivars); void recordObjCProtocols(ObjCContainerRecord *Container, ObjCInterfaceDecl::protocol_range Protocols); ASTContext &Context; APISet &API; StringRef getTypedefName(const TagDecl *Decl) { if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) return TypedefDecl->getName(); return {}; } bool isInSystemHeader(const Decl *D) { return Context.getSourceManager().isInSystemHeader(D->getLocation()); } private: Derived &getDerivedExtractAPIVisitor() { return *static_cast(this); } protected: SmallVector getBases(const CXXRecordDecl *Decl) { // FIXME: store AccessSpecifier given by inheritance SmallVector Bases; for (const auto &BaseSpecifier : Decl->bases()) { // skip classes not inherited as public if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public) continue; if (auto *BaseDecl = BaseSpecifier.getType()->getAsTagDecl()) { Bases.emplace_back(createSymbolReferenceForDecl(*BaseDecl)); } else { SymbolReference BaseClass; BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString( Decl->getASTContext().getPrintingPolicy())); if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) { if (auto *TTPTD = BaseSpecifier.getType() ->getAs() ->getDecl()) { SmallString<128> USR; index::generateUSRForDecl(TTPTD, USR); BaseClass.USR = API.copyString(USR); BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD)); } } Bases.emplace_back(BaseClass); } } return Bases; } APIRecord::RecordKind getKindForDisplay(const CXXRecordDecl *Decl) { if (Decl->isUnion()) return APIRecord::RK_Union; if (Decl->isStruct()) return APIRecord::RK_Struct; return APIRecord::RK_CXXClass; } StringRef getOwningModuleName(const Decl &D) { if (auto *OwningModule = D.getImportedOwningModule()) return OwningModule->Name; return {}; } SymbolReference createHierarchyInformationForDecl(const Decl &D) { const auto *Context = cast_if_present(D.getDeclContext()); if (!Context || isa(Context)) return {}; return createSymbolReferenceForDecl(*Context); } SymbolReference createSymbolReferenceForDecl(const Decl &D) { SmallString<128> USR; index::generateUSRForDecl(&D, USR); APIRecord *Record = API.findRecordForUSR(USR); if (Record) return SymbolReference(Record); StringRef Name; if (auto *ND = dyn_cast(&D)) Name = ND->getName(); return API.createSymbolReference(Name, USR, getOwningModuleName(D)); } bool isEmbeddedInVarDeclarator(const TagDecl &D) { return D.getName().empty() && getTypedefName(&D).empty() && D.isEmbeddedInDeclarator() && !D.isFreeStanding(); } void maybeMergeWithAnonymousTag(const DeclaratorDecl &D, RecordContext *NewRecordContext) { if (!NewRecordContext) return; auto *Tag = D.getType()->getAsTagDecl(); SmallString<128> TagUSR; clang::index::generateUSRForDecl(Tag, TagUSR); if (auto *Record = llvm::dyn_cast_if_present( API.findRecordForUSR(TagUSR))) { if (Record->IsEmbeddedInVarDeclarator) { NewRecordContext->stealRecordChain(*Record); API.removeRecord(Record); } } } }; template bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { // skip function parameters. if (isa(Decl)) return true; // Skip non-global variables in records (struct/union/class) but not static // members. if (Decl->getDeclContext()->isRecord() && !Decl->isStaticDataMember()) return true; // Skip local variables inside function or method. if (!Decl->isDefinedOutsideFunctionOrMethod()) return true; // If this is a template but not specialization or instantiation, skip. if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && Decl->getTemplateSpecializationKind() == TSK_Undeclared) return true; if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the variable. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForVar(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); if (Decl->isStaticDataMember()) { auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, Access, isInSystemHeader(Decl)); } else { // Add the global variable record to the API set. auto *NewRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, isInSystemHeader(Decl)); // If this global variable has a non typedef'd anonymous tag type let's // pretend the type's child records are under us in the hierarchy. maybeMergeWithAnonymousTag(*Decl, NewRecord); } return true; } template bool ExtractAPIVisitorBase::VisitFunctionDecl( const FunctionDecl *Decl) { if (const auto *Method = dyn_cast(Decl)) { // Skip member function in class templates. if (Method->getParent()->getDescribedClassTemplate() != nullptr) return true; // Skip methods in records. for (const auto &P : Context.getParents(*Method)) { if (P.template get()) return true; } // Skip ConstructorDecl and DestructorDecl. if (isa(Method) || isa(Method)) return true; } // Skip templated functions that aren't processed here. switch (Decl->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: case FunctionDecl::TK_DependentNonTemplate: case FunctionDecl::TK_FunctionTemplateSpecialization: break; case FunctionDecl::TK_FunctionTemplate: case FunctionDecl::TK_DependentFunctionTemplateSpecialization: case FunctionDecl::TK_MemberSpecialization: return true; } if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. auto Name = Decl->getNameAsString(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments, sub-heading, and signature of the function. DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); if (Decl->getTemplateSpecializationInfo()) API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, DeclarationFragmentsBuilder:: getFragmentsForFunctionTemplateSpecialization(Decl), SubHeading, Signature, isInSystemHeader(Decl)); else // Add the function record to the API set. API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), SubHeading, Signature, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the enum. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); // Collect symbol information. SymbolReference ParentContainer; if (Decl->hasNameForLinkage()) { StringRef Name = Decl->getName(); if (Name.empty()) Name = getTypedefName(Decl); auto *ER = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, isInSystemHeader(Decl), false); ParentContainer = SymbolReference(ER); } else { // If this an anonymous enum then the parent scope of the constants is the // top level namespace. ParentContainer = {}; } // Now collect information about the enumerators in this enum. getDerivedExtractAPIVisitor().recordEnumConstants(ParentContainer, Decl->enumerators()); return true; } template bool ExtractAPIVisitorBase::WalkUpFromFunctionDecl( const FunctionDecl *Decl) { getDerivedExtractAPIVisitor().VisitFunctionDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromRecordDecl( const RecordDecl *Decl) { getDerivedExtractAPIVisitor().VisitRecordDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromCXXRecordDecl( const CXXRecordDecl *Decl) { getDerivedExtractAPIVisitor().VisitCXXRecordDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromCXXMethodDecl( const CXXMethodDecl *Decl) { getDerivedExtractAPIVisitor().VisitCXXMethodDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *Decl) { getDerivedExtractAPIVisitor().VisitClassTemplateSpecializationDecl(Decl); return true; } template bool ExtractAPIVisitorBase:: WalkUpFromClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *Decl) { getDerivedExtractAPIVisitor().VisitClassTemplatePartialSpecializationDecl( Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromVarTemplateDecl( const VarTemplateDecl *Decl) { getDerivedExtractAPIVisitor().VisitVarTemplateDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *Decl) { getDerivedExtractAPIVisitor().VisitVarTemplateSpecializationDecl(Decl); return true; } template bool ExtractAPIVisitorBase:: WalkUpFromVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *Decl) { getDerivedExtractAPIVisitor().VisitVarTemplatePartialSpecializationDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromFunctionTemplateDecl( const FunctionTemplateDecl *Decl) { getDerivedExtractAPIVisitor().VisitFunctionTemplateDecl(Decl); return true; } template bool ExtractAPIVisitorBase::WalkUpFromNamespaceDecl( const NamespaceDecl *Decl) { getDerivedExtractAPIVisitor().VisitNamespaceDecl(Decl); return true; } template bool ExtractAPIVisitorBase::VisitNamespaceDecl( const NamespaceDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; if (Decl->isAnonymousNamespace()) return true; StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the struct. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForNamespace(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::TraverseRecordDecl(RecordDecl *Decl) { bool Ret = Base::TraverseRecordDecl(Decl); if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) { SmallString<128> USR; index::generateUSRForDecl(Decl, USR); API.removeRecord(USR); } return Ret; } template bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); if (Name.empty()) Name = getTypedefName(Decl); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the struct. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForRecordDecl(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); if (Decl->isUnion()) API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl)); else API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl)); return true; } template bool ExtractAPIVisitorBase::TraverseCXXRecordDecl( CXXRecordDecl *Decl) { bool Ret = Base::TraverseCXXRecordDecl(Decl); if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) { SmallString<128> USR; index::generateUSRForDecl(Decl, USR); API.removeRecord(USR); } return Ret; } template bool ExtractAPIVisitorBase::VisitCXXRecordDecl( const CXXRecordDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || Decl->isImplicit()) return true; StringRef Name = Decl->getName(); if (Name.empty()) Name = getTypedefName(Decl); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForCXXClass(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); CXXClassRecord *Record; if (Decl->getDescribedClassTemplate()) { // Inject template fragments before class fragments. Declaration.prepend( DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate( Decl->getDescribedClassTemplate())); Record = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Template(Decl->getDescribedClassTemplate()), Access, isInSystemHeader(Decl)); } else { Record = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, APIRecord::RecordKind::RK_CXXClass, Access, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl)); } Record->KindForDisplay = getKindForDisplay(Decl); Record->Bases = getBases(Decl); return true; } template bool ExtractAPIVisitorBase::VisitCXXMethodDecl( const CXXMethodDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || Decl->isImplicit()) return true; if (isa(Decl)) return true; if (isa(Decl) || isa(Decl)) return true; SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); auto Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); if (FunctionTemplateDecl *TemplateDecl = Decl->getDescribedFunctionTemplate()) { API.createRecord( USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate( TemplateDecl), SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl), DeclarationFragmentsBuilder::getAccessControl(TemplateDecl), Template(TemplateDecl), isInSystemHeader(Decl)); } else if (Decl->getTemplateSpecializationInfo()) API.createRecord( USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder:: getFragmentsForFunctionTemplateSpecialization(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else if (Decl->isOverloadedOperator()) API.createRecord( USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else if (Decl->isStatic()) API.createRecord( USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else API.createRecord( USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitCXXConstructorDecl( const CXXConstructorDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || Decl->isImplicit()) return true; auto Name = Decl->getNameAsString(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments, sub-heading, and signature for the method. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Signature, Access, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitCXXDestructorDecl( const CXXDestructorDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || Decl->isImplicit()) return true; auto Name = Decl->getNameAsString(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments, sub-heading, and signature for the method. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Signature, Access, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitConceptDecl(const ConceptDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForConcept(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Template(Decl), isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); auto *CTSR = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl), isInSystemHeader(Decl)); CTSR->Bases = getBases(Decl); return true; } template bool ExtractAPIVisitorBase:: VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); DeclarationFragments Declaration = DeclarationFragmentsBuilder:: getFragmentsForClassTemplatePartialSpecialization(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); auto *CTPSR = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Template(Decl), DeclarationFragmentsBuilder::getAccessControl(Decl), isInSystemHeader(Decl)); CTPSR->KindForDisplay = getKindForDisplay(Decl); CTPSR->Bases = getBases(Decl); return true; } template bool ExtractAPIVisitorBase::VisitVarTemplateDecl( const VarTemplateDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the variable. DeclarationFragments Declaration; Declaration .append(DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate( Decl)) .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate( Decl->getTemplatedDecl())); // Inject template fragments before var fragments. DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); if (Decl->getDeclContext()->getDeclKind() == Decl::CXXRecord) API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl), Template(Decl), isInSystemHeader(Decl)); else API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, Template(Decl), isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the variable. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the variable. DeclarationFragments Declaration = DeclarationFragmentsBuilder:: getFragmentsForVarTemplatePartialSpecialization(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, Template(Decl), isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl( const FunctionTemplateDecl *Decl) { if (isa(Decl->getTemplatedDecl())) return true; if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. auto Name = Decl->getNameAsString(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature( Decl->getTemplatedDecl()); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Decl), SubHeading, Signature, Template(Decl), isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( const ObjCInterfaceDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the interface. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); // Collect super class information. SymbolReference SuperClass; if (const auto *SuperClassDecl = Decl->getSuperClass()) SuperClass = createSymbolReferenceForDecl(*SuperClassDecl); auto *InterfaceRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, SubHeading, SuperClass, isInSystemHeader(Decl)); // Record all methods (selectors). This doesn't include automatically // synthesized property methods. getDerivedExtractAPIVisitor().recordObjCMethods(InterfaceRecord, Decl->methods()); getDerivedExtractAPIVisitor().recordObjCProperties(InterfaceRecord, Decl->properties()); getDerivedExtractAPIVisitor().recordObjCInstanceVariables(InterfaceRecord, Decl->ivars()); getDerivedExtractAPIVisitor().recordObjCProtocols(InterfaceRecord, Decl->protocols()); return true; } template bool ExtractAPIVisitorBase::VisitObjCProtocolDecl( const ObjCProtocolDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the protocol. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); auto *ProtoRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, isInSystemHeader(Decl)); getDerivedExtractAPIVisitor().recordObjCMethods(ProtoRecord, Decl->methods()); getDerivedExtractAPIVisitor().recordObjCProperties(ProtoRecord, Decl->properties()); getDerivedExtractAPIVisitor().recordObjCProtocols(ProtoRecord, Decl->protocols()); return true; } template bool ExtractAPIVisitorBase::VisitTypedefNameDecl( const TypedefNameDecl *Decl) { // Skip ObjC Type Parameter for now. if (isa(Decl)) return true; if (!Decl->isDefinedOutsideFunctionOrMethod()) return true; if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; StringRef Name = Decl->getName(); // If the underlying type was defined as part of the typedef modify it's // fragments directly and pretend the typedef doesn't exist. if (auto *TagDecl = Decl->getUnderlyingType()->getAsTagDecl()) { if (TagDecl->isEmbeddedInDeclarator() && TagDecl->isCompleteDefinition() && Decl->getName() == TagDecl->getName()) { SmallString<128> TagUSR; index::generateUSRForDecl(TagDecl, TagUSR); if (auto *Record = API.findRecordForUSR(TagUSR)) { DeclarationFragments LeadingFragments; LeadingFragments.append("typedef", DeclarationFragments::FragmentKind::Keyword); LeadingFragments.appendSpace(); Record->Declaration.removeTrailingSemicolon() .prepend(std::move(LeadingFragments)) .append(" { ... } ", DeclarationFragments::FragmentKind::Text) .append(Name, DeclarationFragments::FragmentKind::Identifier) .appendSemicolon(); return true; } } } PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); QualType Type = Decl->getUnderlyingType(); SymbolReference SymRef = TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, API); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( const ObjCCategoryDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the category. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); SymbolReference Interface = createSymbolReferenceForDecl(*InterfaceDecl); auto *CategoryRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Interface, isInSystemHeader(Decl)); getDerivedExtractAPIVisitor().recordObjCMethods(CategoryRecord, Decl->methods()); getDerivedExtractAPIVisitor().recordObjCProperties(CategoryRecord, Decl->properties()); getDerivedExtractAPIVisitor().recordObjCInstanceVariables(CategoryRecord, Decl->ivars()); getDerivedExtractAPIVisitor().recordObjCProtocols(CategoryRecord, Decl->protocols()); return true; } /// Collect API information for the enum constants and associate with the /// parent enum. template void ExtractAPIVisitorBase::recordEnumConstants( SymbolReference Container, const EnumDecl::enumerator_range Constants) { for (const auto *Constant : Constants) { // Collect symbol information. StringRef Name = Constant->getName(); SmallString<128> USR; index::generateUSRForDecl(Constant, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Constant->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Constant)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the enum constant. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Constant); API.createRecord( USR, Name, Container, Loc, AvailabilityInfo::createFromDecl(Constant), Comment, Declaration, SubHeading, isInSystemHeader(Constant)); } } template bool ExtractAPIVisitorBase::VisitFieldDecl(const FieldDecl *Decl) { // ObjCIvars are handled separately if (isa(Decl) || isa(Decl)) return true; if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; // Collect symbol information. StringRef Name = Decl->getName(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the struct field. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForField(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); RecordContext *NewRecord = nullptr; if (isa(Decl->getDeclContext())) { AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); NewRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Access, isInSystemHeader(Decl)); } else if (auto *RD = dyn_cast(Decl->getDeclContext())) { if (RD->isUnion()) NewRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, isInSystemHeader(Decl)); else NewRecord = API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, isInSystemHeader(Decl)); } // If this field has a non typedef'd anonymous tag type let's pretend the // type's child records are under us in the hierarchy. maybeMergeWithAnonymousTag(*Decl, NewRecord); return true; } template bool ExtractAPIVisitorBase::VisitCXXConversionDecl( const CXXConversionDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || Decl->isImplicit()) return true; auto Name = Decl->getNameAsString(); SmallString<128> USR; index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments, sub-heading, and signature for the method. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForConversionFunction(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); if (Decl->isStatic()) API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Signature, Access, isInSystemHeader(Decl)); else API.createRecord( USR, Name, createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, Signature, Access, isInSystemHeader(Decl)); return true; } /// Collect API information for the Objective-C methods and associate with the /// parent container. template void ExtractAPIVisitorBase::recordObjCMethods( ObjCContainerRecord *Container, const ObjCContainerDecl::method_range Methods) { for (const auto *Method : Methods) { // Don't record selectors for properties. if (Method->isPropertyAccessor()) continue; auto Name = Method->getSelector().getAsString(); SmallString<128> USR; index::generateUSRForDecl(Method, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Method->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Method)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments, sub-heading, and signature for the method. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Method); FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Method); if (Method->isInstanceMethod()) API.createRecord( USR, Name, createHierarchyInformationForDecl(*Method), Loc, AvailabilityInfo::createFromDecl(Method), Comment, Declaration, SubHeading, Signature, isInSystemHeader(Method)); else API.createRecord( USR, Name, createHierarchyInformationForDecl(*Method), Loc, AvailabilityInfo::createFromDecl(Method), Comment, Declaration, SubHeading, Signature, isInSystemHeader(Method)); } } template void ExtractAPIVisitorBase::recordObjCProperties( ObjCContainerRecord *Container, const ObjCContainerDecl::prop_range Properties) { for (const auto *Property : Properties) { StringRef Name = Property->getName(); SmallString<128> USR; index::generateUSRForDecl(Property, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Property->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Property)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the property. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Property); auto GetterName = Property->getGetterName().getAsString(); auto SetterName = Property->getSetterName().getAsString(); // Get the attributes for property. unsigned Attributes = ObjCPropertyRecord::NoAttr; if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly) Attributes |= ObjCPropertyRecord::ReadOnly; if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) API.createRecord( USR, Name, createHierarchyInformationForDecl(*Property), Loc, AvailabilityInfo::createFromDecl(Property), Comment, Declaration, SubHeading, static_cast(Attributes), GetterName, SetterName, Property->isOptional(), isInSystemHeader(Property)); else API.createRecord( USR, Name, createHierarchyInformationForDecl(*Property), Loc, AvailabilityInfo::createFromDecl(Property), Comment, Declaration, SubHeading, static_cast(Attributes), GetterName, SetterName, Property->isOptional(), isInSystemHeader(Property)); } } template void ExtractAPIVisitorBase::recordObjCInstanceVariables( ObjCContainerRecord *Container, const llvm::iterator_range< DeclContext::specific_decl_iterator> Ivars) { for (const auto *Ivar : Ivars) { StringRef Name = Ivar->getName(); SmallString<128> USR; index::generateUSRForDecl(Ivar, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Ivar)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); // Build declaration fragments and sub-heading for the instance variable. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForField(Ivar); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Ivar); API.createRecord( USR, Name, createHierarchyInformationForDecl(*Ivar), Loc, AvailabilityInfo::createFromDecl(Ivar), Comment, Declaration, SubHeading, isInSystemHeader(Ivar)); } } template void ExtractAPIVisitorBase::recordObjCProtocols( ObjCContainerRecord *Container, ObjCInterfaceDecl::protocol_range Protocols) { for (const auto *Protocol : Protocols) Container->Protocols.emplace_back(createSymbolReferenceForDecl(*Protocol)); } } // namespace impl /// The RecursiveASTVisitor to traverse symbol declarations and collect API /// information. template class ExtractAPIVisitor : public impl::ExtractAPIVisitorBase, ExtractAPIVisitor<>, Derived>> { using Base = impl::ExtractAPIVisitorBase, ExtractAPIVisitor<>, Derived>>; public: ExtractAPIVisitor(ASTContext &Context, APISet &API) : Base(Context, API) {} bool shouldDeclBeIncluded(const Decl *D) const { return true; } const RawComment *fetchRawCommentForDecl(const Decl *D) const { if (const auto *Comment = this->Context.getRawCommentForDeclNoCache(D)) return Comment; if (const auto *Declarator = dyn_cast(D)) { const auto *TagTypeDecl = Declarator->getType()->getAsTagDecl(); if (TagTypeDecl && TagTypeDecl->isEmbeddedInDeclarator() && TagTypeDecl->isCompleteDefinition()) return this->Context.getRawCommentForDeclNoCache(TagTypeDecl); } return nullptr; } }; } // namespace extractapi } // namespace clang #endif // LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H