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 "Representation.h"
13 #include "llvm/Support/YAMLTraits.h"
14 #include "llvm/Support/raw_ostream.h"
17 using namespace clang::doc
;
19 // These define YAML traits for decoding the listed values within a vector.
20 LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo
)
21 LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo
)
22 LLVM_YAML_IS_SEQUENCE_VECTOR(Reference
)
23 LLVM_YAML_IS_SEQUENCE_VECTOR(Location
)
24 LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo
)
25 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo
)
26 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo
)
27 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumValueInfo
)
28 LLVM_YAML_IS_SEQUENCE_VECTOR(TemplateParamInfo
)
29 LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo
)
30 LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo
)
31 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr
<CommentInfo
>)
32 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString
<16>)
37 // Enumerations to YAML output.
39 template <> struct ScalarEnumerationTraits
<clang::AccessSpecifier
> {
40 static void enumeration(IO
&IO
, clang::AccessSpecifier
&Value
) {
41 IO
.enumCase(Value
, "Public", clang::AccessSpecifier::AS_public
);
42 IO
.enumCase(Value
, "Protected", clang::AccessSpecifier::AS_protected
);
43 IO
.enumCase(Value
, "Private", clang::AccessSpecifier::AS_private
);
44 IO
.enumCase(Value
, "None", clang::AccessSpecifier::AS_none
);
48 template <> struct ScalarEnumerationTraits
<clang::TagTypeKind
> {
49 static void enumeration(IO
&IO
, clang::TagTypeKind
&Value
) {
50 IO
.enumCase(Value
, "Struct", clang::TagTypeKind::TTK_Struct
);
51 IO
.enumCase(Value
, "Interface", clang::TagTypeKind::TTK_Interface
);
52 IO
.enumCase(Value
, "Union", clang::TagTypeKind::TTK_Union
);
53 IO
.enumCase(Value
, "Class", clang::TagTypeKind::TTK_Class
);
54 IO
.enumCase(Value
, "Enum", clang::TagTypeKind::TTK_Enum
);
58 template <> struct ScalarEnumerationTraits
<InfoType
> {
59 static void enumeration(IO
&IO
, InfoType
&Value
) {
60 IO
.enumCase(Value
, "Namespace", InfoType::IT_namespace
);
61 IO
.enumCase(Value
, "Record", InfoType::IT_record
);
62 IO
.enumCase(Value
, "Function", InfoType::IT_function
);
63 IO
.enumCase(Value
, "Enum", InfoType::IT_enum
);
64 IO
.enumCase(Value
, "Default", InfoType::IT_default
);
68 // Scalars to YAML output.
69 template <unsigned U
> struct ScalarTraits
<SmallString
<U
>> {
71 static void output(const SmallString
<U
> &S
, void *, llvm::raw_ostream
&OS
) {
72 for (const auto &C
: S
)
76 static StringRef
input(StringRef Scalar
, void *, SmallString
<U
> &Value
) {
77 Value
.assign(Scalar
.begin(), Scalar
.end());
81 static QuotingType
mustQuote(StringRef
) { return QuotingType::Single
; }
84 template <> struct ScalarTraits
<std::array
<unsigned char, 20>> {
86 static void output(const std::array
<unsigned char, 20> &S
, void *,
87 llvm::raw_ostream
&OS
) {
88 OS
<< toHex(toStringRef(S
));
91 static StringRef
input(StringRef Scalar
, void *,
92 std::array
<unsigned char, 20> &Value
) {
93 if (Scalar
.size() != 40)
94 return "Error: Incorrect scalar size for USR.";
95 Value
= StringToSymbol(Scalar
);
99 static SymbolID
StringToSymbol(llvm::StringRef Value
) {
101 std::string HexString
= fromHex(Value
);
102 std::copy(HexString
.begin(), HexString
.end(), USR
.begin());
103 return SymbolID(USR
);
106 static QuotingType
mustQuote(StringRef
) { return QuotingType::Single
; }
109 // Helper functions to map infos to YAML.
111 static void TypeInfoMapping(IO
&IO
, TypeInfo
&I
) {
112 IO
.mapOptional("Type", I
.Type
, Reference());
115 static void FieldTypeInfoMapping(IO
&IO
, FieldTypeInfo
&I
) {
116 TypeInfoMapping(IO
, I
);
117 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
118 IO
.mapOptional("DefaultValue", I
.DefaultValue
, SmallString
<16>());
121 static void InfoMapping(IO
&IO
, Info
&I
) {
122 IO
.mapRequired("USR", I
.USR
);
123 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
124 IO
.mapOptional("Path", I
.Path
, SmallString
<128>());
125 IO
.mapOptional("Namespace", I
.Namespace
, llvm::SmallVector
<Reference
, 4>());
126 IO
.mapOptional("Description", I
.Description
);
129 static void SymbolInfoMapping(IO
&IO
, SymbolInfo
&I
) {
131 IO
.mapOptional("DefLocation", I
.DefLoc
, std::optional
<Location
>());
132 IO
.mapOptional("Location", I
.Loc
, llvm::SmallVector
<Location
, 2>());
135 static void RecordInfoMapping(IO
&IO
, RecordInfo
&I
) {
136 SymbolInfoMapping(IO
, I
);
137 IO
.mapOptional("TagType", I
.TagType
);
138 IO
.mapOptional("IsTypeDef", I
.IsTypeDef
, false);
139 IO
.mapOptional("Members", I
.Members
);
140 IO
.mapOptional("Bases", I
.Bases
);
141 IO
.mapOptional("Parents", I
.Parents
, llvm::SmallVector
<Reference
, 4>());
142 IO
.mapOptional("VirtualParents", I
.VirtualParents
,
143 llvm::SmallVector
<Reference
, 4>());
144 IO
.mapOptional("ChildRecords", I
.Children
.Records
, std::vector
<Reference
>());
145 IO
.mapOptional("ChildFunctions", I
.Children
.Functions
);
146 IO
.mapOptional("ChildEnums", I
.Children
.Enums
);
147 IO
.mapOptional("ChildTypedefs", I
.Children
.Typedefs
);
148 IO
.mapOptional("Template", I
.Template
);
151 static void CommentInfoMapping(IO
&IO
, CommentInfo
&I
) {
152 IO
.mapOptional("Kind", I
.Kind
, SmallString
<16>());
153 IO
.mapOptional("Text", I
.Text
, SmallString
<64>());
154 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
155 IO
.mapOptional("Direction", I
.Direction
, SmallString
<8>());
156 IO
.mapOptional("ParamName", I
.ParamName
, SmallString
<16>());
157 IO
.mapOptional("CloseName", I
.CloseName
, SmallString
<16>());
158 IO
.mapOptional("SelfClosing", I
.SelfClosing
, false);
159 IO
.mapOptional("Explicit", I
.Explicit
, false);
160 IO
.mapOptional("Args", I
.Args
, llvm::SmallVector
<SmallString
<16>, 4>());
161 IO
.mapOptional("AttrKeys", I
.AttrKeys
,
162 llvm::SmallVector
<SmallString
<16>, 4>());
163 IO
.mapOptional("AttrValues", I
.AttrValues
,
164 llvm::SmallVector
<SmallString
<16>, 4>());
165 IO
.mapOptional("Children", I
.Children
);
168 // Template specialization to YAML traits for Infos.
170 template <> struct MappingTraits
<Location
> {
171 static void mapping(IO
&IO
, Location
&Loc
) {
172 IO
.mapOptional("LineNumber", Loc
.LineNumber
, 0);
173 IO
.mapOptional("Filename", Loc
.Filename
, SmallString
<32>());
177 template <> struct MappingTraits
<Reference
> {
178 static void mapping(IO
&IO
, Reference
&Ref
) {
179 IO
.mapOptional("Type", Ref
.RefType
, InfoType::IT_default
);
180 IO
.mapOptional("Name", Ref
.Name
, SmallString
<16>());
181 IO
.mapOptional("QualName", Ref
.QualName
, SmallString
<16>());
182 IO
.mapOptional("USR", Ref
.USR
, SymbolID());
183 IO
.mapOptional("Path", Ref
.Path
, SmallString
<128>());
187 template <> struct MappingTraits
<TypeInfo
> {
188 static void mapping(IO
&IO
, TypeInfo
&I
) { TypeInfoMapping(IO
, I
); }
191 template <> struct MappingTraits
<FieldTypeInfo
> {
192 static void mapping(IO
&IO
, FieldTypeInfo
&I
) {
193 TypeInfoMapping(IO
, I
);
194 IO
.mapOptional("Name", I
.Name
, SmallString
<16>());
195 IO
.mapOptional("DefaultValue", I
.DefaultValue
, SmallString
<16>());
199 template <> struct MappingTraits
<MemberTypeInfo
> {
200 static void mapping(IO
&IO
, MemberTypeInfo
&I
) {
201 FieldTypeInfoMapping(IO
, I
);
202 // clang::AccessSpecifier::AS_none is used as the default here because it's
203 // the AS that shouldn't be part of the output. Even though AS_public is the
204 // default in the struct, it should be displayed in the YAML output.
205 IO
.mapOptional("Access", I
.Access
, clang::AccessSpecifier::AS_none
);
206 IO
.mapOptional("Description", I
.Description
);
210 template <> struct MappingTraits
<NamespaceInfo
> {
211 static void mapping(IO
&IO
, NamespaceInfo
&I
) {
213 IO
.mapOptional("ChildNamespaces", I
.Children
.Namespaces
,
214 std::vector
<Reference
>());
215 IO
.mapOptional("ChildRecords", I
.Children
.Records
,
216 std::vector
<Reference
>());
217 IO
.mapOptional("ChildFunctions", I
.Children
.Functions
);
218 IO
.mapOptional("ChildEnums", I
.Children
.Enums
);
219 IO
.mapOptional("ChildTypedefs", I
.Children
.Typedefs
);
223 template <> struct MappingTraits
<RecordInfo
> {
224 static void mapping(IO
&IO
, RecordInfo
&I
) { RecordInfoMapping(IO
, I
); }
227 template <> struct MappingTraits
<BaseRecordInfo
> {
228 static void mapping(IO
&IO
, BaseRecordInfo
&I
) {
229 RecordInfoMapping(IO
, I
);
230 IO
.mapOptional("IsVirtual", I
.IsVirtual
, false);
231 // clang::AccessSpecifier::AS_none is used as the default here because it's
232 // the AS that shouldn't be part of the output. Even though AS_public is the
233 // default in the struct, it should be displayed in the YAML output.
234 IO
.mapOptional("Access", I
.Access
, clang::AccessSpecifier::AS_none
);
235 IO
.mapOptional("IsParent", I
.IsParent
, false);
239 template <> struct MappingTraits
<EnumValueInfo
> {
240 static void mapping(IO
&IO
, EnumValueInfo
&I
) {
241 IO
.mapOptional("Name", I
.Name
);
242 IO
.mapOptional("Value", I
.Value
);
243 IO
.mapOptional("Expr", I
.ValueExpr
, SmallString
<16>());
247 template <> struct MappingTraits
<EnumInfo
> {
248 static void mapping(IO
&IO
, EnumInfo
&I
) {
249 SymbolInfoMapping(IO
, I
);
250 IO
.mapOptional("Scoped", I
.Scoped
, false);
251 IO
.mapOptional("BaseType", I
.BaseType
);
252 IO
.mapOptional("Members", I
.Members
);
256 template <> struct MappingTraits
<TypedefInfo
> {
257 static void mapping(IO
&IO
, TypedefInfo
&I
) {
258 SymbolInfoMapping(IO
, I
);
259 IO
.mapOptional("Underlying", I
.Underlying
.Type
);
260 IO
.mapOptional("IsUsing", I
.IsUsing
, false);
264 template <> struct MappingTraits
<FunctionInfo
> {
265 static void mapping(IO
&IO
, FunctionInfo
&I
) {
266 SymbolInfoMapping(IO
, I
);
267 IO
.mapOptional("IsMethod", I
.IsMethod
, false);
268 IO
.mapOptional("Parent", I
.Parent
, Reference());
269 IO
.mapOptional("Params", I
.Params
);
270 IO
.mapOptional("ReturnType", I
.ReturnType
);
271 // clang::AccessSpecifier::AS_none is used as the default here because it's
272 // the AS that shouldn't be part of the output. Even though AS_public is the
273 // default in the struct, it should be displayed in the YAML output.
274 IO
.mapOptional("Access", I
.Access
, clang::AccessSpecifier::AS_none
);
275 IO
.mapOptional("Template", I
.Template
);
279 template <> struct MappingTraits
<TemplateParamInfo
> {
280 static void mapping(IO
&IO
, TemplateParamInfo
&I
) {
281 IO
.mapOptional("Contents", I
.Contents
);
285 template <> struct MappingTraits
<TemplateSpecializationInfo
> {
286 static void mapping(IO
&IO
, TemplateSpecializationInfo
&I
) {
287 IO
.mapOptional("SpecializationOf", I
.SpecializationOf
);
288 IO
.mapOptional("Params", I
.Params
);
292 template <> struct MappingTraits
<TemplateInfo
> {
293 static void mapping(IO
&IO
, TemplateInfo
&I
) {
294 IO
.mapOptional("Params", I
.Params
);
295 IO
.mapOptional("Specialization", I
.Specialization
,
296 std::optional
<TemplateSpecializationInfo
>());
300 template <> struct MappingTraits
<CommentInfo
> {
301 static void mapping(IO
&IO
, CommentInfo
&I
) { CommentInfoMapping(IO
, I
); }
304 template <> struct MappingTraits
<std::unique_ptr
<CommentInfo
>> {
305 static void mapping(IO
&IO
, std::unique_ptr
<CommentInfo
> &I
) {
307 CommentInfoMapping(IO
, *I
);
311 } // end namespace yaml
312 } // end namespace llvm
317 /// Generator for YAML documentation.
318 class YAMLGenerator
: public Generator
{
320 static const char *Format
;
322 llvm::Error
generateDocs(StringRef RootDir
,
323 llvm::StringMap
<std::unique_ptr
<doc::Info
>> Infos
,
324 const ClangDocContext
&CDCtx
) override
;
325 llvm::Error
generateDocForInfo(Info
*I
, llvm::raw_ostream
&OS
,
326 const ClangDocContext
&CDCtx
) override
;
329 const char *YAMLGenerator::Format
= "yaml";
332 YAMLGenerator::generateDocs(StringRef RootDir
,
333 llvm::StringMap
<std::unique_ptr
<doc::Info
>> Infos
,
334 const ClangDocContext
&CDCtx
) {
335 for (const auto &Group
: Infos
) {
336 doc::Info
*Info
= Group
.getValue().get();
338 // Output file names according to the USR except the global namesapce.
339 // Anonymous namespaces are taken care of in serialization, so here we can
340 // safely assume an unnamed namespace is the global one.
341 llvm::SmallString
<128> Path
;
342 llvm::sys::path::native(RootDir
, Path
);
343 if (Info
->IT
== InfoType::IT_namespace
&& Info
->Name
.empty()) {
344 llvm::sys::path::append(Path
, "index.yaml");
346 llvm::sys::path::append(Path
, Group
.getKey() + ".yaml");
349 std::error_code FileErr
;
350 llvm::raw_fd_ostream
InfoOS(Path
, FileErr
, llvm::sys::fs::OF_None
);
352 return llvm::createStringError(FileErr
, "Error opening file '%s'",
356 if (llvm::Error Err
= generateDocForInfo(Info
, InfoOS
, CDCtx
)) {
361 return llvm::Error::success();
364 llvm::Error
YAMLGenerator::generateDocForInfo(Info
*I
, llvm::raw_ostream
&OS
,
365 const ClangDocContext
&CDCtx
) {
366 llvm::yaml::Output
InfoYAML(OS
);
368 case InfoType::IT_namespace
:
369 InfoYAML
<< *static_cast<clang::doc::NamespaceInfo
*>(I
);
371 case InfoType::IT_record
:
372 InfoYAML
<< *static_cast<clang::doc::RecordInfo
*>(I
);
374 case InfoType::IT_enum
:
375 InfoYAML
<< *static_cast<clang::doc::EnumInfo
*>(I
);
377 case InfoType::IT_function
:
378 InfoYAML
<< *static_cast<clang::doc::FunctionInfo
*>(I
);
380 case InfoType::IT_typedef
:
381 InfoYAML
<< *static_cast<clang::doc::TypedefInfo
*>(I
);
383 case InfoType::IT_default
:
384 return llvm::createStringError(llvm::inconvertibleErrorCode(),
385 "unexpected InfoType");
387 return llvm::Error::success();
390 static GeneratorRegistry::Add
<YAMLGenerator
> YAML(YAMLGenerator::Format
,
391 "Generator for YAML output.");
393 // This anchor is used to force the linker to link in the generated object file
394 // and thus register the generator.
395 volatile int YAMLGeneratorAnchorSource
= 0;