Skip to content

Commit

Permalink
[clang][ExtractAPI] Add support for C++ global function templates
Browse files Browse the repository at this point in the history
Add records, serialization for global function templates and their specializations

Depends on D157350

Reviewed By: dang

Differential Revision: https://reviews.llvm.org/D157579
  • Loading branch information
evelez7 committed Aug 19, 2023
1 parent 3e56988 commit 80b787e
Show file tree
Hide file tree
Showing 10 changed files with 920 additions and 22 deletions.
85 changes: 85 additions & 0 deletions clang/include/clang/ExtractAPI/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ struct APIRecord {
enum RecordKind {
RK_Unknown,
RK_GlobalFunction,
RK_GlobalFunctionTemplate,
RK_GlobalFunctionTemplateSpecialization,
RK_GlobalVariable,
RK_GlobalVariableTemplate,
RK_GlobalVariableTemplateSpecialization,
Expand Down Expand Up @@ -281,6 +283,16 @@ struct GlobalFunctionRecord : APIRecord {
IsFromSystemHeader),
Signature(Signature) {}

GlobalFunctionRecord(RecordKind Kind, StringRef USR, StringRef Name,
PresumedLoc Loc, AvailabilitySet Availabilities,
LinkageInfo Linkage, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading,
FunctionSignature Signature, bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Loc, std::move(Availabilities), Linkage,
Comment, Declaration, SubHeading, IsFromSystemHeader),
Signature(Signature) {}

static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_GlobalFunction;
}
Expand All @@ -289,6 +301,44 @@ struct GlobalFunctionRecord : APIRecord {
virtual void anchor();
};

struct GlobalFunctionTemplateRecord : GlobalFunctionRecord {
Template Templ;

GlobalFunctionTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilitySet Availabilities,
LinkageInfo Linkage, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading,
FunctionSignature Signature, Template Template,
bool IsFromSystemHeader)
: GlobalFunctionRecord(RK_GlobalFunctionTemplate, USR, Name, Loc,
std::move(Availabilities), Linkage, Comment,
Declaration, SubHeading, Signature,
IsFromSystemHeader),
Templ(Template) {}

static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_GlobalFunctionTemplate;
}
};

struct GlobalFunctionTemplateSpecializationRecord : GlobalFunctionRecord {
GlobalFunctionTemplateSpecializationRecord(
StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature,
bool IsFromSystemHeader)
: GlobalFunctionRecord(RK_GlobalFunctionTemplateSpecialization, USR, Name,
Loc, std::move(Availabilities), Linkage, Comment,
Declaration, SubHeading, Signature,
IsFromSystemHeader) {}

static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_GlobalFunctionTemplateSpecialization;
}
};

