blob: 97cc457ea2a9263c8ce4b5910fc85b56a0c98755 [file] [log] [blame]
//===- 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/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 <type_traits>
namespace clang {
namespace extractapi {
namespace impl {
template <typename Derived>
class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
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 VisitRecordDecl(const RecordDecl *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(EnumRecord *EnumRecord,
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<ObjCIvarDecl>>
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<Derived *>(this);
}
protected:
SmallVector<SymbolReference> getBases(const CXXRecordDecl *Decl) {
// FIXME: store AccessSpecifier given by inheritance
SmallVector<SymbolReference> Bases;
for (const auto &BaseSpecifier : Decl->bases()) {
// skip classes not inherited as public
if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public)
continue;
SymbolReference BaseClass;
if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString());
if (auto *TTPTD = BaseSpecifier.getType()
->getAs<TemplateTypeParmType>()
->getDecl()) {
SmallString<128> USR;
index::generateUSRForDecl(TTPTD, USR);
BaseClass.USR = API.copyString(USR);
BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD));
}
} else {
BaseClass = createSymbolReferenceForDecl(
*BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl());
}
Bases.emplace_back(BaseClass);
}
return Bases;
}
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<Decl>(D.getDeclContext());
if (!Context || isa<TranslationUnitDecl>(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<NamedDecl>(&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();
}
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<TagRecord>(
API.findRecordForUSR(TagUSR))) {
if (Record->IsEmbeddedInVarDeclarator) {
NewRecordContext->stealRecordChain(*Record);
auto *NewRecord = cast<APIRecord>(NewRecordContext);
if (NewRecord->Comment.empty())
NewRecord->Comment = Record->Comment;
}
}
}
};
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) {
// skip function parameters.
if (isa<ParmVarDecl>(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<StaticFieldRecord>(
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<GlobalVariableRecord>(
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 <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
const FunctionDecl *Decl) {
if (const auto *Method = dyn_cast<CXXMethodDecl>(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<CXXRecordDecl>())
return true;
}
// Skip ConstructorDecl and DestructorDecl.
if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(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.
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, sub-heading, and signature of the function.
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
FunctionSignature Signature =
DeclarationFragmentsBuilder::getFunctionSignature(Decl);
if (Decl->getTemplateSpecializationInfo())
API.createRecord<GlobalFunctionTemplateSpecializationRecord>(
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<GlobalFunctionRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment,
DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), SubHeading,
Signature, isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
return true;
SmallString<128> QualifiedNameBuffer;
// Collect symbol information.
StringRef Name = Decl->getName();
if (Name.empty())
Name = getTypedefName(Decl);
if (Name.empty()) {
llvm::raw_svector_ostream OS(QualifiedNameBuffer);
Decl->printQualifiedName(OS);
Name = QualifiedNameBuffer;
}
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);
auto *ER = API.createRecord<EnumRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
// Now collect information about the enumerators in this enum.
getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators());
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionDecl(
const FunctionDecl *Decl) {
getDerivedExtractAPIVisitor().VisitFunctionDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromRecordDecl(
const RecordDecl *Decl) {
getDerivedExtractAPIVisitor().VisitRecordDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromCXXRecordDecl(
const CXXRecordDecl *Decl) {
getDerivedExtractAPIVisitor().VisitCXXRecordDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromCXXMethodDecl(
const CXXMethodDecl *Decl) {
getDerivedExtractAPIVisitor().VisitCXXMethodDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromClassTemplateSpecializationDecl(
const ClassTemplateSpecializationDecl *Decl) {
getDerivedExtractAPIVisitor().VisitClassTemplateSpecializationDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::
WalkUpFromClassTemplatePartialSpecializationDecl(
const ClassTemplatePartialSpecializationDecl *Decl) {
getDerivedExtractAPIVisitor().VisitClassTemplatePartialSpecializationDecl(
Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromVarTemplateDecl(
const VarTemplateDecl *Decl) {
getDerivedExtractAPIVisitor().VisitVarTemplateDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromVarTemplateSpecializationDecl(
const VarTemplateSpecializationDecl *Decl) {
getDerivedExtractAPIVisitor().VisitVarTemplateSpecializationDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::
WalkUpFromVarTemplatePartialSpecializationDecl(
const VarTemplatePartialSpecializationDecl *Decl) {
getDerivedExtractAPIVisitor().VisitVarTemplatePartialSpecializationDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionTemplateDecl(
const FunctionTemplateDecl *Decl) {
getDerivedExtractAPIVisitor().VisitFunctionTemplateDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromNamespaceDecl(
const NamespaceDecl *Decl) {
getDerivedExtractAPIVisitor().VisitNamespaceDecl(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<NamespaceRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
SubHeading, isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<UnionRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
else
API.createRecord<StructRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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);
APIRecord::RecordKind Kind;
if (Decl->isUnion())
Kind = APIRecord::RecordKind::RK_Union;
else if (Decl->isStruct())
Kind = APIRecord::RecordKind::RK_Struct;
else
Kind = APIRecord::RecordKind::RK_CXXClass;
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<ClassTemplateRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, Template(Decl->getDescribedClassTemplate()), Access,
isInSystemHeader(Decl));
} else
Record = API.createRecord<CXXClassRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, Kind, Access, isInSystemHeader(Decl),
isEmbeddedInVarDeclarator(*Decl));
Record->Bases = getBases(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
const CXXMethodDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
Decl->isImplicit())
return true;
if (isa<CXXConversionDecl>(Decl))
return true;
if (isa<CXXConstructorDecl>(Decl) || isa<CXXDestructorDecl>(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<CXXMethodTemplateRecord>(
USR, Decl->getName(), 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<CXXMethodTemplateSpecializationRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::
getFragmentsForFunctionTemplateSpecialization(Decl),
SubHeading, Signature, Access, isInSystemHeader(Decl));
else if (Decl->isOverloadedOperator())
API.createRecord<CXXInstanceMethodRecord>(
USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(Decl),
SubHeading, Signature, Access, isInSystemHeader(Decl));
else if (Decl->isStatic())
API.createRecord<CXXStaticMethodRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
Signature, Access, isInSystemHeader(Decl));
else
API.createRecord<CXXInstanceMethodRecord>(
USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
Signature, Access, isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<CXXConstructorRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
Signature, Access, isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<CXXDestructorRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
Signature, Access, isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<ConceptRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
Template(Decl), isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<ClassTemplateSpecializationRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
DeclarationFragmentsBuilder::getAccessControl(Decl),
isInSystemHeader(Decl));
CTSR->Bases = getBases(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::
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<ClassTemplatePartialSpecializationRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
Template(Decl), DeclarationFragmentsBuilder::getAccessControl(Decl),
isInSystemHeader(Decl));
CTPSR->Bases = getBases(Decl);
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<CXXFieldTemplateRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl),
Template(Decl), isInSystemHeader(Decl));
else
API.createRecord<GlobalVariableTemplateRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
SubHeading, Template(Decl), isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<GlobalVariableTemplateSpecializationRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
SubHeading, isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<GlobalVariableTemplatePartialSpecializationRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
SubHeading, Template(Decl), isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitFunctionTemplateDecl(
const FunctionTemplateDecl *Decl) {
if (isa<CXXMethodDecl>(Decl->getTemplatedDecl()))
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());
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
FunctionSignature Signature =
DeclarationFragmentsBuilder::getFunctionSignature(
Decl->getTemplatedDecl());
API.createRecord<GlobalFunctionTemplateRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment,
DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Decl),
SubHeading, Signature, Template(Decl), isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<ObjCInterfaceRecord>(
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 <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<ObjCProtocolRecord>(
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 <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
const TypedefNameDecl *Decl) {
// Skip ObjC Type Parameter for now.
if (isa<ObjCTypeParamDecl>(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<TypedefRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
isInSystemHeader(Decl));
return true;
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<ObjCCategoryRecord>(
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 <typename Derived>
void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
EnumRecord *EnumRecord, 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<EnumConstantRecord>(
USR, Name, createHierarchyInformationForDecl(*Constant), Loc,
AvailabilityInfo::createFromDecl(Constant), Comment, Declaration,
SubHeading, isInSystemHeader(Constant));
}
}
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitFieldDecl(const FieldDecl *Decl) {
// ObjCIvars are handled separately
if (isa<ObjCIvarDecl>(Decl) || isa<ObjCAtDefsFieldDecl>(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<CXXRecordDecl>(Decl->getDeclContext())) {
AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
NewRecord = API.createRecord<CXXFieldRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, Access, isInSystemHeader(Decl));
} else if (auto *RD = dyn_cast<RecordDecl>(Decl->getDeclContext())) {
if (RD->isUnion())
NewRecord = API.createRecord<UnionFieldRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl));
else
NewRecord = API.createRecord<StructFieldRecord>(
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 <typename Derived>
bool ExtractAPIVisitorBase<Derived>::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<CXXStaticMethodRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, Signature, Access, isInSystemHeader(Decl));
else
API.createRecord<CXXInstanceMethodRecord>(
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 <typename Derived>
void ExtractAPIVisitorBase<Derived>::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<ObjCInstanceMethodRecord>(
USR, Name, createHierarchyInformationForDecl(*Method), Loc,
AvailabilityInfo::createFromDecl(Method), Comment, Declaration,
SubHeading, Signature, isInSystemHeader(Method));
else
API.createRecord<ObjCClassMethodRecord>(
USR, Name, createHierarchyInformationForDecl(*Method), Loc,
AvailabilityInfo::createFromDecl(Method), Comment, Declaration,
SubHeading, Signature, isInSystemHeader(Method));
}
}
template <typename Derived>
void ExtractAPIVisitorBase<Derived>::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<ObjCClassPropertyRecord>(
USR, Name, createHierarchyInformationForDecl(*Property), Loc,
AvailabilityInfo::createFromDecl(Property), Comment, Declaration,
SubHeading,
static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
GetterName, SetterName, Property->isOptional(),
isInSystemHeader(Property));
else
API.createRecord<ObjCInstancePropertyRecord>(
USR, Name, createHierarchyInformationForDecl(*Property), Loc,
AvailabilityInfo::createFromDecl(Property), Comment, Declaration,
SubHeading,
static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
GetterName, SetterName, Property->isOptional(),
isInSystemHeader(Property));
}
}
template <typename Derived>
void ExtractAPIVisitorBase<Derived>::recordObjCInstanceVariables(
ObjCContainerRecord *Container,
const llvm::iterator_range<
DeclContext::specific_decl_iterator<ObjCIvarDecl>>
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<ObjCInstanceVariableRecord>(
USR, Name, createHierarchyInformationForDecl(*Ivar), Loc,
AvailabilityInfo::createFromDecl(Ivar), Comment, Declaration,
SubHeading, isInSystemHeader(Ivar));
}
}
template <typename Derived>
void ExtractAPIVisitorBase<Derived>::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 <typename Derived = void>
class ExtractAPIVisitor
: public impl::ExtractAPIVisitorBase<std::conditional_t<
std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>> {
using Base = impl::ExtractAPIVisitorBase<std::conditional_t<
std::is_same_v<Derived, void>, 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 {
return this->Context.getRawCommentForDeclNoCache(D);
}
};
} // namespace extractapi
} // namespace clang
#endif // LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H