evelez7 updated this revision to Diff 548042.
evelez7 added a comment.
Add brackets for SerializerBase visit methods
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D157076/new/
https://reviews.llvm.org/D157076
Files:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/DeclarationFragments.h
clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
clang/lib/ExtractAPI/API.cpp
clang/lib/ExtractAPI/DeclarationFragments.cpp
clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
clang/test/ExtractAPI/class_template.cpp
clang/test/ExtractAPI/class_template_partial_spec.cpp
clang/test/ExtractAPI/class_template_spec.cpp
clang/test/ExtractAPI/concept.cpp
Index: clang/test/ExtractAPI/concept.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/concept.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 -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"
+ }
+ ]
+ }
+ }
+ ]
+}
Index: clang/test/ExtractAPI/class_template_spec.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/class_template_spec.cpp
@@ -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"
+ ]
+ }
+ ]
+}
Index: clang/test/ExtractAPI/class_template_partial_spec.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/class_template_partial_spec.cpp
@@ -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"
+ }
+ ]
+ }
+ }
+ ]
+}
Index: clang/test/ExtractAPI/class_template.cpp
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/class_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<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"
+ }
+ ]
+ }
+ }
+ ]
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -387,10 +387,17 @@
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";
@@ -536,6 +543,52 @@
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;
@@ -680,6 +733,7 @@
serializeFunctionSignatureMixin(Obj, Record);
serializeAccessMixin(Obj, Record);
+ serializeTemplateMixin(Obj, Record);
return Obj;
}
@@ -713,6 +767,16 @@
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) {
@@ -783,6 +847,56 @@
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::visitClassTemplateSpecRecord(
+ const ClassTemplateSpecRecord &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::visitClassTemplatePartialSpecRecord(
+ const ClassTemplatePartialSpecRecord &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);
Index: clang/lib/ExtractAPI/DeclarationFragments.cpp
===================================================================
--- clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -735,6 +735,174 @@
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->getIndex()) + "-" +
+ std::to_string(Parameter->getDepth())) == 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) {
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -159,6 +159,49 @@
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);
+}
+
+ClassTemplateSpecRecord *APISet::addClassTemplateSpec(
+ 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);
+}
+
+ClassTemplatePartialSpecRecord *APISet::addClassTemplatePartialSpec(
+ 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,
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -92,6 +92,10 @@
/// 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();
@@ -164,6 +168,15 @@
void visitCXXClassRecord(const CXXClassRecord &Record);
+ void visitClassTemplateRecord(const ClassTemplateRecord &Record);
+
+ void visitClassTemplateSpecRecord(const ClassTemplateSpecRecord &Record);
+
+ void visitClassTemplatePartialSpecRecord(
+ const ClassTemplatePartialSpecRecord &Record);
+
+ void visitConceptRecord(const ConceptRecord &Record);
+
/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record);
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -33,6 +33,14 @@
getDerived()->traverseCXXClassRecords();
+ getDerived()->traverseClassTemplateRecords();
+
+ getDerived()->traverseClassTemplateSpecRecords();
+
+ getDerived()->traverseClassTemplatePartialSpecRecords();
+
+ getDerived()->traverseConcepts();
+
getDerived()->traverseStructRecords();
getDerived()->traverseObjCInterfaces();
@@ -74,6 +82,28 @@
getDerived()->visitCXXClassRecord(*Class.second);
}
+ void traverseClassTemplateRecords() {
+ for (const auto &ClassTemplate : API.getClassTemplates())
+ getDerived()->visitClassTemplateRecord(*ClassTemplate.second);
+ }
+
+ void traverseClassTemplateSpecRecords() {
+ for (const auto &ClassTemplateSpec : API.getClassTemplateSpecializations())
+ getDerived()->visitClassTemplateSpecRecord(*ClassTemplateSpec.second);
+ }
+
+ void traverseClassTemplatePartialSpecRecords() {
+ for (const auto &ClassTemplatePartialSpec :
+ API.getClassTemplatePartialSpecializations())
+ getDerived()->visitClassTemplatePartialSpecRecord(
+ *ClassTemplatePartialSpec.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);
@@ -110,6 +140,13 @@
void visitCXXClassRecord(const CXXClassRecord &Record){};
+ void visitClassTemplateRecord(const ClassTemplateRecord &Record){};
+
+ void visitClassTemplateSpecRecord(const ClassTemplateSpecRecord &Record){};
+
+ void visitClassTemplatePartialSpecRecord(
+ const ClassTemplatePartialSpecRecord &Record){};
+
/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record){};
Index: clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
===================================================================
--- clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -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 @@
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);
@@ -328,6 +343,22 @@
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 +399,8 @@
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,9 +425,23 @@
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()));
+ // Cast to easily use previous declaration to get bases.
+ CXXClassRecord = API.addClassTemplate(
+ Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+ DeclarationFragmentsBuilder::getTemplate(
+ 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()) {
@@ -416,6 +462,116 @@
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, DeclarationFragmentsBuilder::getTemplate(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);
+
+ ClassTemplateSpecRecord *ClassTemplateSpecializationRecord =
+ API.addClassTemplateSpec(Name, USR, Loc, AvailabilitySet(Decl), Comment,
+ Declaration, SubHeading, isInSystemHeader(Decl));
+
+ // FIXME: store AccessSpecifier given by inheritance
+ for (const auto BaseSpecifier : Decl->bases()) {
+ SymbolReference BaseClass;
+ CXXRecordDecl *BaseClassDecl =
+ BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl();
+ BaseClass.Name = BaseClassDecl->getName();
+ BaseClass.USR = API.recordUSR(BaseClassDecl);
+ ClassTemplateSpecializationRecord->Bases.emplace_back(BaseClass);
+ }
+
+ 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);
+
+ ClassTemplatePartialSpecRecord *ClassTemplatePartialSpecRecord =
+ API.addClassTemplatePartialSpec(
+ Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+ SubHeading, DeclarationFragmentsBuilder::getTemplate(Decl),
+ isInSystemHeader(Decl));
+
+ // FIXME: store AccessSpecifier given by inheritance
+ for (const auto BaseSpecifier : Decl->bases()) {
+ SymbolReference BaseClass;
+ CXXRecordDecl *BaseClassDecl =
+ BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl();
+ BaseClass.Name = BaseClassDecl->getName();
+ BaseClass.USR = API.recordUSR(BaseClassDecl);
+ ClassTemplatePartialSpecRecord->Bases.emplace_back(BaseClass);
+ }
+
+ getDerivedExtractAPIVisitor().recordCXXFields(ClassTemplatePartialSpecRecord,
+ Decl->fields());
+ getDerivedExtractAPIVisitor().recordCXXMethods(ClassTemplatePartialSpecRecord,
+ Decl->methods());
+ return true;
+}
+
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
const ObjCInterfaceDecl *Decl) {
Index: clang/include/clang/ExtractAPI/DeclarationFragments.h
===================================================================
--- clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -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 @@
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
@@ -182,6 +188,50 @@
std::vector<Fragment> Fragments;
};
+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;
+ };
+ SmallVector<TemplateParameter> Parameters;
+ SmallVector<TemplateConstraint> Constraints;
+
+public:
+ Template() = default;
+
+ const SmallVector<TemplateParameter> &getParameters() const {
+ return Parameters;
+ }
+
+ const 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(); }
+};
+
class AccessControl {
public:
AccessControl(std::string Access) : Access(Access) {}
@@ -259,6 +309,50 @@
llvm_unreachable("Unhandled access control");
}
+ /// Get template details from a template function, class, or variable
+ static Template getTemplate(const TemplateDecl *Decl) {
+ Template Template;
+ 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";
+
+ 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<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";
+
+ Template.addTemplateParameter(Type, Param->getName().str(),
+ Param->getIndex(), Param->getDepth(),
+ Param->isParameterPack());
+ }
+ return Template;
+ }
+
/// Build DeclarationFragments for a variable declaration VarDecl.
static DeclarationFragments getFragmentsForVar(const VarDecl *);
@@ -292,6 +386,28 @@
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
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -69,6 +69,10 @@
RK_StaticField,
RK_CXXField,
RK_CXXClass,
+ RK_ClassTemplate,
+ RK_ClassTemplateSpecialization,
+ RK_ClassTemplatePartialSpecialization,
+ RK_Concept,
RK_CXXStaticMethod,
RK_CXXInstanceMethod,
RK_CXXConstructorMethod,
@@ -640,6 +644,75 @@
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 ClassTemplateSpecRecord : CXXClassRecord {
+ ClassTemplateSpecRecord(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 ClassTemplatePartialSpecRecord : CXXClassRecord {
+ Template Templ;
+ ClassTemplatePartialSpecRecord(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;
@@ -773,6 +846,12 @@
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<ClassTemplatePartialSpecRecord> : 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:
@@ -870,6 +949,26 @@
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);
+
+ ClassTemplateSpecRecord *
+ addClassTemplateSpec(StringRef Name, StringRef USR, PresumedLoc Loc,
+ AvailabilitySet Availability, const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader);
+
+ ClassTemplatePartialSpecRecord *addClassTemplatePartialSpec(
+ 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,
@@ -884,6 +983,13 @@
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
@@ -1012,6 +1118,19 @@
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<ClassTemplateSpecRecord> &
+ getClassTemplateSpecializations() const {
+ return ClassTemplateSpecializations;
+ }
+ const RecordMap<ClassTemplatePartialSpecRecord> &
+ getClassTemplatePartialSpecializations() const {
+ return ClassTemplatePartialSpecializations;
+ }
+ const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
return ObjCCategories;
}
@@ -1065,10 +1184,14 @@
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<ClassTemplateSpecRecord> ClassTemplateSpecializations;
+ RecordMap<ClassTemplatePartialSpecRecord> ClassTemplatePartialSpecializations;
RecordMap<ObjCCategoryRecord> ObjCCategories;
RecordMap<ObjCInterfaceRecord> ObjCInterfaces;
RecordMap<ObjCProtocolRecord> ObjCProtocols;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits