[clang][ExtractAPI] Add support for C++ class templates and concepts
Add has_template template, DeclarationFragmentBuilder functions, and tests for class templates, specializations/partial specs, and concepts. Depends on D157007 Reviewed By: dang Differential Revision: https://reviews.llvm.org/D157076
This commit is contained in:
parent
d8900f661a
commit
7ba37f4e46
@ -36,6 +36,86 @@
|
||||
namespace clang {
|
||||
namespace extractapi {
|
||||
|
||||
class Template {
|
||||
struct TemplateParameter {
|
||||
// "class", "typename", or concept name
|
||||
std::string Type;
|
||||
std::string Name;
|
||||
unsigned int Index;
|
||||
unsigned int Depth;
|
||||
bool IsParameterPack;
|
||||
|
||||
TemplateParameter(std::string Type, std::string Name, unsigned int Index,
|
||||
unsigned int Depth, bool IsParameterPack)
|
||||
: Type(Type), Name(Name), Index(Index), Depth(Depth),
|
||||
IsParameterPack(IsParameterPack) {}
|
||||
};
|
||||
|
||||
struct TemplateConstraint {
|
||||
// type name of the constraint, if it has one
|
||||
std::string Type;
|
||||
std::string Kind;
|
||||
std::string LHS, RHS;
|
||||
};
|
||||
llvm::SmallVector<TemplateParameter> Parameters;
|
||||
llvm::SmallVector<TemplateConstraint> Constraints;
|
||||
|
||||
public:
|
||||
Template() = default;
|
||||
|
||||
Template(const TemplateDecl *Decl) {
|
||||
for (auto *const Parameter : *Decl->getTemplateParameters()) {
|
||||
const auto *Param = dyn_cast<TemplateTypeParmDecl>(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";
|
||||
|
||||
addTemplateParameter(Type, Param->getName().str(), Param->getIndex(),
|
||||
Param->getDepth(), Param->isParameterPack());
|
||||
}
|
||||
}
|
||||
|
||||
Template(const ClassTemplatePartialSpecializationDecl *Decl) {
|
||||
for (auto *const Parameter : *Decl->getTemplateParameters()) {
|
||||
const auto *Param = dyn_cast<TemplateTypeParmDecl>(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";
|
||||
|
||||
addTemplateParameter(Type, Param->getName().str(), Param->getIndex(),
|
||||
Param->getDepth(), Param->isParameterPack());
|
||||
}
|
||||
}
|
||||
|
||||
const llvm::SmallVector<TemplateParameter> &getParameters() const {
|
||||
return Parameters;
|
||||
}
|
||||
|
||||
const llvm::SmallVector<TemplateConstraint> &getConstraints() const {
|
||||
return Constraints;
|
||||
}
|
||||
|
||||
void addTemplateParameter(std::string Type, std::string Name,
|
||||
unsigned int Index, unsigned int Depth,
|
||||
bool IsParameterPack) {
|
||||
Parameters.emplace_back(Type, Name, Index, Depth, IsParameterPack);
|
||||
}
|
||||
|
||||
bool empty() const { return Parameters.empty() && Constraints.empty(); }
|
||||
};
|
||||
|
||||
/// DocComment is a vector of RawComment::CommentLine.
|
||||
///
|
||||
/// Each line represents one line of striped documentation comment,
|
||||
@ -69,6 +149,10 @@ struct APIRecord {
|
||||
RK_StaticField,
|
||||
RK_CXXField,
|
||||
RK_CXXClass,
|
||||
RK_ClassTemplate,
|
||||
RK_ClassTemplateSpecialization,
|
||||
RK_ClassTemplatePartialSpecialization,
|
||||
RK_Concept,
|
||||
RK_CXXStaticMethod,
|
||||
RK_CXXInstanceMethod,
|
||||
RK_CXXConstructorMethod,
|
||||
@ -644,6 +728,75 @@ private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
struct ClassTemplateRecord : CXXClassRecord {
|
||||
Template Templ;
|
||||
|
||||
ClassTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
|
||||
AvailabilitySet Availabilities, const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, Template Template,
|
||||
bool IsFromSystemHeader)
|
||||
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
|
||||
Declaration, SubHeading, RK_ClassTemplate,
|
||||
IsFromSystemHeader),
|
||||
Templ(Template) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ClassTemplate;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassTemplateSpecializationRecord : CXXClassRecord {
|
||||
ClassTemplateSpecializationRecord(StringRef USR, StringRef Name,
|
||||
PresumedLoc Loc,
|
||||
AvailabilitySet Availabilities,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
bool IsFromSystemHeader)
|
||||
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
|
||||
Declaration, SubHeading, RK_ClassTemplateSpecialization,
|
||||
IsFromSystemHeader) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ClassTemplateSpecialization;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassTemplatePartialSpecializationRecord : CXXClassRecord {
|
||||
Template Templ;
|
||||
ClassTemplatePartialSpecializationRecord(
|
||||
StringRef USR, StringRef Name, PresumedLoc Loc,
|
||||
AvailabilitySet Availabilities, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
Template Template, bool IsFromSystemHeader)
|
||||
: CXXClassRecord(USR, Name, Loc, std::move(Availabilities), Comment,
|
||||
Declaration, SubHeading, RK_ClassTemplateSpecialization,
|
||||
IsFromSystemHeader),
|
||||
Templ(Template) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ClassTemplatePartialSpecialization;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConceptRecord : APIRecord {
|
||||
Template Templ;
|
||||
ConceptRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
|
||||
AvailabilitySet Availabilities, const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, Template Template,
|
||||
bool IsFromSystemHeader)
|
||||
: APIRecord(RK_Concept, USR, Name, Loc, std::move(Availabilities),
|
||||
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.
|
||||
struct ObjCCategoryRecord : ObjCContainerRecord {
|
||||
SymbolReference Interface;
|
||||
@ -779,6 +932,13 @@ template <typename RecordTy> struct has_access : public std::false_type {};
|
||||
template <> struct has_access<CXXMethodRecord> : public std::true_type {};
|
||||
template <> struct has_access<CXXFieldRecord> : public std::true_type {};
|
||||
|
||||
template <typename RecordTy> struct has_template : public std::false_type {};
|
||||
template <> struct has_template<ClassTemplateRecord> : public std::true_type {};
|
||||
template <>
|
||||
struct has_template<ClassTemplatePartialSpecializationRecord>
|
||||
: public std::true_type {};
|
||||
template <> struct has_template<ConceptRecord> : public std::true_type {};
|
||||
|
||||
/// APISet holds the set of API records collected from given inputs.
|
||||
class APISet {
|
||||
public:
|
||||
@ -876,6 +1036,26 @@ public:
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
APIRecord::RecordKind Kind, bool IsFromSystemHeader);
|
||||
|
||||
ClassTemplateRecord *
|
||||
addClassTemplate(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, Template Template,
|
||||
bool IsFromSystemHeader);
|
||||
|
||||
ClassTemplateSpecializationRecord *addClassTemplateSpecialization(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
bool IsFromSystemHeader);
|
||||
|
||||
ClassTemplatePartialSpecializationRecord *
|
||||
addClassTemplatePartialSpecialization(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
Template Template, bool IsFromSystemHeader);
|
||||
|
||||
CXXMethodRecord *
|
||||
addCXXMethod(CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, AvailabilitySet Availability,
|
||||
@ -890,6 +1070,13 @@ public:
|
||||
FunctionSignature Signature, bool IsConstructor, AccessControl Access,
|
||||
bool IsFromSystemHeader);
|
||||
|
||||
ConceptRecord *addConcept(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, Template Template,
|
||||
bool IsFromSystemHeader);
|
||||
|
||||
/// Create and add an Objective-C category record into the API set.
|
||||
///
|
||||
/// Note: the caller is responsible for keeping the StringRef \p Name and
|
||||
@ -1018,6 +1205,19 @@ public:
|
||||
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
|
||||
const RecordMap<StructRecord> &getStructs() const { return Structs; }
|
||||
const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
|
||||
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
|
||||
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
|
||||
return ClassTemplates;
|
||||
}
|
||||
const RecordMap<ClassTemplateSpecializationRecord> &
|
||||
getClassTemplateSpecializations() const {
|
||||
return ClassTemplateSpecializations;
|
||||
}
|
||||
const RecordMap<ClassTemplatePartialSpecializationRecord> &
|
||||
getClassTemplatePartialSpecializations() const {
|
||||
return ClassTemplatePartialSpecializations;
|
||||
}
|
||||
const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
|
||||
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
|
||||
return ObjCCategories;
|
||||
}
|
||||
@ -1071,10 +1271,15 @@ private:
|
||||
llvm::DenseMap<StringRef, APIRecord *> USRBasedLookupTable;
|
||||
RecordMap<GlobalFunctionRecord> GlobalFunctions;
|
||||
RecordMap<GlobalVariableRecord> GlobalVariables;
|
||||
RecordMap<ConceptRecord> Concepts;
|
||||
RecordMap<StaticFieldRecord> StaticFields;
|
||||
RecordMap<EnumRecord> Enums;
|
||||
RecordMap<StructRecord> Structs;
|
||||
RecordMap<CXXClassRecord> CXXClasses;
|
||||
RecordMap<ClassTemplateRecord> ClassTemplates;
|
||||
RecordMap<ClassTemplateSpecializationRecord> ClassTemplateSpecializations;
|
||||
RecordMap<ClassTemplatePartialSpecializationRecord>
|
||||
ClassTemplatePartialSpecializations;
|
||||
RecordMap<ObjCCategoryRecord> ObjCCategories;
|
||||
RecordMap<ObjCInterfaceRecord> ObjCInterfaces;
|
||||
RecordMap<ObjCProtocolRecord> ObjCProtocols;
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <vector>
|
||||
@ -161,6 +162,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeclarationFragments &pop_back() {
|
||||
Fragments.pop_back();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Append a text Fragment of a space character.
|
||||
///
|
||||
/// \returns a reference to the DeclarationFragments object itself after
|
||||
@ -292,6 +298,28 @@ public:
|
||||
static DeclarationFragments
|
||||
getFragmentsForOverloadedOperator(const CXXMethodDecl *);
|
||||
|
||||
static DeclarationFragments
|
||||
getFragmentsForTemplateParameters(ArrayRef<NamedDecl *>);
|
||||
|
||||
static std::string getNameForTemplateArgument(const ArrayRef<NamedDecl *>,
|
||||
std::string);
|
||||
|
||||
static DeclarationFragments
|
||||
getFragmentsForTemplateArguments(const ArrayRef<TemplateArgument>,
|
||||
ASTContext &,
|
||||
const std::optional<ArrayRef<NamedDecl *>>);
|
||||
|
||||
static DeclarationFragments getFragmentsForConcept(const ConceptDecl *);
|
||||
|
||||
static DeclarationFragments
|
||||
getFragmentsForRedeclarableTemplate(const RedeclarableTemplateDecl *);
|
||||
|
||||
static DeclarationFragments getFragmentsForClassTemplateSpecialization(
|
||||
const ClassTemplateSpecializationDecl *);
|
||||
|
||||
static DeclarationFragments getFragmentsForClassTemplatePartialSpecialization(
|
||||
const ClassTemplatePartialSpecializationDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an Objective-C category declaration
|
||||
/// ObjCCategoryDecl.
|
||||
static DeclarationFragments
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
|
||||
|
||||
#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"
|
||||
@ -52,10 +53,24 @@ public:
|
||||
|
||||
bool WalkUpFromCXXRecordDecl(const CXXRecordDecl *Decl);
|
||||
|
||||
bool WalkUpFromClassTemplateSpecializationDecl(
|
||||
const ClassTemplateSpecializationDecl *Decl);
|
||||
|
||||
bool WalkUpFromClassTemplatePartialSpecializationDecl(
|
||||
const ClassTemplatePartialSpecializationDecl *Decl);
|
||||
|
||||
bool VisitRecordDecl(const RecordDecl *Decl);
|
||||
|
||||
bool VisitCXXRecordDecl(const CXXRecordDecl *Decl);
|
||||
|
||||
bool VisitConceptDecl(const ConceptDecl *Decl);
|
||||
|
||||
bool VisitClassTemplateSpecializationDecl(
|
||||
const ClassTemplateSpecializationDecl *Decl);
|
||||
|
||||
bool VisitClassTemplatePartialSpecializationDecl(
|
||||
const ClassTemplatePartialSpecializationDecl *Decl);
|
||||
|
||||
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl);
|
||||
|
||||
bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl);
|
||||
@ -128,6 +143,29 @@ private:
|
||||
Derived &getDerivedExtractAPIVisitor() {
|
||||
return *static_cast<Derived *>(this);
|
||||
}
|
||||
|
||||
SmallVector<SymbolReference> getBases(const CXXRecordDecl *Decl) {
|
||||
// FIXME: store AccessSpecifier given by inheritance
|
||||
SmallVector<SymbolReference> Bases;
|
||||
for (const auto BaseSpecifier : Decl->bases()) {
|
||||
// skip classes not inherited as public
|
||||
if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public)
|
||||
continue;
|
||||
SymbolReference BaseClass;
|
||||
if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
|
||||
BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString());
|
||||
BaseClass.USR = API.recordUSR(
|
||||
BaseSpecifier.getType()->getAs<TemplateTypeParmType>()->getDecl());
|
||||
} else {
|
||||
CXXRecordDecl *BaseClassDecl =
|
||||
BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl();
|
||||
BaseClass.Name = BaseClassDecl->getName();
|
||||
BaseClass.USR = API.recordUSR(BaseClassDecl);
|
||||
}
|
||||
Bases.emplace_back(BaseClass);
|
||||
}
|
||||
return Bases;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -328,6 +366,22 @@ bool ExtractAPIVisitorBase<Derived>::WalkUpFromCXXRecordDecl(
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::WalkUpFromClassTemplateSpecializationDecl(
|
||||
const ClassTemplateSpecializationDecl *Decl) {
|
||||
getDerivedExtractAPIVisitor().VisitClassTemplateSpecializationDecl(Decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::
|
||||
WalkUpFromClassTemplatePartialSpecializationDecl(
|
||||
const ClassTemplatePartialSpecializationDecl *Decl) {
|
||||
getDerivedExtractAPIVisitor().VisitClassTemplatePartialSpecializationDecl(
|
||||
Decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
|
||||
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
|
||||
@ -368,7 +422,8 @@ bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
|
||||
const CXXRecordDecl *Decl) {
|
||||
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
|
||||
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
|
||||
Decl->isImplicit())
|
||||
return true;
|
||||
|
||||
StringRef Name = Decl->getName();
|
||||
@ -393,22 +448,22 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
|
||||
else
|
||||
Kind = APIRecord::RecordKind::RK_CXXClass;
|
||||
|
||||
CXXClassRecord *CXXClassRecord =
|
||||
API.addCXXClass(Name, USR, Loc, AvailabilitySet(Decl), Comment,
|
||||
Declaration, SubHeading, Kind, isInSystemHeader(Decl));
|
||||
CXXClassRecord *CXXClassRecord;
|
||||
if (Decl->getDescribedClassTemplate()) {
|
||||
// Inject template fragments before class fragments.
|
||||
Declaration.insert(
|
||||
Declaration.begin(),
|
||||
DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
|
||||
Decl->getDescribedClassTemplate()));
|
||||
CXXClassRecord = API.addClassTemplate(
|
||||
Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
|
||||
Template(Decl->getDescribedClassTemplate()), isInSystemHeader(Decl));
|
||||
} else
|
||||
CXXClassRecord =
|
||||
API.addCXXClass(Name, USR, Loc, AvailabilitySet(Decl), Comment,
|
||||
Declaration, SubHeading, Kind, isInSystemHeader(Decl));
|
||||
|
||||
// FIXME: store AccessSpecifier given by inheritance
|
||||
for (const auto BaseSpecifier : Decl->bases()) {
|
||||
// skip classes not inherited as public
|
||||
if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public)
|
||||
continue;
|
||||
SymbolReference BaseClass;
|
||||
CXXRecordDecl *BaseClassDecl =
|
||||
BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl();
|
||||
BaseClass.Name = BaseClassDecl->getName();
|
||||
BaseClass.USR = API.recordUSR(BaseClassDecl);
|
||||
CXXClassRecord->Bases.emplace_back(BaseClass);
|
||||
}
|
||||
CXXClassRecord->Bases = getBases(Decl);
|
||||
|
||||
getDerivedExtractAPIVisitor().recordCXXFields(CXXClassRecord, Decl->fields());
|
||||
getDerivedExtractAPIVisitor().recordCXXMethods(CXXClassRecord,
|
||||
@ -416,6 +471,97 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::VisitConceptDecl(const ConceptDecl *Decl) {
|
||||
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
|
||||
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 Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForConcept(Decl);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Decl);
|
||||
API.addConcept(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
|
||||
SubHeading, Template(Decl), isInSystemHeader(Decl));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::VisitClassTemplateSpecializationDecl(
|
||||
const ClassTemplateSpecializationDecl *Decl) {
|
||||
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
|
||||
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 Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
|
||||
Decl);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Decl);
|
||||
|
||||
auto *ClassTemplateSpecializationRecord = API.addClassTemplateSpecialization(
|
||||
Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
|
||||
isInSystemHeader(Decl));
|
||||
|
||||
ClassTemplateSpecializationRecord->Bases = getBases(Decl);
|
||||
getDerivedExtractAPIVisitor().recordCXXFields(
|
||||
ClassTemplateSpecializationRecord, Decl->fields());
|
||||
getDerivedExtractAPIVisitor().recordCXXMethods(
|
||||
ClassTemplateSpecializationRecord, Decl->methods());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::
|
||||
VisitClassTemplatePartialSpecializationDecl(
|
||||
const ClassTemplatePartialSpecializationDecl *Decl) {
|
||||
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
|
||||
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 Declaration = DeclarationFragmentsBuilder::
|
||||
getFragmentsForClassTemplatePartialSpecialization(Decl);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Decl);
|
||||
|
||||
auto *ClassTemplatePartialSpecRecord =
|
||||
API.addClassTemplatePartialSpecialization(
|
||||
Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
|
||||
SubHeading, Template(Decl), isInSystemHeader(Decl));
|
||||
|
||||
ClassTemplatePartialSpecRecord->Bases = getBases(Decl);
|
||||
|
||||
getDerivedExtractAPIVisitor().recordCXXFields(ClassTemplatePartialSpecRecord,
|
||||
Decl->fields());
|
||||
getDerivedExtractAPIVisitor().recordCXXMethods(ClassTemplatePartialSpecRecord,
|
||||
Decl->methods());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
|
||||
const ObjCInterfaceDecl *Decl) {
|
||||
|
||||
@ -33,6 +33,14 @@ public:
|
||||
|
||||
getDerived()->traverseCXXClassRecords();
|
||||
|
||||
getDerived()->traverseClassTemplateRecords();
|
||||
|
||||
getDerived()->traverseClassTemplateSpecializationRecords();
|
||||
|
||||
getDerived()->traverseClassTemplatePartialSpecializationRecords();
|
||||
|
||||
getDerived()->traverseConcepts();
|
||||
|
||||
getDerived()->traverseStructRecords();
|
||||
|
||||
getDerived()->traverseObjCInterfaces();
|
||||
@ -76,6 +84,30 @@ public:
|
||||
getDerived()->visitCXXClassRecord(*Class.second);
|
||||
}
|
||||
|
||||
void traverseClassTemplateRecords() {
|
||||
for (const auto &ClassTemplate : API.getClassTemplates())
|
||||
getDerived()->visitClassTemplateRecord(*ClassTemplate.second);
|
||||
}
|
||||
|
||||
void traverseClassTemplateSpecializationRecords() {
|
||||
for (const auto &ClassTemplateSpecialization :
|
||||
API.getClassTemplateSpecializations())
|
||||
getDerived()->visitClassTemplateSpecializationRecord(
|
||||
*ClassTemplateSpecialization.second);
|
||||
}
|
||||
|
||||
void traverseClassTemplatePartialSpecializationRecords() {
|
||||
for (const auto &ClassTemplatePartialSpecialization :
|
||||
API.getClassTemplatePartialSpecializations())
|
||||
getDerived()->visitClassTemplatePartialSpecializationRecord(
|
||||
*ClassTemplatePartialSpecialization.second);
|
||||
}
|
||||
|
||||
void traverseConcepts() {
|
||||
for (const auto &Concept : API.getConcepts())
|
||||
getDerived()->visitConceptRecord(*Concept.second);
|
||||
}
|
||||
|
||||
void traverseObjCInterfaces() {
|
||||
for (const auto &Interface : API.getObjCInterfaces())
|
||||
getDerived()->visitObjCContainerRecord(*Interface.second);
|
||||
@ -117,6 +149,14 @@ public:
|
||||
|
||||
void visitCXXClassRecord(const CXXClassRecord &Record){};
|
||||
|
||||
void visitClassTemplateRecord(const ClassTemplateRecord &Record){};
|
||||
|
||||
void visitClassTemplateSpecializationRecord(
|
||||
const ClassTemplateSpecializationRecord &Record){};
|
||||
|
||||
void visitClassTemplatePartialSpecializationRecord(
|
||||
const ClassTemplatePartialSpecializationRecord &Record){};
|
||||
|
||||
/// Visit an Objective-C container record.
|
||||
void visitObjCContainerRecord(const ObjCContainerRecord &Record){};
|
||||
|
||||
|
||||
@ -97,6 +97,10 @@ public:
|
||||
/// Get the string representation of the relationship kind.
|
||||
static StringRef getRelationshipString(RelationshipKind Kind);
|
||||
|
||||
enum ConstraintKind { Conformance, ConditionalConformance };
|
||||
|
||||
static StringRef getConstraintString(ConstraintKind Kind);
|
||||
|
||||
private:
|
||||
/// Just serialize the currently recorded objects in Symbol Graph format.
|
||||
Object serializeCurrentGraph();
|
||||
@ -171,6 +175,16 @@ public:
|
||||
|
||||
void visitCXXClassRecord(const CXXClassRecord &Record);
|
||||
|
||||
void visitClassTemplateRecord(const ClassTemplateRecord &Record);
|
||||
|
||||
void visitClassTemplateSpecializationRecord(
|
||||
const ClassTemplateSpecializationRecord &Record);
|
||||
|
||||
void visitClassTemplatePartialSpecializationRecord(
|
||||
const ClassTemplatePartialSpecializationRecord &Record);
|
||||
|
||||
void visitConceptRecord(const ConceptRecord &Record);
|
||||
|
||||
/// Visit an Objective-C container record.
|
||||
void visitObjCContainerRecord(const ObjCContainerRecord &Record);
|
||||
|
||||
|
||||
@ -159,6 +159,50 @@ APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
SubHeading, Kind, IsFromSystemHeader);
|
||||
}
|
||||
|
||||
ClassTemplateRecord *APISet::addClassTemplate(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
Template Template, bool IsFromSystemHeader) {
|
||||
|
||||
return addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc,
|
||||
std::move(Availability), Comment, Declaration,
|
||||
SubHeading, Template, IsFromSystemHeader);
|
||||
}
|
||||
|
||||
ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
bool IsFromSystemHeader) {
|
||||
return addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations,
|
||||
USR, Name, Loc, std::move(Availability), Comment,
|
||||
Declaration, SubHeading, IsFromSystemHeader);
|
||||
}
|
||||
|
||||
ClassTemplatePartialSpecializationRecord *
|
||||
APISet::addClassTemplatePartialSpecialization(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
AvailabilitySet Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
Template Template, bool IsFromSystemHeader) {
|
||||
return addTopLevelRecord(USRBasedLookupTable,
|
||||
ClassTemplatePartialSpecializations, USR, Name, Loc,
|
||||
std::move(Availability), Comment, Declaration,
|
||||
SubHeading, Template, IsFromSystemHeader);
|
||||
}
|
||||
|
||||
ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, AvailabilitySet Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
Template Template, bool IsFromSystemHeader) {
|
||||
return addTopLevelRecord(USRBasedLookupTable, Concepts, USR, Name, Loc,
|
||||
std::move(Availability), Comment, Declaration,
|
||||
SubHeading, Template, IsFromSystemHeader);
|
||||
}
|
||||
|
||||
CXXMethodRecord *APISet::addCXXMethod(
|
||||
CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
|
||||
|
||||
@ -735,6 +735,174 @@ DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(
|
||||
return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
|
||||
}
|
||||
|
||||
// Get fragments for template parameters, e.g. T in tempalte<typename T> ...
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getFragmentsForTemplateParameters(
|
||||
ArrayRef<NamedDecl *> ParameterArray) {
|
||||
DeclarationFragments Fragments;
|
||||
for (unsigned i = 0, end = ParameterArray.size(); i != end; ++i) {
|
||||
if (i)
|
||||
Fragments.append(",", DeclarationFragments::FragmentKind::Text)
|
||||
.appendSpace();
|
||||
|
||||
const auto *TemplateParam =
|
||||
dyn_cast<TemplateTypeParmDecl>(ParameterArray[i]);
|
||||
if (!TemplateParam)
|
||||
continue;
|
||||
if (TemplateParam->hasTypeConstraint())
|
||||
Fragments.append(TemplateParam->getTypeConstraint()
|
||||
->getNamedConcept()
|
||||
->getName()
|
||||
.str(),
|
||||
DeclarationFragments::FragmentKind::TypeIdentifier);
|
||||
else if (TemplateParam->wasDeclaredWithTypename())
|
||||
Fragments.append("typename", DeclarationFragments::FragmentKind::Keyword);
|
||||
else
|
||||
Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
|
||||
|
||||
if (TemplateParam->isParameterPack())
|
||||
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
|
||||
|
||||
Fragments.appendSpace().append(
|
||||
TemplateParam->getName(),
|
||||
DeclarationFragments::FragmentKind::GenericParameter);
|
||||
}
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
// Find the name of a template argument from the template's parameters.
|
||||
std::string DeclarationFragmentsBuilder::getNameForTemplateArgument(
|
||||
const ArrayRef<NamedDecl *> TemplateParameters, std::string TypeParameter) {
|
||||
// The arg is a generic parameter from a partial spec, e.g.
|
||||
// T in template<typename T> Foo<T, int>.
|
||||
//
|
||||
// Those names appear as "type-parameter-<index>-<depth>", so we must find its
|
||||
// name from the template's parameter list.
|
||||
for (unsigned i = 0; i < TemplateParameters.size(); ++i) {
|
||||
const auto *Parameter =
|
||||
dyn_cast<TemplateTypeParmDecl>(TemplateParameters[i]);
|
||||
if (TypeParameter.compare("type-parameter-" +
|
||||
std::to_string(Parameter->getDepth()) + "-" +
|
||||
std::to_string(Parameter->getIndex())) == 0)
|
||||
return std::string(TemplateParameters[i]->getName());
|
||||
}
|
||||
llvm_unreachable("Could not find the name of a template argument.");
|
||||
}
|
||||
|
||||
// Get fragments for template arguments, e.g. int in template<typename T>
|
||||
// Foo<int>;
|
||||
//
|
||||
// Note: TemplateParameters is only necessary if the Decl is a
|
||||
// PartialSpecialization, where we need the parameters to deduce the name of the
|
||||
// generic arguments.
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getFragmentsForTemplateArguments(
|
||||
const ArrayRef<TemplateArgument> TemplateArguments, ASTContext &Context,
|
||||
const std::optional<ArrayRef<NamedDecl *>> TemplateParameters) {
|
||||
DeclarationFragments Fragments;
|
||||
for (unsigned i = 0, end = TemplateArguments.size(); i != end; ++i) {
|
||||
if (i)
|
||||
Fragments.append(",", DeclarationFragments::FragmentKind::Text)
|
||||
.appendSpace();
|
||||
|
||||
std::string Type = TemplateArguments[i].getAsType().getAsString();
|
||||
DeclarationFragments After;
|
||||
DeclarationFragments ArgumentFragment =
|
||||
getFragmentsForType(TemplateArguments[i].getAsType(), Context, After);
|
||||
|
||||
if (ArgumentFragment.begin()->Spelling.substr(0, 14).compare(
|
||||
"type-parameter") == 0) {
|
||||
std::string ProperArgName = getNameForTemplateArgument(
|
||||
TemplateParameters.value(), ArgumentFragment.begin()->Spelling);
|
||||
ArgumentFragment.begin()->Spelling.swap(ProperArgName);
|
||||
}
|
||||
Fragments.append(std::move(ArgumentFragment));
|
||||
|
||||
if (TemplateArguments[i].isPackExpansion())
|
||||
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
|
||||
}
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept(
|
||||
const ConceptDecl *Concept) {
|
||||
DeclarationFragments Fragments;
|
||||
return Fragments
|
||||
.append("template", DeclarationFragments::FragmentKind::Keyword)
|
||||
.append("<", DeclarationFragments::FragmentKind::Text)
|
||||
.append(getFragmentsForTemplateParameters(
|
||||
Concept->getTemplateParameters()->asArray()))
|
||||
.append("> ", DeclarationFragments::FragmentKind::Text)
|
||||
.append("concept", DeclarationFragments::FragmentKind::Keyword)
|
||||
.appendSpace()
|
||||
.append(Concept->getName().str(),
|
||||
DeclarationFragments::FragmentKind::Identifier)
|
||||
.append(";", DeclarationFragments::FragmentKind::Text);
|
||||
}
|
||||
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
|
||||
const RedeclarableTemplateDecl *RedeclarableTemplate) {
|
||||
DeclarationFragments Fragments;
|
||||
Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
|
||||
.append("<", DeclarationFragments::FragmentKind::Text)
|
||||
.append(getFragmentsForTemplateParameters(
|
||||
RedeclarableTemplate->getTemplateParameters()->asArray()))
|
||||
.append(">", DeclarationFragments::FragmentKind::Text)
|
||||
.appendSpace();
|
||||
|
||||
if (isa<TypeAliasTemplateDecl>(RedeclarableTemplate))
|
||||
Fragments.appendSpace()
|
||||
.append("using", DeclarationFragments::FragmentKind::Keyword)
|
||||
.appendSpace()
|
||||
.append(RedeclarableTemplate->getName(),
|
||||
DeclarationFragments::FragmentKind::Identifier);
|
||||
// the templated records will be resposbible for injecting their templates
|
||||
return Fragments.appendSpace();
|
||||
}
|
||||
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
|
||||
const ClassTemplateSpecializationDecl *Decl) {
|
||||
DeclarationFragments Fragments;
|
||||
return Fragments
|
||||
.append("template", DeclarationFragments::FragmentKind::Keyword)
|
||||
.append("<", DeclarationFragments::FragmentKind::Text)
|
||||
.append(">", DeclarationFragments::FragmentKind::Text)
|
||||
.appendSpace()
|
||||
.append(DeclarationFragmentsBuilder::getFragmentsForCXXClass(
|
||||
cast<CXXRecordDecl>(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::getFragmentsForClassTemplatePartialSpecialization(
|
||||
const ClassTemplatePartialSpecializationDecl *Decl) {
|
||||
DeclarationFragments Fragments;
|
||||
return Fragments
|
||||
.append("template", DeclarationFragments::FragmentKind::Keyword)
|
||||
.append("<", DeclarationFragments::FragmentKind::Text)
|
||||
.append(getFragmentsForTemplateParameters(
|
||||
Decl->getTemplateParameters()->asArray()))
|
||||
.append(">", DeclarationFragments::FragmentKind::Text)
|
||||
.appendSpace()
|
||||
.append(DeclarationFragmentsBuilder::getFragmentsForCXXClass(
|
||||
cast<CXXRecordDecl>(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) {
|
||||
|
||||
@ -393,10 +393,17 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
|
||||
Kind["identifier"] = AddLangPrefix("type.property");
|
||||
Kind["displayName"] = "Type Property";
|
||||
break;
|
||||
case APIRecord::RK_ClassTemplate:
|
||||
case APIRecord::RK_ClassTemplateSpecialization:
|
||||
case APIRecord::RK_ClassTemplatePartialSpecialization:
|
||||
case APIRecord::RK_CXXClass:
|
||||
Kind["identifier"] = AddLangPrefix("class");
|
||||
Kind["displayName"] = "Class";
|
||||
break;
|
||||
case APIRecord::RK_Concept:
|
||||
Kind["identifier"] = AddLangPrefix("concept");
|
||||
Kind["displayName"] = "Concept";
|
||||
break;
|
||||
case APIRecord::RK_CXXStaticMethod:
|
||||
Kind["identifier"] = AddLangPrefix("type.method");
|
||||
Kind["displayName"] = "Static Method";
|
||||
@ -545,6 +552,52 @@ void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
|
||||
serializeString(Paren, "accessLevel", accessLevel);
|
||||
}
|
||||
|
||||
template <typename RecordTy>
|
||||
std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
|
||||
std::true_type) {
|
||||
const auto &Template = Record.Templ;
|
||||
if (Template.empty())
|
||||
return std::nullopt;
|
||||
|
||||
Object Generics;
|
||||
Array GenericParameters;
|
||||
for (const auto Param : Template.getParameters()) {
|
||||
Object Parameter;
|
||||
Parameter["name"] = Param.Name;
|
||||
Parameter["index"] = Param.Index;
|
||||
Parameter["depth"] = Param.Depth;
|
||||
GenericParameters.emplace_back(std::move(Parameter));
|
||||
}
|
||||
if (!GenericParameters.empty())
|
||||
Generics["parameters"] = std::move(GenericParameters);
|
||||
|
||||
Array GenericConstraints;
|
||||
for (const auto Constr : Template.getConstraints()) {
|
||||
Object Constraint;
|
||||
Constraint["kind"] = Constr.Kind;
|
||||
Constraint["lhs"] = Constr.LHS;
|
||||
Constraint["rhs"] = Constr.RHS;
|
||||
GenericConstraints.emplace_back(std::move(Constraint));
|
||||
}
|
||||
|
||||
if (!GenericConstraints.empty())
|
||||
Generics["constraints"] = std::move(GenericConstraints);
|
||||
|
||||
return Generics;
|
||||
}
|
||||
|
||||
template <typename RecordTy>
|
||||
std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
|
||||
std::false_type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename RecordTy>
|
||||
void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
|
||||
serializeObject(Paren, "swiftGenerics",
|
||||
serializeTemplateMixinImpl(Record, has_template<RecordTy>()));
|
||||
}
|
||||
|
||||
struct PathComponent {
|
||||
StringRef USR;
|
||||
StringRef Name;
|
||||
@ -691,6 +744,7 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
|
||||
|
||||
serializeFunctionSignatureMixin(Obj, Record);
|
||||
serializeAccessMixin(Obj, Record);
|
||||
serializeTemplateMixin(Obj, Record);
|
||||
|
||||
return Obj;
|
||||
}
|
||||
@ -726,6 +780,16 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
|
||||
llvm_unreachable("Unhandled relationship kind");
|
||||
}
|
||||
|
||||
StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
|
||||
switch (Kind) {
|
||||
case ConstraintKind::Conformance:
|
||||
return "conformance";
|
||||
case ConstraintKind::ConditionalConformance:
|
||||
return "conditionalConformance";
|
||||
}
|
||||
llvm_unreachable("Unhandled constraint kind");
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
|
||||
SymbolReference Source,
|
||||
SymbolReference Target) {
|
||||
@ -796,6 +860,56 @@ void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
|
||||
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::visitClassTemplateRecord(
|
||||
const ClassTemplateRecord &Record) {
|
||||
auto Class = serializeAPIRecord(Record);
|
||||
if (!Class)
|
||||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Class));
|
||||
serializeMembers(Record, Record.Fields);
|
||||
serializeMembers(Record, Record.Methods);
|
||||
|
||||
for (const auto Base : Record.Bases)
|
||||
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
|
||||
const ClassTemplateSpecializationRecord &Record) {
|
||||
auto Class = serializeAPIRecord(Record);
|
||||
if (!Class)
|
||||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Class));
|
||||
serializeMembers(Record, Record.Fields);
|
||||
serializeMembers(Record, Record.Methods);
|
||||
|
||||
for (const auto Base : Record.Bases)
|
||||
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
|
||||
const ClassTemplatePartialSpecializationRecord &Record) {
|
||||
auto Class = serializeAPIRecord(Record);
|
||||
if (!Class)
|
||||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Class));
|
||||
serializeMembers(Record, Record.Fields);
|
||||
serializeMembers(Record, Record.Methods);
|
||||
|
||||
for (const auto Base : Record.Bases)
|
||||
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) {
|
||||
auto Concept = serializeAPIRecord(Record);
|
||||
if (!Concept)
|
||||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Concept));
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::visitObjCContainerRecord(
|
||||
const ObjCContainerRecord &Record) {
|
||||
auto ObjCContainer = serializeAPIRecord(Record);
|
||||
|
||||
133
clang/test/ExtractAPI/class_template.cpp
Normal file
133
clang/test/ExtractAPI/class_template.cpp
Normal file
@ -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<typename T> class 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": "keyword",
|
||||
"spelling": "class"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@ST>1#T@Foo"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 28,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
140
clang/test/ExtractAPI/class_template_param_inheritance.cpp
Normal file
140
clang/test/ExtractAPI/class_template_param_inheritance.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
// 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<typename T> class Foo : public T {};
|
||||
|
||||
/// 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": "inheritsFrom",
|
||||
"source": "c:@ST>1#T@Foo",
|
||||
"target": "",
|
||||
"targetFallback": "T"
|
||||
}
|
||||
],
|
||||
"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": "keyword",
|
||||
"spelling": "class"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@ST>1#T@Foo"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 28,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
261
clang/test/ExtractAPI/class_template_partial_spec.cpp
Normal file
261
clang/test/ExtractAPI/class_template_partial_spec.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
// 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<typename X, typename Y> class Foo {};
|
||||
|
||||
template<typename Z> class Foo<Z, int> {};
|
||||
|
||||
/// 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": "keyword",
|
||||
"spelling": "class"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@ST>2#T#T@Foo"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 40,
|
||||
"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": "keyword",
|
||||
"spelling": "class"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "<"
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:t0.0",
|
||||
"spelling": "Z"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ", "
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:I",
|
||||
"spelling": "int"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ">;"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@SP>1#T@Foo>#t0.0#I"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 28,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
206
clang/test/ExtractAPI/class_template_spec.cpp
Normal file
206
clang/test/ExtractAPI/class_template_spec.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
// 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<typename T> class Foo {};
|
||||
|
||||
template<> class Foo<int> {};
|
||||
|
||||
/// 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": "keyword",
|
||||
"spelling": "class"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@ST>1#T@Foo"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 28,
|
||||
"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": "class"
|
||||
},
|
||||
{
|
||||
"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:@S@Foo>#I"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "c++.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 18,
|
||||
"line": 3
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"navigator": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
}
|
||||
],
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
}
|
||||
],
|
||||
"title": "Foo"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Foo"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
133
clang/test/ExtractAPI/concept.cpp
Normal file
133
clang/test/ExtractAPI/concept.cpp
Normal file
@ -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 -std=c++20 -extract-api -triple arm64-apple-macosx \
|
||||
// RUN: -x c++-header %t/input.h -o %t/output.json -verify
|
||||
|
||||
// Generator version is not consistent across test runs, normalize it.
|
||||
// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
|
||||
// RUN: %t/output.json >> %t/output-normalized.json
|
||||
// RUN: diff %t/reference.output.json %t/output-normalized.json
|
||||
|
||||
//--- input.h
|
||||
template<typename T> concept Foo = true;
|
||||
|
||||
/// 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": "keyword",
|
||||
"spelling": "concept"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Foo"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ";"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c++",
|
||||
"precise": "c:@CT@Foo"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Concept",
|
||||
"identifier": "c++.concept"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 30,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user