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 @@ -61,6 +61,9 @@ RK_Unknown, RK_GlobalFunction, RK_GlobalVariable, + RK_GlobalVariableTemplate, + RK_GlobalVariableTemplateSpecialization, + RK_GlobalVariableTemplatePartialSpecialization, RK_EnumConstant, RK_Enum, RK_StructField, @@ -195,6 +198,14 @@ Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader) {} + GlobalVariableRecord(RecordKind Kind, StringRef USR, StringRef Name, + PresumedLoc Loc, AvailabilitySet Availabilities, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities), Linkage, + Comment, Declaration, SubHeading, IsFromSystemHeader) {} + static bool classof(const APIRecord *Record) { return Record->getKind() == RK_GlobalVariable; } @@ -203,6 +214,60 @@ virtual void anchor(); }; +struct GlobalVariableTemplateRecord : GlobalVariableRecord { + Template Templ; + + GlobalVariableTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilitySet Availabilities, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + class Template Template, bool IsFromSystemHeader) + : GlobalVariableRecord(RK_GlobalVariableTemplate, USR, Name, Loc, + std::move(Availabilities), Linkage, Comment, + Declaration, SubHeading, IsFromSystemHeader), + Templ(Template) {} + + static bool classof(const APIRecord *Record) { + return Record->getKind() == RK_GlobalVariableTemplate; + } +}; + +struct GlobalVariableTemplateSpecRecord : GlobalVariableRecord { + GlobalVariableTemplateSpecRecord( + StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilitySet Availabilities, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : GlobalVariableRecord(RK_GlobalVariableTemplateSpecialization, USR, Name, + Loc, std::move(Availabilities), Linkage, Comment, + Declaration, SubHeading, IsFromSystemHeader) {} + + static bool classof(const APIRecord *Record) { + return Record->getKind() == RK_GlobalVariableTemplatePartialSpecialization; + } +}; + +struct GlobalVariableTemplatePartialSpecRecord : GlobalVariableRecord { + Template Templ; + + GlobalVariableTemplatePartialSpecRecord( + StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilitySet Availabilities, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, class Template Template, + bool IsFromSystemHeader) + : GlobalVariableRecord(RK_GlobalVariableTemplatePartialSpecialization, + USR, Name, Loc, std::move(Availabilities), Linkage, + Comment, Declaration, SubHeading, + IsFromSystemHeader), + Templ(Template) {} + + static bool classof(const APIRecord *Record) { + return Record->getKind() == RK_GlobalVariableTemplate; + } +}; + /// This holds information associated with enum constants. struct EnumConstantRecord : APIRecord { EnumConstantRecord(StringRef USR, StringRef Name, PresumedLoc Loc, @@ -698,6 +763,7 @@ struct ConceptRecord : APIRecord { Template Templ; + ConceptRecord(StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, DeclarationFragments Declaration, @@ -707,10 +773,6 @@ LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} - - static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_Concept; - } }; /// This holds information associated with Objective-C categories. @@ -851,6 +913,11 @@ template <> struct has_template : public std::true_type {}; template <> struct has_template : 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 { @@ -867,6 +934,14 @@ const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeadin, bool IsFromSystemHeaderg); + GlobalVariableTemplateRecord * + addGlobalVariableTemplate(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, LinkageInfo Linkage, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader); + /// Create and add a function record into the API set. /// /// Note: the caller is responsible for keeping the StringRef \p Name and @@ -969,6 +1044,19 @@ DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, bool IsFromSystemHeader); + GlobalVariableTemplateSpecRecord *addGlobalVariableTemplateSpec( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader); + + GlobalVariableTemplatePartialSpecRecord *addGlobalVariableTemplatePartialSpec( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader); + CXXMethodRecord * addCXXMethod(CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, AvailabilitySet Availability, @@ -1112,9 +1200,21 @@ const RecordMap &getGlobalVariables() const { return GlobalVariables; } + const RecordMap & + getGlobalVariableTemplates() const { + return GlobalVariableTemplates; + } const RecordMap &getStaticFields() const { return StaticFields; } + const RecordMap & + getGlobalVariableTemplateSpecializations() const { + return GlobalVariableTemplateSpecializations; + } + const RecordMap & + getGlobalVariableTemplatePartialSpecializations() const { + return GlobalVariableTemplatePartialSpecializations; + } const RecordMap &getEnums() const { return Enums; } const RecordMap &getStructs() const { return Structs; } const RecordMap &getCXXClasses() const { return CXXClasses; } @@ -1184,6 +1284,11 @@ llvm::DenseMap USRBasedLookupTable; RecordMap GlobalFunctions; RecordMap GlobalVariables; + RecordMap GlobalVariableTemplates; + RecordMap + GlobalVariableTemplateSpecializations; + RecordMap + GlobalVariableTemplatePartialSpecializations; RecordMap Concepts; RecordMap StaticFields; RecordMap Enums; 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 @@ -23,7 +23,10 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/Specifiers.h" #include "clang/Lex/MacroInfo.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include @@ -331,8 +334,28 @@ return Template; } - static Template - getTemplate(const ClassTemplatePartialSpecializationDecl *Decl) { + static Template getTemplate(const VarTemplatePartialSpecializationDecl *Decl) { + Template Template; + for (auto *const Parameter : *Decl->getTemplateParameters()) { + const auto *Param = dyn_cast(Parameter); + if (!Param) // some params are null + continue; + std::string Type; + if (Param->hasTypeConstraint()) + Type = Param->getTypeConstraint()->getNamedConcept()->getName().str(); + else if (Param->wasDeclaredWithTypename()) + Type = "typename"; + else + Type = "class"; + + Template.addTemplateParameter(Type, Param->getName().str(), + Param->getIndex(), Param->getDepth(), + Param->isParameterPack()); + } + return Template; + } + + static Template getTemplate(const ClassTemplatePartialSpecializationDecl *Decl) { Template Template; for (auto *const Parameter : *Decl->getTemplateParameters()) { const auto *Param = dyn_cast(Parameter); @@ -356,6 +379,8 @@ /// Build DeclarationFragments for a variable declaration VarDecl. static DeclarationFragments getFragmentsForVar(const VarDecl *); + static DeclarationFragments getFragmentsForVarTemplate(const VarDecl *); + /// Build DeclarationFragments for a function declaration FunctionDecl. static DeclarationFragments getFragmentsForFunction(const FunctionDecl *); @@ -408,6 +433,12 @@ static DeclarationFragments getFragmentsForClassTemplatePartialSpecialization( const ClassTemplatePartialSpecializationDecl *); + static DeclarationFragments getFragmentsForVarTemplateSpecialization( + const VarTemplateSpecializationDecl *); + + static DeclarationFragments getFragmentsForVarTemplatePartialSpecialization( + const VarTemplatePartialSpecializationDecl *); + /// Build DeclarationFragments for an Objective-C category declaration /// ObjCCategoryDecl. static DeclarationFragments 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 @@ -59,6 +59,14 @@ bool WalkUpFromClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *Decl); + bool WalkUpFromVarTemplateDecl(const VarTemplateDecl *Decl); + + bool WalkUpFromVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *Decl); + + bool WalkUpFromVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *Decl); + bool VisitRecordDecl(const RecordDecl *Decl); bool VisitCXXRecordDecl(const CXXRecordDecl *Decl); @@ -71,6 +79,14 @@ bool VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *Decl); + bool VisitVarTemplateDecl(const VarTemplateDecl *Decl); + + bool + VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *Decl); + + bool VisitVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *Decl); + bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl); bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl); @@ -359,6 +375,28 @@ return true; } +template +bool ExtractAPIVisitorBase::WalkUpFromVarTemplateDecl( + const VarTemplateDecl *Decl) { + getDerivedExtractAPIVisitor().VisitVarTemplateDecl(Decl); + return true; +} + +template +bool ExtractAPIVisitorBase::WalkUpFromVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *Decl) { + getDerivedExtractAPIVisitor().VisitVarTemplateSpecializationDecl(Decl); + return true; +} + +template +bool ExtractAPIVisitorBase:: + WalkUpFromVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *Decl) { + getDerivedExtractAPIVisitor().VisitVarTemplatePartialSpecializationDecl(Decl); + return true; +} + template bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) @@ -572,6 +610,105 @@ return true; } +template +bool ExtractAPIVisitorBase::VisitVarTemplateDecl( + const VarTemplateDecl *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()); + + // Build declaration fragments and sub-heading for the variable. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForVarTemplate( + Decl->getTemplatedDecl()); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + // Inject template fragments before var fragments. + Declaration.insert( + Declaration.begin(), + DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(Decl)); + + API.addGlobalVariableTemplate(Name, USR, Loc, AvailabilitySet(Decl), Linkage, + Comment, Declaration, SubHeading, + DeclarationFragmentsBuilder::getTemplate(Decl), + isInSystemHeader(Decl)); + return true; +} + +template +bool ExtractAPIVisitorBase::VisitVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *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()); + + // Build declaration fragments and sub-heading for the variable. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( + Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + API.addGlobalVariableTemplateSpec(Name, USR, Loc, AvailabilitySet(Decl), + Linkage, Comment, Declaration, SubHeading, + isInSystemHeader(Decl)); + return true; +} + +template +bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *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()); + + // Build declaration fragments and sub-heading for the variable. + DeclarationFragments Declaration = DeclarationFragmentsBuilder:: + getFragmentsForVarTemplatePartialSpecialization(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + API.addGlobalVariableTemplatePartialSpec( + Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, + SubHeading, 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 @@ -41,6 +41,12 @@ getDerived()->traverseConcepts(); + getDerived()->traverseGlobalVariableTemplateRecords(); + + getDerived()->traverseGlobalVariableTemplateSpecRecords(); + + getDerived()->traverseGlobalVariableTemplatePartialSpecRecords(); + getDerived()->traverseStructRecords(); getDerived()->traverseObjCInterfaces(); @@ -99,6 +105,26 @@ *ClassTemplatePartialSpec.second); } + void traverseGlobalVariableTemplateRecords() { + for (const auto &GlobalVariableTemplate : API.getGlobalVariableTemplates()) + getDerived()->visitGlobalVariableTemplateRecord( + *GlobalVariableTemplate.second); + } + + void traverseGlobalVariableTemplateSpecRecords() { + for (const auto &GlobalVariableTemplateSpec : + API.getGlobalVariableTemplateSpecializations()) + getDerived()->visitGlobalVariableTemplateSpecRecord( + *GlobalVariableTemplateSpec.second); + } + + void traverseGlobalVariableTemplatePartialSpecRecords() { + for (const auto &GlobalVariableTemplatePartialSpec : + API.getGlobalVariableTemplatePartialSpecializations()) + getDerived()->visitGlobalVariableTemplatePartialSpecRecord( + *GlobalVariableTemplatePartialSpec.second); + } + void traverseConcepts() { for (const auto &Concept : API.getConcepts()) getDerived()->visitConceptRecord(*Concept.second); @@ -147,6 +173,15 @@ void visitClassTemplatePartialSpecRecord( const ClassTemplatePartialSpecRecord &Record){}; + void visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord &Record) {} + + void visitGlobalVariableTemplateSpecRecord( + const GlobalVariableTemplateSpecRecord &Record){}; + + void visitGlobalVariableTemplatePartialSpecRecord( + const GlobalVariableTemplatePartialSpecRecord &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 @@ -177,6 +177,15 @@ void visitConceptRecord(const ConceptRecord &Record); + void + visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord &Record); + + void visitGlobalVariableTemplateSpecRecord( + const GlobalVariableTemplateSpecRecord &Record); + + void visitGlobalVariableTemplatePartialSpecRecord( + const GlobalVariableTemplatePartialSpecRecord &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 @@ -54,6 +54,18 @@ Fragments, SubHeading, IsFromSystemHeader); } +GlobalVariableTemplateRecord *APISet::addGlobalVariableTemplate( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, GlobalVariableTemplates, USR, + Name, Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, Template, + IsFromSystemHeader); +} + GlobalFunctionRecord *APISet::addGlobalFunction( StringRef Name, StringRef USR, PresumedLoc Loc, AvailabilitySet Availabilities, LinkageInfo Linkage, @@ -191,6 +203,30 @@ SubHeading, Template, IsFromSystemHeader); } +GlobalVariableTemplateSpecRecord *APISet::addGlobalVariableTemplateSpec( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, + GlobalVariableTemplateSpecializations, USR, Name, + Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, IsFromSystemHeader); +} + +GlobalVariableTemplatePartialSpecRecord * +APISet::addGlobalVariableTemplatePartialSpec( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilitySet Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader) { + return addTopLevelRecord( + USRBasedLookupTable, GlobalVariableTemplatePartialSpecializations, USR, + Name, Loc, std::move(Availability), Linkage, Comment, Declaration, + SubHeading, Template, IsFromSystemHeader); +} + ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR, PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment, 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 @@ -14,10 +14,12 @@ #include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/QualTypeNames.h" #include "clang/Basic/OperatorKinds.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringSwitch.h" +#include using namespace clang::extractapi; using namespace llvm; @@ -452,6 +454,34 @@ .append(";", DeclarationFragments::FragmentKind::Text); } +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) { + DeclarationFragments Fragments; + if (Var->isConstexpr()) + Fragments.append("constexpr", DeclarationFragments::FragmentKind::Keyword) + .appendSpace(); + QualType T = + Var->getTypeSourceInfo() + ? Var->getTypeSourceInfo()->getType() + : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType()); + + DeclarationFragments After; + DeclarationFragments ArgumentFragment = + getFragmentsForType(T, Var->getASTContext(), After); + if (ArgumentFragment.begin()->Spelling.substr(0, 14).compare( + "type-parameter") == 0) { + std::string ProperArgName = getNameForTemplateArgument( + Var->getDescribedVarTemplate()->getTemplateParameters()->asArray(), + ArgumentFragment.begin()->Spelling); + ArgumentFragment.begin()->Spelling.swap(ProperArgName); + } + Fragments.append(std::move(ArgumentFragment)) + .appendSpace() + .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) + .append(";", DeclarationFragments::FragmentKind::Text); + return Fragments; +} + DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { DeclarationFragments Fragments, After; @@ -903,6 +933,47 @@ .append(";", DeclarationFragments::FragmentKind::Text); } +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( + const VarTemplateSpecializationDecl *Decl) { + DeclarationFragments Fragments; + return Fragments + .append("template", DeclarationFragments::FragmentKind::Keyword) + .append("<", DeclarationFragments::FragmentKind::Text) + .append(">", DeclarationFragments::FragmentKind::Text) + .appendSpace() + .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(Decl)) + .pop_back() // there is an extra semicolon now + .append("<", DeclarationFragments::FragmentKind::Text) + .append( + getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), + Decl->getASTContext(), std::nullopt)) + .append(">", DeclarationFragments::FragmentKind::Text) + .append(";", DeclarationFragments::FragmentKind::Text); +} + +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization( + const VarTemplatePartialSpecializationDecl *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::getFragmentsForVarTemplate(Decl)) + .pop_back() // there is an extra semicolon now + .append("<", DeclarationFragments::FragmentKind::Text) + .append(getFragmentsForTemplateArguments( + Decl->getTemplateArgs().asArray(), Decl->getASTContext(), + Decl->getTemplateParameters()->asArray())) + .append(">", DeclarationFragments::FragmentKind::Text) + .append(";", DeclarationFragments::FragmentKind::Text); +} + 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,18 @@ Kind["identifier"] = AddLangPrefix("func"); Kind["displayName"] = "Function"; break; + case APIRecord::RK_GlobalVariableTemplate: + Kind["identifier"] = AddLangPrefix("var"); + Kind["displayName"] = "Global Variable Template"; + break; + case APIRecord::RK_GlobalVariableTemplateSpecialization: + Kind["identifier"] = AddLangPrefix("var"); + Kind["displayName"] = "Global Variable Template Specialization"; + break; + case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: + Kind["identifier"] = AddLangPrefix("var"); + Kind["displayName"] = "Global Variable Template Partial Specialization"; + break; case APIRecord::RK_GlobalVariable: Kind["identifier"] = AddLangPrefix("var"); Kind["displayName"] = "Global Variable"; @@ -897,6 +909,30 @@ Symbols.emplace_back(std::move(*Concept)); } +void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord &Record) { + auto GlobalVariableTemplate = serializeAPIRecord(Record); + if (!GlobalVariableTemplate) + return; + Symbols.emplace_back(std::move(*GlobalVariableTemplate)); +} + +void SymbolGraphSerializer::visitGlobalVariableTemplateSpecRecord( + const GlobalVariableTemplateSpecRecord &Record) { + auto GlobalVariableTemplateSpec = serializeAPIRecord(Record); + if (!GlobalVariableTemplateSpec) + return; + Symbols.emplace_back(std::move(*GlobalVariableTemplateSpec)); +} + +void SymbolGraphSerializer::visitGlobalVariableTemplatePartialSpecRecord( + const GlobalVariableTemplatePartialSpecRecord &Record) { + auto GlobalVariableTemplatePartialSpec = serializeAPIRecord(Record); + if (!GlobalVariableTemplatePartialSpec) + return; + Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpec)); +} + void SymbolGraphSerializer::visitObjCContainerRecord( const ObjCContainerRecord &Record) { auto ObjCContainer = serializeAPIRecord(Record); diff --git a/clang/test/ExtractAPI/global_var_template.cpp b/clang/test/ExtractAPI/global_var_template.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ExtractAPI/global_var_template.cpp @@ -0,0 +1,133 @@ +// 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 T Foo = T(3.14); +/// 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:t0.0", + "spelling": "T" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@Foo" + }, + "kind": { + "displayName": "Global Variable Template", + "identifier": "c++.var" + }, + "location": { + "position": { + "character": 24, + "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" + } + ] + } + } + ] +} diff --git a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp @@ -0,0 +1,262 @@ +// 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 int Foo = 0; + +template int Foo = 0; +/// 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": "X" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "keyword", + "spelling": "typename" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "genericParameter", + "spelling": "Y" + }, + { + "kind": "text", + "spelling": "> " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@Foo" + }, + "kind": { + "displayName": "Global Variable Template", + "identifier": "c++.var" + }, + "location": { + "position": { + "character": 38, + "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": "X" + }, + { + "depth": 0, + "index": 1, + "name": "Y" + } + ] + } + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "template" + }, + { + "kind": "text", + "spelling": "<" + }, + { + "kind": "keyword", + "spelling": "typename" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "genericParameter", + "spelling": "Z" + }, + { + "kind": "text", + "spelling": "> " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": "<" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:t0.0", + "spelling": "Z" + }, + { + "kind": "text", + "spelling": ">;" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@VP>1#T@Foo>#I#t0.0" + }, + "kind": { + "displayName": "Global Variable Template Partial Specialization", + "identifier": "c++.var" + }, + "location": { + "position": { + "character": 26, + "line": 3 + }, + "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": "Z" + } + ] + } + } + ] +} diff --git a/clang/test/ExtractAPI/global_var_template_spec.cpp b/clang/test/ExtractAPI/global_var_template_spec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/ExtractAPI/global_var_template_spec.cpp @@ -0,0 +1,207 @@ +// 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 T Foo = T(3.14); + +template<> int Foo; +/// 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:t0.0", + "spelling": "T" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@Foo" + }, + "kind": { + "displayName": "Global Variable Template", + "identifier": "c++.var" + }, + "location": { + "position": { + "character": 24, + "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:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": "<" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": ">;" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@Foo>#I" + }, + "kind": { + "displayName": "Global Variable Template Specialization", + "identifier": "c++.var" + }, + "location": { + "position": { + "character": 16, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + } + ] +}