diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h --- a/clang/include/clang/ExtractAPI/API.h +++ b/clang/include/clang/ExtractAPI/API.h @@ -60,6 +60,8 @@ enum RecordKind { RK_Unknown, RK_GlobalFunction, + RK_GlobalFunctionTemplate, + RK_GlobalFunctionTemplateSpecialization, RK_GlobalVariable, RK_GlobalVariableTemplate, RK_GlobalVariableTemplateSpecialization, @@ -179,6 +181,16 @@ 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; } @@ -187,6 +199,44 @@ 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 GlobalFunctionTemplateSpecRecord : GlobalFunctionRecord { + GlobalFunctionTemplateSpecRecord( + 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, @@ -903,6 +953,12 @@ struct has_function_signature : public std::true_type {}; template <> struct has_function_signature : public std::true_type {}; +template <> +struct has_function_signature + : public std::true_type {}; +template <> +struct has_function_signature + : public std::true_type {}; template struct has_access : public std::false_type {}; template <> struct has_access : public std::true_type {}; @@ -918,6 +974,8 @@ template <> struct has_template : public std::true_type {}; +template <> +struct has_template : public std::true_type {}; /// APISet holds the set of API records collected from given inputs. class APISet { @@ -955,6 +1013,20 @@ 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); + + GlobalFunctionTemplateSpecRecord *addGlobalFunctionTemplateSpec( + 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 @@ -1197,6 +1269,14 @@ const RecordMap &getGlobalFunctions() const { return GlobalFunctions; } + const RecordMap & + getGlobalFunctionTemplates() const { + return GlobalFunctionTemplates; + } + const RecordMap & + getGlobalFunctionTemplateSpecializations() const { + return GlobalFunctionTemplateSpecializations; + } const RecordMap &getGlobalVariables() const { return GlobalVariables; } @@ -1283,6 +1363,9 @@ 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 --- a/clang/include/clang/ExtractAPI/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -334,7 +334,8 @@ return Template; } - static Template getTemplate(const VarTemplatePartialSpecializationDecl *Decl) { + static Template + getTemplate(const VarTemplatePartialSpecializationDecl *Decl) { Template Template; for (auto *const Parameter : *Decl->getTemplateParameters()) { const auto *Param = dyn_cast(Parameter); @@ -355,7 +356,8 @@ return Template; } - static Template getTemplate(const ClassTemplatePartialSpecializationDecl *Decl) { + static Template + getTemplate(const ClassTemplatePartialSpecializationDecl *Decl) { Template Template; for (auto *const Parameter : *Decl->getTemplateParameters()) { const auto *Param = dyn_cast(Parameter); @@ -414,8 +416,8 @@ 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, @@ -439,6 +441,12 @@ 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 @@ -513,10 +521,21 @@ 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 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -89,6 +89,8 @@ bool WalkUpFromVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *Decl); + bool WalkUpFromFunctionTemplateDecl(const FunctionTemplateDecl *Decl); + bool VisitRecordDecl(const RecordDecl *Decl); bool VisitCXXRecordDecl(const CXXRecordDecl *Decl); @@ -109,6 +111,8 @@ bool VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *Decl); + bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *Decl); + bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl); bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl); @@ -267,13 +271,8 @@ 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: @@ -296,17 +295,23 @@ 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.addGlobalFunctionTemplateSpec( + 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; } @@ -404,6 +409,13 @@ 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)) @@ -716,6 +728,39 @@ 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, DeclarationFragmentsBuilder::getTemplate(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 --- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h +++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h @@ -47,6 +47,10 @@ getDerived()->traverseGlobalVariableTemplatePartialSpecRecords(); + getDerived()->traverseGlobalFunctionTemplateRecords(); + + getDerived()->traverseGlobalFunctionTemplateSpecRecords(); + getDerived()->traverseStructRecords(); getDerived()->traverseObjCInterfaces(); @@ -125,6 +129,19 @@ *GlobalVariableTemplatePartialSpec.second); } + void traverseGlobalFunctionTemplateRecords() { + for (const auto &GlobalFunctionTemplate : API.getGlobalFunctionTemplates()) + getDerived()->visitGlobalFunctionTemplateRecord( + *GlobalFunctionTemplate.second); + } + + void traverseGlobalFunctionTemplateSpecRecords() { + for (const auto &GlobalFunctionTemplateSpec : + API.getGlobalFunctionTemplateSpecializations()) + getDerived()->visitGlobalFunctionTemplateSpecRecord( + *GlobalFunctionTemplateSpec.second); + } + void traverseConcepts() { for (const auto &Concept : API.getConcepts()) getDerived()->visitConceptRecord(*Concept.second); @@ -182,6 +199,12 @@ void visitGlobalVariableTemplatePartialSpecRecord( const GlobalVariableTemplatePartialSpecRecord &Record){}; + void visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord &Record){}; + + void visitGlobalFunctionTemplateSpecRecord( + const GlobalFunctionTemplateSpecRecord &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 --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h @@ -186,6 +186,12 @@ void visitGlobalVariableTemplatePartialSpecRecord( const GlobalVariableTemplatePartialSpecRecord &Record); + void + visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record); + + void visitGlobalFunctionTemplateSpecRecord( + const GlobalFunctionTemplateSpecRecord &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 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -78,6 +78,30 @@ 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); +} + +GlobalFunctionTemplateSpecRecord *APISet::addGlobalFunctionTemplateSpec( + 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 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -493,6 +493,16 @@ 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 @@ // 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 @@ .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 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -355,6 +355,14 @@ 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"; @@ -933,6 +941,22 @@ Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpec)); } +void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord &Record) { + auto GlobalFunctionTemplate = serializeAPIRecord(Record); + if (!GlobalFunctionTemplate) + return; + Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); +} + +void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecRecord( + const GlobalFunctionTemplateSpecRecord &Record) { + auto GlobalFunctionTemplateSpec= serializeAPIRecord(Record); + if (!GlobalFunctionTemplateSpec) + return; + Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpec)); +} + 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 --- /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 --- /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" + ] + } + ] +}