/// This holds information associated with global functions.
struct GlobalVariableRecord : APIRecord {
GlobalVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
Expand Down Expand Up @@ -1025,6 +1075,15 @@ template <>
struct has_template<GlobalVariableTemplatePartialSpecializationRecord>
: public std::true_type {};

template <>
struct has_template<GlobalFunctionTemplateRecord> : public std::true_type {};
template <>
struct has_function_signature<GlobalFunctionTemplateRecord>
: public std::true_type {};
template <>
struct has_function_signature<GlobalFunctionTemplateSpecializationRecord>
: public std::true_type {};

/// APISet holds the set of API records collected from given inputs.
class APISet {
public:
Expand Down Expand Up @@ -1061,6 +1120,21 @@ class APISet {
DeclarationFragments SubHeading,
FunctionSignature Signature, bool IsFromSystemHeader);

GlobalFunctionTemplateRecord *addGlobalFunctionTemplate(
StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature,
Template Template, bool IsFromSystemHeader);

GlobalFunctionTemplateSpecializationRecord *
addGlobalFunctionTemplateSpecialization(
StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature,
bool IsFromSystemHeader);

/// Create and add an enum constant record into the API set.
///
/// Note: the caller is responsible for keeping the StringRef \p Name and
Expand Down Expand Up @@ -1305,6 +1379,14 @@ class APISet {
const RecordMap<GlobalFunctionRecord> &getGlobalFunctions() const {
return GlobalFunctions;
}
const RecordMap<GlobalFunctionTemplateRecord> &
getGlobalFunctionTemplates() const {
return GlobalFunctionTemplates;
}
const RecordMap<GlobalFunctionTemplateSpecializationRecord> &
getGlobalFunctionTemplateSpecializations() const {
return GlobalFunctionTemplateSpecializations;
}
const RecordMap<GlobalVariableRecord> &getGlobalVariables() const {
return GlobalVariables;
}
Expand Down Expand Up @@ -1391,6 +1473,9 @@ class APISet {

llvm::DenseMap<StringRef, APIRecord *> USRBasedLookupTable;
RecordMap<GlobalFunctionRecord> GlobalFunctions;
RecordMap<GlobalFunctionTemplateRecord> GlobalFunctionTemplates;
RecordMap<GlobalFunctionTemplateSpecializationRecord>
GlobalFunctionTemplateSpecializations;
RecordMap<GlobalVariableRecord> GlobalVariables;
RecordMap<GlobalVariableTemplateRecord> GlobalVariableTemplates;
RecordMap<GlobalVariableTemplateSpecializationRecord>
Expand Down
29 changes: 23 additions & 6 deletions clang/include/clang/ExtractAPI/DeclarationFragments.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,8 @@ class DeclarationFragmentsBuilder {
static DeclarationFragments
getFragmentsForTemplateParameters(ArrayRef<NamedDecl *>);

static std::string getNameForTemplateArgument(const ArrayRef<NamedDecl *>,
std::string);
static std::string
getNameForTemplateArgument(const ArrayRef<NamedDecl *>, std::string);

static DeclarationFragments
getFragmentsForTemplateArguments(const ArrayRef<TemplateArgument>,
Expand All @@ -331,6 +331,12 @@ class DeclarationFragmentsBuilder {
static DeclarationFragments getFragmentsForVarTemplatePartialSpecialization(
const VarTemplatePartialSpecializationDecl *);

static DeclarationFragments
getFragmentsForFunctionTemplate(const FunctionTemplateDecl *Decl);

static DeclarationFragments
getFragmentsForFunctionTemplateSpecialization(const FunctionDecl *Decl);

/// Build DeclarationFragments for an Objective-C category declaration
/// ObjCCategoryDecl.
static DeclarationFragments
Expand Down Expand Up @@ -405,10 +411,21 @@ DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
FunctionSignature Signature;

DeclarationFragments ReturnType, After;
ReturnType
.append(getFragmentsForType(Function->getReturnType(),
Function->getASTContext(), After))
.append(std::move(After));
ReturnType = getFragmentsForType(Function->getReturnType(),
Function->getASTContext(), After);
if (isa<FunctionDecl>(Function) &&
dyn_cast<FunctionDecl>(Function)->getDescribedFunctionTemplate() &&
ReturnType.begin()->Spelling.substr(0, 14).compare("type-parameter") ==
0) {
std::string ProperArgName =
getNameForTemplateArgument(dyn_cast<FunctionDecl>(Function)
->getDescribedFunctionTemplate()
->getTemplateParameters()
->asArray(),
ReturnType.begin()->Spelling);
ReturnType.begin()->Spelling.swap(ProperArgName);
}
ReturnType.append(std::move(After));
Signature.setReturnType(ReturnType);

for (const auto *Param : Function->parameters())
Expand Down
66 changes: 55 additions & 11 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
bool WalkUpFromVarTemplatePartialSpecializationDecl(
const VarTemplatePartialSpecializationDecl *Decl);

bool WalkUpFromFunctionTemplateDecl(const FunctionTemplateDecl *Decl);

bool VisitRecordDecl(const RecordDecl *Decl);

bool VisitCXXRecordDecl(const CXXRecordDecl *Decl);
Expand All @@ -87,6 +89,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
bool VisitVarTemplatePartialSpecializationDecl(
const VarTemplatePartialSpecializationDecl *Decl);

bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *Decl);

bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl);

bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl);
Expand Down Expand Up @@ -283,13 +287,8 @@ bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
switch (Decl->getTemplatedKind()) {
case FunctionDecl::TK_NonTemplate:
case FunctionDecl::TK_DependentNonTemplate:
break;
case FunctionDecl::TK_MemberSpecialization:
case FunctionDecl::TK_FunctionTemplateSpecialization:
if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
return true;
}
break;
case FunctionDecl::TK_FunctionTemplate:
case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
Expand All @@ -312,17 +311,23 @@ bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
Context.getDiagnostics());

// Build declaration fragments, sub-heading, and signature of the function.
DeclarationFragments Declaration =
DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
FunctionSignature Signature =
DeclarationFragmentsBuilder::getFunctionSignature(Decl);

// Add the function record to the API set.
API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
Declaration, SubHeading, Signature,
isInSystemHeader(Decl));
if (Decl->getTemplateSpecializationInfo())
API.addGlobalFunctionTemplateSpecialization(
Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
DeclarationFragmentsBuilder::
getFragmentsForFunctionTemplateSpecialization(Decl),
SubHeading, Signature, isInSystemHeader(Decl));
else
// Add the function record to the API set.
API.addGlobalFunction(
Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), SubHeading,
Signature, isInSystemHeader(Decl));
return true;
}

