[clang] 80b787e - [clang][ExtractAPI] Add support for C++ global function templates
Erick Velez via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 18 17:42:22 PDT 2023
Author: Erick Velez
Date: 2023-08-18T17:42:05-07:00
New Revision: 80b787e803292119f30da2e1e95acff5beea61db
URL: https://github.com/llvm/llvm-project/commit/80b787e803292119f30da2e1e95acff5beea61db
DIFF: https://github.com/llvm/llvm-project/commit/80b787e803292119f30da2e1e95acff5beea61db.diff
LOG: [clang][ExtractAPI] Add support for C++ global function templates
Add records, serialization for global function templates and their specializations
Depends on D157350
Reviewed By: dang
Differential Revision: https://reviews.llvm.org/D157579
Added:
clang/test/ExtractAPI/global_func_template.cpp
clang/test/ExtractAPI/global_func_template_spec.cpp
Modified:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/DeclarationFragments.h
clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
clang/lib/ExtractAPI/API.cpp
clang/lib/ExtractAPI/DeclarationFragments.cpp
clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index 7846ad14127fe4..7fc6447e93b961 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -158,6 +158,8 @@ struct APIRecord {
enum RecordKind {
RK_Unknown,
RK_GlobalFunction,
+ RK_GlobalFunctionTemplate,
+ RK_GlobalFunctionTemplateSpecialization,
RK_GlobalVariable,
RK_GlobalVariableTemplate,
RK_GlobalVariableTemplateSpecialization,
@@ -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;
}
@@ -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,
@@ -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:
@@ -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
@@ -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;
}
@@ -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>
diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h
index c2260a209ee5e1..b72ce667c4d55a 100644
--- a/clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -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>,
@@ -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
@@ -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())
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index e7746f4abc8d57..ec58dac59ae59d 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -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);
@@ -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);
@@ -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:
@@ -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;
}
@@ -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))
@@ -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) {
diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
index d5d23edc449788..9a2140fcd0318f 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -47,6 +47,10 @@ template <typename Derived> class APISetVisitor {
getDerived()->traverseGlobalVariableTemplatePartialSpecializationRecords();
+ getDerived()->traverseGlobalFunctionTemplateRecords();
+
+ getDerived()->traverseGlobalFunctionTemplateSpecializationRecords();
+
getDerived()->traverseStructRecords();
getDerived()->traverseObjCInterfaces();
@@ -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);
@@ -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){};
diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
index 102436af9bc1a3..77c844a32f20ec 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -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);
diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp
index 4d2ab172656533..bc19630ae17e1f 100644
--- a/clang/lib/ExtractAPI/API.cpp
+++ b/clang/lib/ExtractAPI/API.cpp
@@ -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,
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 271355d4de169b..8a0a628d3f7354 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -493,6 +493,16 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
DeclarationFragments TypeFragments =
getFragmentsForType(T, Param->getASTContext(), After);
+ if (TypeFragments.begin()->Spelling.substr(0, 14).compare("type-parameter") ==
+ 0) {
+ std::string ProperArgName = getNameForTemplateArgument(
+ dyn_cast<FunctionDecl>(Param->getDeclContext())
+ ->getDescribedFunctionTemplate()
+ ->getTemplateParameters()
+ ->asArray(),
+ TypeFragments.begin()->Spelling);
+ TypeFragments.begin()->Spelling.swap(ProperArgName);
+ }
if (Param->isObjCMethodParameter())
Fragments.append("(", DeclarationFragments::FragmentKind::Text)
@@ -536,12 +546,35 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
// FIXME: Is `after` actually needed here?
DeclarationFragments After;
- Fragments
- .append(getFragmentsForType(Func->getReturnType(), Func->getASTContext(),
- After))
+ auto ReturnValueFragment =
+ getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After);
+ if (ReturnValueFragment.begin()->Spelling.substr(0, 14).compare(
+ "type-parameter") == 0) {
+ std::string ProperArgName =
+ getNameForTemplateArgument(Func->getDescribedFunctionTemplate()
+ ->getTemplateParameters()
+ ->asArray(),
+ ReturnValueFragment.begin()->Spelling);
+ ReturnValueFragment.begin()->Spelling.swap(ProperArgName);
+ }
+
+ Fragments.append(std::move(ReturnValueFragment))
.appendSpace()
- .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier)
- .append(std::move(After));
+ .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+ if (Func->getTemplateSpecializationInfo()) {
+ Fragments.append("<", DeclarationFragments::FragmentKind::Text);
+
+ for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(
+ getFragmentsForType(Func->getParamDecl(i)->getType(),
+ Func->getParamDecl(i)->getASTContext(), After));
+ }
+ Fragments.append(">", DeclarationFragments::FragmentKind::Text);
+ }
+ Fragments.append(std::move(After));
Fragments.append("(", DeclarationFragments::FragmentKind::Text);
for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
@@ -974,6 +1007,33 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization(
.append(";", DeclarationFragments::FragmentKind::Text);
}
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
+ const FunctionTemplateDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ // Partial specs may have new params.
+ .append(getFragmentsForTemplateParameters(
+ Decl->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForFunction(
+ Decl->getAsFunction()));
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization(
+ const FunctionDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .append("<>", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForFunction(Decl));
+}
+
DeclarationFragments
DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name,
const MacroDirective *MD) {
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index ae8b1a67a50e9b..de6654b1008940 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -361,6 +361,14 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
Kind["identifier"] = AddLangPrefix("func");
Kind["displayName"] = "Function";
break;
+ case APIRecord::RK_GlobalFunctionTemplate:
+ Kind["identifier"] = AddLangPrefix("func");
+ Kind["displayName"] = "Function Template";
+ break;
+ case APIRecord::RK_GlobalFunctionTemplateSpecialization:
+ Kind["identifier"] = AddLangPrefix("func");
+ Kind["displayName"] = "Function Template Specialization";
+ break;
case APIRecord::RK_GlobalVariableTemplate:
Kind["identifier"] = AddLangPrefix("var");
Kind["displayName"] = "Global Variable Template";
@@ -947,6 +955,22 @@ void SymbolGraphSerializer::
Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization));
}
+void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
+ const GlobalFunctionTemplateRecord &Record) {
+ auto GlobalFunctionTemplate = serializeAPIRecord(Record);
+ if (!GlobalFunctionTemplate)
+ return;
+ Symbols.emplace_back(std::move(*GlobalFunctionTemplate));
+}
+
+void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord(
+ const GlobalFunctionTemplateSpecializationRecord &Record) {
+ auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record);
+ if (!GlobalFunctionTemplateSpecialization)
+ return;
+ Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization));
+}
+
void SymbolGraphSerializer::visitObjCContainerRecord(
const ObjCContainerRecord &Record) {
auto ObjCContainer = serializeAPIRecord(Record);
diff --git a/clang/test/ExtractAPI/global_func_template.cpp b/clang/test/ExtractAPI/global_func_template.cpp
new file mode 100644
index 00000000000000..360d3b534cbded
--- /dev/null
+++ b/clang/test/ExtractAPI/global_func_template.cpp
@@ -0,0 +1,315 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at INPUT_DIR@%{/t:regex_replacement}@g" \
+// RUN: %t/reference.output.json.in >> %t/reference.output.json
+// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \
+// RUN: -x c++-header %t/input.h -o %t/output.json -verify
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN:
diff %t/reference.output.json %t/output-normalized.json
+
+//--- input.h
+template<typename T> void Foo(T Bar);
+
+template<typename T> T Fizz(int Buzz);
+/// expected-no-diagnostics
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationships": [],
+ "symbols": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "template"
+ },
+ {
+ "kind": "text",
+ "spelling": "<"
+ },
+ {
+ "kind": "keyword",
+ "spelling": "typename"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "genericParameter",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": "> "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ },
+ {
+ "kind": "text",
+ "spelling": "("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:t0.0",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Bar"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:t0.0",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Bar"
+ }
+ ],
+ "name": "Bar"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@FT@>1#TFoo#t0.0#v#"
+ },
+ "kind": {
+ "displayName": "Function Template",
+ "identifier": "c++.func"
+ },
+ "location": {
+ "position": {
+ "character": 27,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "title": "Foo"
+ },
+ "pathComponents": [
+ "Foo"
+ ],
+ "swiftGenerics": {
+ "parameters": [
+ {
+ "depth": 0,
+ "index": 0,
+ "name": "T"
+ }
+ ]
+ }
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "template"
+ },
+ {
+ "kind": "text",
+ "spelling": "<"
+ },
+ {
+ "kind": "keyword",
+ "spelling": "typename"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "genericParameter",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": "> "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:t0.0",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Fizz"
+ },
+ {
+ "kind": "text",
+ "spelling": "("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Buzz"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Buzz"
+ }
+ ],
+ "name": "Buzz"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:t0.0",
+ "spelling": "T"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@FT@>1#TFizz#I#t0.0#"
+ },
+ "kind": {
+ "displayName": "Function Template",
+ "identifier": "c++.func"
+ },
+ "location": {
+ "position": {
+ "character": 24,
+ "line": 3
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Fizz"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Fizz"
+ }
+ ],
+ "title": "Fizz"
+ },
+ "pathComponents": [
+ "Fizz"
+ ],
+ "swiftGenerics": {
+ "parameters": [
+ {
+ "depth": 0,
+ "index": 0,
+ "name": "T"
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/clang/test/ExtractAPI/global_func_template_spec.cpp b/clang/test/ExtractAPI/global_func_template_spec.cpp
new file mode 100644
index 00000000000000..4dc71953683632
--- /dev/null
+++ b/clang/test/ExtractAPI/global_func_template_spec.cpp
@@ -0,0 +1,299 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at INPUT_DIR@%{/t:regex_replacement}@g" \
+// RUN: %t/reference.output.json.in >> %t/reference.output.json
+// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \
+// RUN: -x c++-header %t/input.h -o %t/output.json -verify
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN:
diff %t/reference.output.json %t/output-normalized.json
+
+//--- input.h
+template<typename T> void Foo(T Bar);
+
+template<> void Foo<int>(int Bar);
+/// expected-no-diagnostics
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationships": [],
+ "symbols": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "template"
+ },
+ {
+ "kind": "text",
+ "spelling": "<"
+ },
+ {
+ "kind": "keyword",
+ "spelling": "typename"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "genericParameter",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": "> "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ },
+ {
+ "kind": "text",
+ "spelling": "("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:t0.0",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Bar"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:t0.0",
+ "spelling": "T"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Bar"
+ }
+ ],
+ "name": "Bar"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@FT@>1#TFoo#t0.0#v#"
+ },
+ "kind": {
+ "displayName": "Function Template",
+ "identifier": "c++.func"
+ },
+ "location": {
+ "position": {
+ "character": 27,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "title": "Foo"
+ },
+ "pathComponents": [
+ "Foo"
+ ],
+ "swiftGenerics": {
+ "parameters": [
+ {
+ "depth": 0,
+ "index": 0,
+ "name": "T"
+ }
+ ]
+ }
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "template"
+ },
+ {
+ "kind": "text",
+ "spelling": "<> "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ },
+ {
+ "kind": "text",
+ "spelling": "<"
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": ">("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Bar"
+ },
+ {
+ "kind": "text",
+ "spelling": ");"
+ }
+ ],
+ "functionSignature": {
+ "parameters": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "internalParam",
+ "spelling": "Bar"
+ }
+ ],
+ "name": "Bar"
+ }
+ ],
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c++",
+ "precise": "c:@F at Foo<#I>#I#"
+ },
+ "kind": {
+ "displayName": "Function Template Specialization",
+ "identifier": "c++.func"
+ },
+ "location": {
+ "position": {
+ "character": 17,
+ "line": 3
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Foo"
+ }
+ ],
+ "title": "Foo"
+ },
+ "pathComponents": [
+ "Foo"
+ ]
+ }
+ ]
+}
More information about the cfe-commits
mailing list