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 @@ -82,6 +82,8 @@ RK_CXXInstanceMethod, RK_CXXConstructorMethod, RK_CXXDestructorMethod, + RK_CXXMethodTemplate, + RK_CXXMethodTemplateSpecialization, RK_ObjCInstanceProperty, RK_ObjCClassProperty, RK_ObjCIvar, @@ -520,6 +522,43 @@ virtual void anchor(); }; +struct CXXMethodTemplateRecord : CXXMethodRecord { + Template Templ; + + CXXMethodTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilitySet Availabilities, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + Template Template, bool IsFromSystemHeader) + : CXXMethodRecord(RK_CXXMethodTemplate, USR, Name, Loc, + std::move(Availabilities), Comment, Declaration, + SubHeading, Signature, Access, IsFromSystemHeader), + Templ(Template) {} + + static bool classof(const APIRecord *Record) { + return Record->getKind() == RK_CXXMethodTemplate; + } +}; + +struct CXXMethodTemplateSpecRecord : CXXMethodRecord { + CXXMethodTemplateSpecRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilitySet Availabilities, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader) + : CXXMethodRecord(RK_CXXMethodTemplateSpecialization, USR, Name, Loc, + std::move(Availabilities), Comment, Declaration, + SubHeading, Signature, Access, IsFromSystemHeader) {} + + static bool classof(const APIRecord *Record) { + return Record->getKind() == RK_CXXMethodTemplateSpecialization; + } +}; + /// This holds information associated with Objective-C properties. struct ObjCPropertyRecord : APIRecord { /// The attributes associated with an Objective-C property. @@ -691,6 +730,8 @@ : Name(Name), USR(USR), Source(Source) {} SymbolReference(const APIRecord &Record) : Name(Record.Name), USR(Record.USR) {} + SymbolReference(const APIRecord *Record) + : Name(Record->Name), USR(Record->USR) {} /// Determine if this SymbolReference is empty. /// @@ -959,10 +1000,21 @@ 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 {}; template <> struct has_access : public std::true_type {}; +template <> +struct has_access : public std::true_type {}; +template <> +struct has_access + : public std::true_type {}; template struct has_template : public std::false_type {}; template <> struct has_template : public std::true_type {}; @@ -976,6 +1028,8 @@ : public std::true_type {}; 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 { @@ -1143,6 +1197,20 @@ FunctionSignature Signature, bool IsConstructor, AccessControl Access, bool IsFromSystemHeader); + CXXMethodTemplateRecord *addCXXMethodTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, Template Template, + bool IsFromSystemHeader); + + CXXMethodTemplateSpecRecord *addCXXMethodTemplateSpec( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader); + ConceptRecord *addConcept(StringRef Name, StringRef USR, PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment, @@ -1298,6 +1366,13 @@ const RecordMap &getEnums() const { return Enums; } const RecordMap &getStructs() const { return Structs; } const RecordMap &getCXXClasses() const { return CXXClasses; } + const RecordMap &getCXXMethodTemplates() const { + return CXXMethodTemplates; + } + const RecordMap & + getCXXMethodTemplateSpecializations() const { + return CXXMethodTemplateSpecializations; + } const RecordMap &getConcepts() const { return Concepts; } const RecordMap &getClassTemplates() const { return ClassTemplates; @@ -1377,6 +1452,8 @@ RecordMap Enums; RecordMap Structs; RecordMap CXXClasses; + RecordMap CXXMethodTemplates; + RecordMap CXXMethodTemplateSpecializations; RecordMap ClassTemplates; RecordMap ClassTemplateSpecializations; RecordMap ClassTemplatePartialSpecializations; 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 @@ -16,17 +16,16 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" -#include "clang/Basic/OperatorKinds.h" -#include "clang/Basic/Specifiers.h" -#include "clang/ExtractAPI/DeclarationFragments.h" -#include "llvm/ADT/FunctionExtras.h" - -#include "clang/AST/ASTContext.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/ExtractAPI/API.h" +#include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" +#include "clang/Index/USRGeneration.h" +#include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringRef.h" #include @@ -53,6 +52,8 @@ bool WalkUpFromCXXRecordDecl(const CXXRecordDecl *Decl); + bool WalkUpFromCXXMethodDecl(const CXXMethodDecl *Decl); + bool WalkUpFromClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *Decl); @@ -73,6 +74,8 @@ bool VisitCXXRecordDecl(const CXXRecordDecl *Decl); + bool VisitCXXMethodDecl(const CXXMethodDecl *Decl); + bool VisitConceptDecl(const ConceptDecl *Decl); bool VisitClassTemplateSpecializationDecl( @@ -264,11 +267,11 @@ switch (Decl->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: case FunctionDecl::TK_DependentNonTemplate: - case FunctionDecl::TK_MemberSpecialization: case FunctionDecl::TK_FunctionTemplateSpecialization: break; case FunctionDecl::TK_FunctionTemplate: case FunctionDecl::TK_DependentFunctionTemplateSpecialization: + case FunctionDecl::TK_MemberSpecialization: return true; } @@ -364,6 +367,13 @@ return true; } +template +bool ExtractAPIVisitorBase::WalkUpFromCXXMethodDecl( + const CXXMethodDecl *Decl) { + getDerivedExtractAPIVisitor().VisitCXXMethodDecl(Decl); + return true; +} + template bool ExtractAPIVisitorBase::WalkUpFromClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *Decl) { @@ -512,6 +522,60 @@ return true; } +template +bool ExtractAPIVisitorBase::VisitCXXMethodDecl( + const CXXMethodDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || + Decl->isImplicit()) + return true; + switch (Decl->getTemplatedKind()) { + case FunctionDecl::TK_MemberSpecialization: + case FunctionDecl::TK_FunctionTemplateSpecialization: + case FunctionDecl::TK_FunctionTemplate: + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: + break; + case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_DependentNonTemplate: + return true; + } + + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); + if (Decl->isTemplated()) { + FunctionTemplateDecl *Template = Decl->getDescribedFunctionTemplate(); + API.addCXXMethodTemplate( + API.findRecordForUSR(ParentUSR), Name, USR, Loc, AvailabilitySet(Decl), + Comment, + DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Template), + SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl), + DeclarationFragmentsBuilder::getAccessControl(Template), + DeclarationFragmentsBuilder::getTemplate(Template), + isInSystemHeader(Decl)); + } else if (Decl->getTemplateSpecializationInfo()) + API.addCXXMethodTemplateSpec( + API.findRecordForUSR(ParentUSR), Name, USR, Loc, AvailabilitySet(Decl), + Comment, + DeclarationFragmentsBuilder:: + getFragmentsForFunctionTemplateSpecialization(Decl), + SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl), + DeclarationFragmentsBuilder::getAccessControl(Decl), + isInSystemHeader(Decl)); + return true; +} + template bool ExtractAPIVisitorBase::VisitConceptDecl(const ConceptDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) @@ -724,6 +788,8 @@ template bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl( const FunctionTemplateDecl *Decl) { + if (isa(Decl->getTemplatedDecl())) + return true; if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; @@ -1104,6 +1170,9 @@ continue; } + if (Method->isFunctionTemplateSpecialization()) + return; + StringRef Name; DeclarationFragments Declaration; if (Method->isOverloadedOperator()) { 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 @@ -39,6 +39,10 @@ getDerived()->traverseClassTemplatePartialSpecRecords(); + getDerived()->traverseCXXMethodTemplates(); + + getDerived()->traverseCXXMethodTemplateSpecializations(); + getDerived()->traverseConcepts(); getDerived()->traverseGlobalVariableTemplateRecords(); @@ -92,6 +96,17 @@ getDerived()->visitCXXClassRecord(*Class.second); } + void traverseCXXMethodTemplates() { + for (const auto &MethodTemplate : API.getCXXMethodTemplates()) + getDerived()->visitMethodTemplateRecord(*MethodTemplate.second); + } + + void traverseCXXMethodTemplateSpecializations() { + for (const auto &MethodTemplateSpec : + API.getCXXMethodTemplateSpecializations()) + getDerived()->visitMethodTemplateSpecRecord(*MethodTemplateSpec.second); + } + void traverseClassTemplateRecords() { for (const auto &ClassTemplate : API.getClassTemplates()) getDerived()->visitClassTemplateRecord(*ClassTemplate.second); @@ -190,6 +205,11 @@ void visitClassTemplatePartialSpecRecord( const ClassTemplatePartialSpecRecord &Record){}; + void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record){}; + + void + visitMethodTemplateSpecRecord(const CXXMethodTemplateSpecRecord &Record){}; + void visitGlobalVariableTemplateRecord( const GlobalVariableTemplateRecord &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 @@ -175,6 +175,10 @@ void visitClassTemplatePartialSpecRecord( const ClassTemplatePartialSpecRecord &Record); + void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record); + + void visitMethodTemplateSpecRecord(const CXXMethodTemplateSpecRecord &Record); + void visitConceptRecord(const ConceptRecord &Record); void 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 @@ -308,6 +308,39 @@ return CXXClassRecord->Methods.emplace_back(std::move(Record)).get(); } +CXXMethodTemplateRecord *APISet::addCXXMethodTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, Template Template, + bool IsFromSystemHeader) { + auto *Record = addTopLevelRecord(USRBasedLookupTable, CXXMethodTemplates, USR, + Name, Loc, std::move(Availability), Comment, + Declaration, SubHeading, Signature, Access, + Template, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + + return Record; +} + +CXXMethodTemplateSpecRecord *APISet::addCXXMethodTemplateSpec( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader) { + + auto *Record = addTopLevelRecord( + USRBasedLookupTable, CXXMethodTemplateSpecializations, USR, Name, Loc, + std::move(Availability), Comment, Declaration, SubHeading, Signature, + Access, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + + return Record; +} + ObjCCategoryRecord *APISet::addObjCCategory( StringRef Name, StringRef USR, PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 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 @@ -414,6 +414,14 @@ Kind["identifier"] = AddLangPrefix("class"); Kind["displayName"] = "Class"; break; + case APIRecord::RK_CXXMethodTemplate: + Kind["identifier"] = AddLangPrefix("method"); + Kind["displayName"] = "Method Template"; + break; + case APIRecord::RK_CXXMethodTemplateSpecialization: + Kind["identifier"] = AddLangPrefix("method"); + Kind["displayName"] = "Method Template Specialization"; + break; case APIRecord::RK_Concept: Kind["identifier"] = AddLangPrefix("concept"); Kind["displayName"] = "Concept"; @@ -909,6 +917,32 @@ serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); } +void SymbolGraphSerializer::visitMethodTemplateRecord( + const CXXMethodTemplateRecord &Record) { + if (!ShouldRecurse) + // Ignore child symbols + return; + auto MethodTemplate = serializeAPIRecord(Record); + if (!MethodTemplate) + return; + Symbols.emplace_back(std::move(*MethodTemplate)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitMethodTemplateSpecRecord( + const CXXMethodTemplateSpecRecord &Record) { + if (!ShouldRecurse) + // Ignore child symbols + return; + auto MethodTemplateSpec = serializeAPIRecord(Record); + if (!MethodTemplateSpec) + return; + Symbols.emplace_back(std::move(*MethodTemplateSpec)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); +} + void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { auto Concept = serializeAPIRecord(Record); if (!Concept) diff --git a/clang/test/ExtractAPI/method_template.cpp b/clang/test/ExtractAPI/method_template.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ExtractAPI/method_template.cpp @@ -0,0 +1,244 @@ +// 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 +class Foo { + template void Bar(T Fizz); +}; + +/// 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": [ + { + "kind": "memberOf", + "source": "c:@S@Foo@FT@>1#TBar#t0.0#v#", + "target": "c:@S@Foo", + "targetFallback": "Foo" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo" + }, + "kind": { + "displayName": "Class", + "identifier": "c++.class" + }, + "location": { + "position": { + "character": 7, + "line": 1 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + }, + { + "accessLevel": "private", + "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": "Bar" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:t0.0", + "spelling": "T" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "Fizz" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:t0.0", + "spelling": "T" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "Fizz" + } + ], + "name": "Fizz" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@FT@>1#TBar#t0.0#v#" + }, + "kind": { + "displayName": "Method Template", + "identifier": "c++.method" + }, + "location": { + "position": { + "character": 29, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Bar" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Bar" + } + ], + "title": "Bar" + }, + "pathComponents": [ + "Foo", + "Bar" + ], + "swiftGenerics": { + "parameters": [ + { + "depth": 0, + "index": 0, + "name": "T" + } + ] + } + } + ] +} diff --git a/clang/test/ExtractAPI/method_template_spec.cpp b/clang/test/ExtractAPI/method_template_spec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ExtractAPI/method_template_spec.cpp @@ -0,0 +1,371 @@ +// 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 +class Foo { + template void Bar(T Fizz); + + template<> void Bar(int Fizz); +}; + +/// 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": [ + { + "kind": "memberOf", + "source": "c:@S@Foo@FT@>1#TBar#t0.0#v#", + "target": "c:@S@Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:@S@Foo@F@Bar<#I>#I#", + "target": "c:@S@Foo", + "targetFallback": "Foo" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo" + }, + "kind": { + "displayName": "Class", + "identifier": "c++.class" + }, + "location": { + "position": { + "character": 7, + "line": 1 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + }, + { + "accessLevel": "private", + "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": "Bar" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:t0.0", + "spelling": "T" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "Fizz" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:t0.0", + "spelling": "T" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "Fizz" + } + ], + "name": "Fizz" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@FT@>1#TBar#t0.0#v#" + }, + "kind": { + "displayName": "Method Template", + "identifier": "c++.method" + }, + "location": { + "position": { + "character": 29, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Bar" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Bar" + } + ], + "title": "Bar" + }, + "pathComponents": [ + "Foo", + "Bar" + ], + "swiftGenerics": { + "parameters": [ + { + "depth": 0, + "index": 0, + "name": "T" + } + ] + } + }, + { + "accessLevel": "private", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "template" + }, + { + "kind": "text", + "spelling": "<> " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Bar" + }, + { + "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": "Fizz" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "Fizz" + } + ], + "name": "Fizz" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@F@Bar<#I>#I#" + }, + "kind": { + "displayName": "Method Template Specialization", + "identifier": "c++.method" + }, + "location": { + "position": { + "character": 19, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Bar" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Bar" + } + ], + "title": "Bar" + }, + "pathComponents": [ + "Foo", + "Bar" + ] + } + ] +}