Expand Down Expand Up @@ -420,6 +425,13 @@ bool ExtractAPIVisitorBase<Derived>::
return true;
}

template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionTemplateDecl(
const FunctionTemplateDecl *Decl) {
getDerivedExtractAPIVisitor().VisitFunctionTemplateDecl(Decl);
return true;
}

template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
Expand Down Expand Up @@ -697,6 +709,38 @@ bool ExtractAPIVisitorBase<Derived>::VisitVarTemplatePartialSpecializationDecl(
return true;
}

template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitFunctionTemplateDecl(
const FunctionTemplateDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
return true;

// Collect symbol information.
StringRef Name = Decl->getName();
StringRef USR = API.recordUSR(Decl);
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.addGlobalFunctionTemplate(
Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Decl),
SubHeading, Signature, Template(Decl), isInSystemHeader(Decl));

return true;
}

template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
const ObjCInterfaceDecl *Decl) {
Expand Down
23 changes: 23 additions & 0 deletions clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ template <typename Derived> class APISetVisitor {

getDerived()->traverseGlobalVariableTemplatePartialSpecializationRecords();

getDerived()->traverseGlobalFunctionTemplateRecords();

getDerived()->traverseGlobalFunctionTemplateSpecializationRecords();

getDerived()->traverseStructRecords();

getDerived()->traverseObjCInterfaces();
Expand Down Expand Up @@ -129,6 +133,19 @@ template <typename Derived> class APISetVisitor {
*GlobalVariableTemplatePartialSpecialization.second);
}

void traverseGlobalFunctionTemplateRecords() {
for (const auto &GlobalFunctionTemplate : API.getGlobalFunctionTemplates())
getDerived()->visitGlobalFunctionTemplateRecord(
*GlobalFunctionTemplate.second);
}

void traverseGlobalFunctionTemplateSpecializationRecords() {
for (const auto &GlobalFunctionTemplateSpecialization :
API.getGlobalFunctionTemplateSpecializations())
getDerived()->visitGlobalFunctionTemplateSpecializationRecord(
*GlobalFunctionTemplateSpecialization.second);
}

void traverseConcepts() {
for (const auto &Concept : API.getConcepts())
getDerived()->visitConceptRecord(*Concept.second);
Expand Down Expand Up @@ -192,6 +209,12 @@ template <typename Derived> class APISetVisitor {
void visitGlobalVariableTemplatePartialSpecializationRecord(
const GlobalVariableTemplatePartialSpecializationRecord &Record){};

void visitGlobalFunctionTemplateRecord(
const GlobalFunctionTemplateRecord &Record){};

void visitGlobalFunctionTemplateSpecializationRecord(
const GlobalFunctionTemplateSpecializationRecord &Record){};

/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record){};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
void visitGlobalVariableTemplatePartialSpecializationRecord(
const GlobalVariableTemplatePartialSpecializationRecord &Record);

void
visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record);

void visitGlobalFunctionTemplateSpecializationRecord(
const GlobalFunctionTemplateSpecializationRecord &Record);

/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record);

Expand Down
25 changes: 25 additions & 0 deletions clang/lib/ExtractAPI/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,31 @@ GlobalFunctionRecord *APISet::addGlobalFunction(
IsFromSystemHeader);
}

GlobalFunctionTemplateRecord *APISet::addGlobalFunctionTemplate(
StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature,
Template Template, bool IsFromSystemHeader) {
return addTopLevelRecord(USRBasedLookupTable, GlobalFunctionTemplates, USR,
Name, Loc, std::move(Availability), Linkage, Comment,
Declaration, SubHeading, Signature, Template,
IsFromSystemHeader);
}

GlobalFunctionTemplateSpecializationRecord *
APISet::addGlobalFunctionTemplateSpecialization(
StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature,
bool IsFromSystemHeader) {
return addTopLevelRecord(
USRBasedLookupTable, GlobalFunctionTemplateSpecializations, USR, Name,
Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading,
Signature, IsFromSystemHeader);
}

EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
StringRef USR, PresumedLoc Loc,
AvailabilitySet Availabilities,
Expand Down

0 comments on commit 80b787e

Please sign in to comment.