1 //===-- YAMLGenerator.cpp - ClangDoc YAML -----------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // Implementation of the YAML generator, converting decl info into YAML output.
9 //===----------------------------------------------------------------------===//
11 #include "Generators.h"
12 #include "llvm/Support/YAMLTraits.h"
13 #include "llvm/Support/raw_ostream.h"
15 using namespace clang::doc
;
17 LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo
)
18 LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo
)
19 LLVM_YAML_IS_SEQUENCE_VECTOR(Reference
)
20 LLVM_YAML_IS_SEQUENCE_VECTOR(Location
)
21 LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo
)
22 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo
)
23 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo
)
24 LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo
)
25 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr
<CommentInfo
>)
26 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString
<16>)
31 // Enumerations to YAML output.
33 template <> struct ScalarEnumerationTraits
<clang::AccessSpecifier
> {
34 static void enumeration(IO
&IO
, clang::AccessSpecifier
&Value
) {
35 IO
.enumCase(Value
, "Public", clang::AccessSpecifier::AS_public
);
36 IO
.enumCase(Value
, "Protected", clang::AccessSpecifier::AS_protected
);
37 IO
.enumCase(Value
, "Private", clang::AccessSpecifier::AS_private
);
38 IO
.enumCase(Value
, "None", clang::AccessSpecifier::AS_none
);
42 template <> struct ScalarEnumerationTraits
<clang::TagTypeKind
> {
43 static void enumeration(IO
&IO
, clang::TagTypeKind
&Value
) {
44 IO
.enumCase(Value
, "Struct", clang::TagTypeKind::TTK_Struct
);
45 IO
.enumCase(Value
, "Interface", clang::TagTypeKind::TTK_Interface
);
46 IO
.enumCase(Value
, "Union", clang::TagTypeKind::TTK_Union
);
47 IO
.enumCase(Value
, "Class", clang::TagTypeKind::TTK_Class
);
48 IO
.enumCase(Value
, "Enum", clang::TagTypeKind::TTK_Enum
);
52 template <> struct ScalarEnumerationTraits
<InfoType
> {
53 static void enumeration(IO
&IO
, InfoType
&Value
) {
54 IO
.enumCase(Value
, "Namespace", InfoType::IT_namespace
);
55 IO
.enumCase(Value
, "Record", InfoType::IT_record
);
56 IO
.enumCase(Value
, "Function", InfoType::IT_function
);
57 IO
.enumCase(Value
, "Enum", InfoType::IT_enum
);
58 IO
.enumCase(Value
, "Default", InfoType::IT_default
);
62 // Scalars to YAML output.
63 template <unsigned U
> struct ScalarTraits
<SmallString
<U
>> {
65 static void output(const SmallString
<U
> &S
, void *, llvm::raw_ostream
&OS
) {
66 for (const auto &C
: S
)
70 static StringRef
input(StringRef Scalar
, void *, SmallString
<U
> &Value
) {
71 Value
.assign(Scalar
.begin(), Scalar
.end());
75 static QuotingType
mustQuote(StringRef
) { return QuotingType::Single
; }
78 template <> struct ScalarTraits
<std::array
<unsigned char, 20>> {
80 static void output(const std::array
<unsigned char, 20> &S
, void *,
81 llvm::raw_ostream
&OS
) {
82 OS
<< toHex(toStringRef(S
));
85 static StringRef
input(StringRef Scalar
, void *,
86 std::array
<unsigned char, 20> &Value
) {
87 if (Scalar
.size() != 40)
88 return "Error: Incorrect scalar size for USR.";
89 Value
= StringToSymbol(Scalar
);
93 static SymbolID
StringToSymbol(llvm::StringRef Value
) {
95 std::string HexString
= fromHex(Value
);
96 std::copy(HexString
.begin(), HexString
.end(), USR
.begin());
100 static QuotingType
mustQuote(StringRef
) { return QuotingType::Single
; }
103 // Helper functions to map infos to YAML.
105 static void TypeInfoMapping(IO
&IO
, TypeInfo
&I
) {
106 IO
.mapOptional("Type", I
.Type
, Reference());
109 static void FieldTypeInfoMapping(IO
&IO
, FieldTypeInfo
&I
) {
110 TypeInfoMapping(IO
, I
);
111 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
114 static void InfoMapping(IO
&IO
, Info
&I
) {
115 IO
.mapRequired("USR", I
.USR
);
116 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
117 IO
.mapOptional("Path", I
.Path
, SmallString
<128>());
118 IO
.mapOptional("Namespace", I
.Namespace
, llvm::SmallVector
<Reference
, 4>());
119 IO
.mapOptional("Description", I
.Description
);
122 static void SymbolInfoMapping(IO
&IO
, SymbolInfo
&I
) {
124 IO
.mapOptional("DefLocation", I
.DefLoc
, Optional
<Location
>());
125 IO
.mapOptional("Location", I
.Loc
, llvm::SmallVector
<Location
, 2>());
128 static void RecordInfoMapping(IO
&IO
, RecordInfo
&I
) {
129 SymbolInfoMapping(IO
, I
);
130 IO
.mapOptional("TagType", I
.TagType
, clang::TagTypeKind::TTK_Struct
);
131 IO
.mapOptional("Members", I
.Members
);
132 IO
.mapOptional("Bases", I
.Bases
);
133 IO
.mapOptional("Parents", I
.Parents
, llvm::SmallVector
<Reference
, 4>());
134 IO
.mapOptional("VirtualParents", I
.VirtualParents
,
135 llvm::SmallVector
<Reference
, 4>());
136 IO
.mapOptional("ChildRecords", I
.ChildRecords
, std::vector
<Reference
>());
137 IO
.mapOptional("ChildFunctions", I
.ChildFunctions
);
138 IO
.mapOptional("ChildEnums", I
.ChildEnums
);
141 static void CommentInfoMapping(IO
&IO
, CommentInfo
&I
) {
142 IO
.mapOptional("Kind", I
.Kind
, SmallString
<16>());
143 IO
.mapOptional("Text", I
.Text
, SmallString
<64>());
144 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
145 IO
.mapOptional("Direction", I
.Direction
, SmallString
<8>());
146 IO
.mapOptional("ParamName", I
.ParamName
, SmallString
<16>());
147 IO
.mapOptional("CloseName", I
.CloseName
, SmallString
<16>());
148 IO
.mapOptional("SelfClosing", I
.SelfClosing
, false);
149 IO
.mapOptional("Explicit", I
.Explicit
, false);
150 IO
.mapOptional("Args", I
.Args
, llvm::SmallVector
<SmallString
<16>, 4>());
151 IO
.mapOptional("AttrKeys", I
.AttrKeys
,
152 llvm::SmallVector
<SmallString
<16>, 4>());
153 IO
.mapOptional("AttrValues", I
.AttrValues
,
154 llvm::SmallVector
<SmallString
<16>, 4>());
155 IO
.mapOptional("Children", I
.Children
);
158 // Template specialization to YAML traits for Infos.
160 template <> struct MappingTraits
<Location
> {
161 static void mapping(IO
&IO
, Location
&Loc
) {
162 IO
.mapOptional("LineNumber", Loc
.LineNumber
, 0);
163 IO
.mapOptional("Filename", Loc
.Filename
, SmallString
<32>());
167 template <> struct MappingTraits
<Reference
> {
168 static void mapping(IO
&IO
, Reference
&Ref
) {
169 IO
.mapOptional("Type", Ref
.RefType
, InfoType::IT_default
);
170 IO
.mapOptional("Name", Ref
.Name
, SmallString
<16>());
171 IO
.mapOptional("USR", Ref
.USR
, SymbolID());
172 IO
.mapOptional("Path", Ref
.Path
, SmallString
<128>());
173 IO
.mapOptional("IsInGlobalNamespace", Ref
.IsInGlobalNamespace
, false);
177 template <> struct MappingTraits
<TypeInfo
> {
178 static void mapping(IO
&IO
, TypeInfo
&I
) { TypeInfoMapping(IO
, I
); }
181 template <> struct MappingTraits
<FieldTypeInfo
> {
182 static void mapping(IO
&IO
, FieldTypeInfo
&I
) {
183 TypeInfoMapping(IO
, I
);
184 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
188 template <> struct MappingTraits
<MemberTypeInfo
> {
189 static void mapping(IO
&IO
, MemberTypeInfo
&I
) {
190 FieldTypeInfoMapping(IO
, I
);
191 // clang::AccessSpecifier::AS_none is used as the default here because it's
192 // the AS that shouldn't be part of the output. Even though AS_public is the
193 // default in the struct, it should be displayed in the YAML output.
194 IO
.mapOptional("Access", I
.Access
, clang::AccessSpecifier::AS_none
);
198 template <> struct MappingTraits
<NamespaceInfo
> {
199 static void mapping(IO
&IO
, NamespaceInfo
&I
) {
201 IO
.mapOptional("ChildNamespaces", I
.ChildNamespaces
,
202 std::vector
<Reference
>());
203 IO
.mapOptional("ChildRecords", I
.ChildRecords
, std::vector
<Reference
>());
204 IO
.mapOptional("ChildFunctions", I
.ChildFunctions
);
205 IO
.mapOptional("ChildEnums", I
.ChildEnums
);
209 template <> struct MappingTraits
<RecordInfo
> {
210 static void mapping(IO
&IO
, RecordInfo
&I
) { RecordInfoMapping(IO
, I
); }
213 template <> struct MappingTraits
<BaseRecordInfo
> {
214 static void mapping(IO
&IO
, BaseRecordInfo
&I
) {
215 RecordInfoMapping(IO
, I
);
216 IO
.mapOptional("IsVirtual", I
.IsVirtual
, false);
217 // clang::AccessSpecifier::AS_none is used as the default here because it's
218 // the AS that shouldn't be part of the output. Even though AS_public is the
219 // default in the struct, it should be displayed in the YAML output.
220 IO
.mapOptional("Access", I
.Access
, clang::AccessSpecifier::AS_none
);
221 IO
.mapOptional("IsParent", I
.IsParent
, false);
225 template <> struct MappingTraits
<EnumInfo
> {
226 static void mapping(IO
&IO
, EnumInfo
&I
) {
227 SymbolInfoMapping(IO
, I
);
228 IO
.mapOptional("Scoped", I
.Scoped
, false);
229 IO
.mapOptional("Members", I
.Members
);
233 template <> struct MappingTraits
<FunctionInfo
> {
234 static void mapping(IO
&IO
, FunctionInfo
&I
) {
235 SymbolInfoMapping(IO
, I
);
236 IO
.mapOptional("IsMethod", I
.IsMethod
, false);
237 IO
.mapOptional("Parent", I
.Parent
, Reference());
238 IO
.mapOptional("Params", I
.Params
);
239 IO
.mapOptional("ReturnType", I
.ReturnType
);
240 // clang::AccessSpecifier::AS_none is used as the default here because it's
241 // the AS that shouldn't be part of the output. Even though AS_public is the
242 // default in the struct, it should be displayed in the YAML output.
243 IO
.mapOptional("Access", I
.Access
, clang::AccessSpecifier::AS_none
);
247 template <> struct MappingTraits
<CommentInfo
> {
248 static void mapping(IO
&IO
, CommentInfo
&I
) { CommentInfoMapping(IO
, I
); }
251 template <> struct MappingTraits
<std::unique_ptr
<CommentInfo
>> {
252 static void mapping(IO
&IO
, std::unique_ptr
<CommentInfo
> &I
) {
254 CommentInfoMapping(IO
, *I
);
258 } // end namespace yaml
259 } // end namespace llvm
264 /// Generator for YAML documentation.
265 class YAMLGenerator
: public Generator
{
267 static const char *Format
;
269 llvm::Error
generateDocForInfo(Info
*I
, llvm::raw_ostream
&OS
,
270 const ClangDocContext
&CDCtx
) override
;
273 const char *YAMLGenerator::Format
= "yaml";
275 llvm::Error
YAMLGenerator::generateDocForInfo(Info
*I
, llvm::raw_ostream
&OS
,
276 const ClangDocContext
&CDCtx
) {
277 llvm::yaml::Output
InfoYAML(OS
);
279 case InfoType::IT_namespace
:
280 InfoYAML
<< *static_cast<clang::doc::NamespaceInfo
*>(I
);
282 case InfoType::IT_record
:
283 InfoYAML
<< *static_cast<clang::doc::RecordInfo
*>(I
);
285 case InfoType::IT_enum
:
286 InfoYAML
<< *static_cast<clang::doc::EnumInfo
*>(I
);
288 case InfoType::IT_function
:
289 InfoYAML
<< *static_cast<clang::doc::FunctionInfo
*>(I
);
291 case InfoType::IT_default
:
292 return llvm::createStringError(llvm::inconvertibleErrorCode(),
293 "unexpected InfoType");
295 return llvm::Error::success();
298 static GeneratorRegistry::Add
<YAMLGenerator
> YAML(YAMLGenerator::Format
,
299 "Generator for YAML output.");
301 // This anchor is used to force the linker to link in the generated object file
302 // and thus register the generator.
303 volatile int YAMLGeneratorAnchorSource
= 0;