[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:
Erick Velez
2023-08-18 12:03:44 -07:00
parent d8900f661a
commit 7ba37f4e46
13 changed files with 1648 additions and 16 deletions

View File

@@ -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);