diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h index 7846ad14127fe..7fc6447e93b96 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 : public std::true_type {}; +template <> +struct has_template : public std::true_type {}; +template <> +struct has_function_signature + : public std::true_type {}; +template <> +struct has_function_signature + : 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 &getGlobalFunctions() const { return GlobalFunctions; } + const RecordMap & + getGlobalFunctionTemplates() const { + return GlobalFunctionTemplates; + } + const RecordMap & + getGlobalFunctionTemplateSpecializations() const { + return GlobalFunctionTemplateSpecializations; + } const RecordMap &getGlobalVariables() const { return GlobalVariables; } @@ -1391,6 +1473,9 @@ class APISet { llvm::DenseMap USRBasedLookupTable; RecordMap GlobalFunctions; + RecordMap GlobalFunctionTemplates; + RecordMap + GlobalFunctionTemplateSpecializations; RecordMap GlobalVariables; RecordMap GlobalVariableTemplates; RecordMap diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index c2260a209ee5e..b72ce667c4d55 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); - static std::string getNameForTemplateArgument(const ArrayRef, - std::string); + static std::string + getNameForTemplateArgument(const ArrayRef, std::string); static DeclarationFragments getFragmentsForTemplateArguments(const ArrayRef, @@ -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(Function) && + dyn_cast(Function)->getDescribedFunctionTemplate() && + ReturnType.begin()->Spelling.substr(0, 14).compare("type-parameter") == + 0) { + std::string ProperArgName = + getNameForTemplateArgument(dyn_cast(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 e7746f4abc8d5..ec58dac59ae59 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -67,6 +67,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor { 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 { 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::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::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:: return true; } +template +bool ExtractAPIVisitorBase::WalkUpFromFunctionTemplateDecl( + const FunctionTemplateDecl *Decl) { + getDerivedExtractAPIVisitor().VisitFunctionTemplateDecl(Decl); + return true; +} + template bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) @@ -697,6 +709,38 @@ bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( return true; } +template +bool ExtractAPIVisitorBase::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 bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( const ObjCInterfaceDecl *Decl) { diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h index d5d23edc44978..9a2140fcd0318 100644 --- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h +++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h @@ -47,6 +47,10 @@ template class APISetVisitor { getDerived()->traverseGlobalVariableTemplatePartialSpecializationRecords(); + getDerived()->traverseGlobalFunctionTemplateRecords(); + + getDerived()->traverseGlobalFunctionTemplateSpecializationRecords(); + getDerived()->traverseStructRecords(); getDerived()->traverseObjCInterfaces(); @@ -129,6 +133,19 @@ template 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 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 102436af9bc1a..77c844a32f20e 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 { 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 4d2ab17265653..bc19630ae17e1 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 271355d4de169..8a0a628d3f735 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(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 ae8b1a67a50e9..de6654b100894 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 0000000000000..360d3b534cbde --- /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@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 void Foo(T Bar); + +template 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 0000000000000..4dc7195368363 --- /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@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 void Foo(T Bar); + +template<> void Foo(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@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" + ] + } + ] +}