1//===-- YAMLGenerator.cpp - ClangDoc YAML -----------------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8// Implementation of the YAML generator, converting decl info into YAML output.
9//===----------------------------------------------------------------------===//
10
11#include "Generators.h"
12#include "Representation.h"
13#include "llvm/Support/YAMLTraits.h"
14#include "llvm/Support/raw_ostream.h"
15#include <optional>
16
17using namespace clang::doc;
18
19// These define YAML traits for decoding the listed values within a vector.
20LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo)
21LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo)
22LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
23LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
24LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
25LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
26LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
27LLVM_YAML_IS_SEQUENCE_VECTOR(EnumValueInfo)
28LLVM_YAML_IS_SEQUENCE_VECTOR(TemplateParamInfo)
29LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo)
30LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
31LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
32LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
33
34namespace llvm {
35namespace yaml {
36
37// Enumerations to YAML output.
38
39template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
40 static void enumeration(IO &IO, clang::AccessSpecifier &Value) {
41 IO.enumCase(Val&: Value, Str: "Public", ConstVal: clang::AccessSpecifier::AS_public);
42 IO.enumCase(Val&: Value, Str: "Protected", ConstVal: clang::AccessSpecifier::AS_protected);
43 IO.enumCase(Val&: Value, Str: "Private", ConstVal: clang::AccessSpecifier::AS_private);
44 IO.enumCase(Val&: Value, Str: "None", ConstVal: clang::AccessSpecifier::AS_none);
45 }
46};
47
48template <> struct ScalarEnumerationTraits<clang::TagTypeKind> {
49 static void enumeration(IO &IO, clang::TagTypeKind &Value) {
50 IO.enumCase(Val&: Value, Str: "Struct", ConstVal: clang::TagTypeKind::Struct);
51 IO.enumCase(Val&: Value, Str: "Interface", ConstVal: clang::TagTypeKind::Interface);
52 IO.enumCase(Val&: Value, Str: "Union", ConstVal: clang::TagTypeKind::Union);
53 IO.enumCase(Val&: Value, Str: "Class", ConstVal: clang::TagTypeKind::Class);
54 IO.enumCase(Val&: Value, Str: "Enum", ConstVal: clang::TagTypeKind::Enum);
55 }
56};
57
58template <> struct ScalarEnumerationTraits<InfoType> {
59 static void enumeration(IO &IO, InfoType &Value) {
60 IO.enumCase(Val&: Value, Str: "Namespace", ConstVal: InfoType::IT_namespace);
61 IO.enumCase(Val&: Value, Str: "Record", ConstVal: InfoType::IT_record);
62 IO.enumCase(Val&: Value, Str: "Function", ConstVal: InfoType::IT_function);
63 IO.enumCase(Val&: Value, Str: "Enum", ConstVal: InfoType::IT_enum);
64 IO.enumCase(Val&: Value, Str: "Default", ConstVal: InfoType::IT_default);
65 }
66};
67
68template <> struct ScalarEnumerationTraits<clang::doc::CommentKind> {
69 static void enumeration(IO &IO, clang::doc::CommentKind &Value) {
70 IO.enumCase(Val&: Value, Str: "FullComment", ConstVal: clang::doc::CommentKind::CK_FullComment);
71 IO.enumCase(Val&: Value, Str: "ParagraphComment",
72 ConstVal: clang::doc::CommentKind::CK_ParagraphComment);
73 IO.enumCase(Val&: Value, Str: "TextComment", ConstVal: clang::doc::CommentKind::CK_TextComment);
74 IO.enumCase(Val&: Value, Str: "InlineCommandComment",
75 ConstVal: clang::doc::CommentKind::CK_InlineCommandComment);
76 IO.enumCase(Val&: Value, Str: "HTMLStartTagComment",
77 ConstVal: clang::doc::CommentKind::CK_HTMLStartTagComment);
78 IO.enumCase(Val&: Value, Str: "HTMLEndTagComment",
79 ConstVal: clang::doc::CommentKind::CK_HTMLEndTagComment);
80 IO.enumCase(Val&: Value, Str: "BlockCommandComment",
81 ConstVal: clang::doc::CommentKind::CK_BlockCommandComment);
82 IO.enumCase(Val&: Value, Str: "ParamCommandComment",
83 ConstVal: clang::doc::CommentKind::CK_ParamCommandComment);
84 IO.enumCase(Val&: Value, Str: "TParamCommandComment",
85 ConstVal: clang::doc::CommentKind::CK_TParamCommandComment);
86 IO.enumCase(Val&: Value, Str: "VerbatimBlockComment",
87 ConstVal: clang::doc::CommentKind::CK_VerbatimBlockComment);
88 IO.enumCase(Val&: Value, Str: "VerbatimBlockLineComment",
89 ConstVal: clang::doc::CommentKind::CK_VerbatimBlockLineComment);
90 IO.enumCase(Val&: Value, Str: "VerbatimLineComment",
91 ConstVal: clang::doc::CommentKind::CK_VerbatimLineComment);
92 IO.enumCase(Val&: Value, Str: "Unknown", ConstVal: clang::doc::CommentKind::CK_Unknown);
93 }
94};
95
96// Scalars to YAML output.
97template <unsigned U> struct ScalarTraits<SmallString<U>> {
98
99 static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
100 for (const auto &C : S)
101 OS << C;
102 }
103
104 static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
105 Value.assign(Scalar.begin(), Scalar.end());
106 return StringRef();
107 }
108
109 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
110};
111
112template <> struct ScalarTraits<std::array<unsigned char, 20>> {
113
114 static void output(const std::array<unsigned char, 20> &S, void *,
115 llvm::raw_ostream &OS) {
116 OS << toHex(Input: toStringRef(Input: S));
117 }
118
119 static StringRef input(StringRef Scalar, void *,
120 std::array<unsigned char, 20> &Value) {
121 if (Scalar.size() != 40)
122 return "Error: Incorrect scalar size for USR.";
123 Value = stringToSymbol(Value: Scalar);
124 return StringRef();
125 }
126
127 static SymbolID stringToSymbol(llvm::StringRef Value) {
128 SymbolID USR;
129 std::string HexString = fromHex(Input: Value);
130 std::copy(first: HexString.begin(), last: HexString.end(), result: USR.begin());
131 return SymbolID(USR);
132 }
133
134 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
135};
136
137// Helper functions to map infos to YAML.
138
139static void typeInfoMapping(IO &IO, TypeInfo &I) {
140 IO.mapOptional(Key: "Type", Val&: I.Type, Default: Reference());
141}
142
143static void fieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
144 typeInfoMapping(IO, I);
145 IO.mapOptional(Key: "Name", Val&: I.Name, Default: SmallString<16>());
146 IO.mapOptional(Key: "DefaultValue", Val&: I.DefaultValue, Default: SmallString<16>());
147}
148
149static void infoMapping(IO &IO, Info &I) {
150 IO.mapRequired(Key: "USR", Val&: I.USR);
151 IO.mapOptional(Key: "Name", Val&: I.Name, Default: SmallString<16>());
152 IO.mapOptional(Key: "Path", Val&: I.Path, Default: SmallString<128>());
153 IO.mapOptional(Key: "Namespace", Val&: I.Namespace, Default: llvm::SmallVector<Reference, 4>());
154 IO.mapOptional(Key: "Description", Val&: I.Description);
155}
156
157static void symbolInfoMapping(IO &IO, SymbolInfo &I) {
158 infoMapping(IO, I);
159 IO.mapOptional(Key: "DefLocation", Val&: I.DefLoc, Default: std::optional<Location>());
160 IO.mapOptional(Key: "Location", Val&: I.Loc, Default: llvm::SmallVector<Location, 2>());
161}
162
163static void recordInfoMapping(IO &IO, RecordInfo &I) {
164 symbolInfoMapping(IO, I);
165 IO.mapOptional(Key: "TagType", Val&: I.TagType);
166 IO.mapOptional(Key: "IsTypeDef", Val&: I.IsTypeDef, Default: false);
167 IO.mapOptional(Key: "Members", Val&: I.Members);
168 IO.mapOptional(Key: "Bases", Val&: I.Bases);
169 IO.mapOptional(Key: "Parents", Val&: I.Parents, Default: llvm::SmallVector<Reference, 4>());
170 IO.mapOptional(Key: "VirtualParents", Val&: I.VirtualParents,
171 Default: llvm::SmallVector<Reference, 4>());
172 IO.mapOptional(Key: "ChildRecords", Val&: I.Children.Records, Default: std::vector<Reference>());
173 IO.mapOptional(Key: "ChildFunctions", Val&: I.Children.Functions);
174 IO.mapOptional(Key: "ChildEnums", Val&: I.Children.Enums);
175 IO.mapOptional(Key: "ChildTypedefs", Val&: I.Children.Typedefs);
176 IO.mapOptional(Key: "Template", Val&: I.Template);
177}
178
179static void commentInfoMapping(IO &IO, CommentInfo &I) {
180 IO.mapOptional(Key: "Kind", Val&: I.Kind, Default: CommentKind::CK_Unknown);
181 IO.mapOptional(Key: "Text", Val&: I.Text, Default: SmallString<64>());
182 IO.mapOptional(Key: "Name", Val&: I.Name, Default: SmallString<16>());
183 IO.mapOptional(Key: "Direction", Val&: I.Direction, Default: SmallString<8>());
184 IO.mapOptional(Key: "ParamName", Val&: I.ParamName, Default: SmallString<16>());
185 IO.mapOptional(Key: "CloseName", Val&: I.CloseName, Default: SmallString<16>());
186 IO.mapOptional(Key: "SelfClosing", Val&: I.SelfClosing, Default: false);
187 IO.mapOptional(Key: "Explicit", Val&: I.Explicit, Default: false);
188 IO.mapOptional(Key: "Args", Val&: I.Args, Default: llvm::SmallVector<SmallString<16>, 4>());
189 IO.mapOptional(Key: "AttrKeys", Val&: I.AttrKeys,
190 Default: llvm::SmallVector<SmallString<16>, 4>());
191 IO.mapOptional(Key: "AttrValues", Val&: I.AttrValues,
192 Default: llvm::SmallVector<SmallString<16>, 4>());
193 IO.mapOptional(Key: "Children", Val&: I.Children);
194}
195
196// Template specialization to YAML traits for Infos.
197
198template <> struct MappingTraits<Location> {
199 static void mapping(IO &IO, Location &Loc) {
200 IO.mapOptional(Key: "LineNumber", Val&: Loc.StartLineNumber, Default: 0);
201 IO.mapOptional(Key: "Filename", Val&: Loc.Filename, Default: SmallString<32>());
202 }
203};
204
205template <> struct MappingTraits<Reference> {
206 static void mapping(IO &IO, Reference &Ref) {
207 IO.mapOptional(Key: "Type", Val&: Ref.RefType, Default: InfoType::IT_default);
208 IO.mapOptional(Key: "Name", Val&: Ref.Name, Default: SmallString<16>());
209 IO.mapOptional(Key: "QualName", Val&: Ref.QualName, Default: SmallString<16>());
210 IO.mapOptional(Key: "USR", Val&: Ref.USR, Default: SymbolID());
211 IO.mapOptional(Key: "Path", Val&: Ref.Path, Default: SmallString<128>());
212 }
213};
214
215template <> struct MappingTraits<TypeInfo> {
216 static void mapping(IO &IO, TypeInfo &I) { typeInfoMapping(IO, I); }
217};
218
219template <> struct MappingTraits<FieldTypeInfo> {
220 static void mapping(IO &IO, FieldTypeInfo &I) {
221 typeInfoMapping(IO, I);
222 IO.mapOptional(Key: "Name", Val&: I.Name, Default: SmallString<16>());
223 IO.mapOptional(Key: "DefaultValue", Val&: I.DefaultValue, Default: SmallString<16>());
224 }
225};
226
227template <> struct MappingTraits<MemberTypeInfo> {
228 static void mapping(IO &IO, MemberTypeInfo &I) {
229 fieldTypeInfoMapping(IO, I);
230 // clang::AccessSpecifier::AS_none is used as the default here because it's
231 // the AS that shouldn't be part of the output. Even though AS_public is the
232 // default in the struct, it should be displayed in the YAML output.
233 IO.mapOptional(Key: "Access", Val&: I.Access, Default: clang::AccessSpecifier::AS_none);
234 IO.mapOptional(Key: "Description", Val&: I.Description);
235 }
236};
237
238template <> struct MappingTraits<NamespaceInfo> {
239 static void mapping(IO &IO, NamespaceInfo &I) {
240 infoMapping(IO, I);
241 IO.mapOptional(Key: "ChildNamespaces", Val&: I.Children.Namespaces,
242 Default: std::vector<Reference>());
243 IO.mapOptional(Key: "ChildRecords", Val&: I.Children.Records,
244 Default: std::vector<Reference>());
245 IO.mapOptional(Key: "ChildFunctions", Val&: I.Children.Functions);
246 IO.mapOptional(Key: "ChildEnums", Val&: I.Children.Enums);
247 IO.mapOptional(Key: "ChildTypedefs", Val&: I.Children.Typedefs);
248 }
249};
250
251template <> struct MappingTraits<RecordInfo> {
252 static void mapping(IO &IO, RecordInfo &I) { recordInfoMapping(IO, I); }
253};
254
255template <> struct MappingTraits<BaseRecordInfo> {
256 static void mapping(IO &IO, BaseRecordInfo &I) {
257 recordInfoMapping(IO, I);
258 IO.mapOptional(Key: "IsVirtual", Val&: I.IsVirtual, Default: false);
259 // clang::AccessSpecifier::AS_none is used as the default here because it's
260 // the AS that shouldn't be part of the output. Even though AS_public is the
261 // default in the struct, it should be displayed in the YAML output.
262 IO.mapOptional(Key: "Access", Val&: I.Access, Default: clang::AccessSpecifier::AS_none);
263 IO.mapOptional(Key: "IsParent", Val&: I.IsParent, Default: false);
264 }
265};
266
267template <> struct MappingTraits<EnumValueInfo> {
268 static void mapping(IO &IO, EnumValueInfo &I) {
269 IO.mapOptional(Key: "Name", Val&: I.Name);
270 IO.mapOptional(Key: "Value", Val&: I.Value);
271 IO.mapOptional(Key: "Expr", Val&: I.ValueExpr, Default: SmallString<16>());
272 }
273};
274
275template <> struct MappingTraits<EnumInfo> {
276 static void mapping(IO &IO, EnumInfo &I) {
277 symbolInfoMapping(IO, I);
278 IO.mapOptional(Key: "Scoped", Val&: I.Scoped, Default: false);
279 IO.mapOptional(Key: "BaseType", Val&: I.BaseType);
280 IO.mapOptional(Key: "Members", Val&: I.Members);
281 }
282};
283
284template <> struct MappingTraits<TypedefInfo> {
285 static void mapping(IO &IO, TypedefInfo &I) {
286 symbolInfoMapping(IO, I);
287 IO.mapOptional(Key: "Underlying", Val&: I.Underlying.Type);
288 IO.mapOptional(Key: "IsUsing", Val&: I.IsUsing, Default: false);
289 }
290};
291
292template <> struct MappingTraits<FunctionInfo> {
293 static void mapping(IO &IO, FunctionInfo &I) {
294 symbolInfoMapping(IO, I);
295 IO.mapOptional(Key: "IsMethod", Val&: I.IsMethod, Default: false);
296 IO.mapOptional(Key: "Parent", Val&: I.Parent, Default: Reference());
297 IO.mapOptional(Key: "Params", Val&: I.Params);
298 IO.mapOptional(Key: "ReturnType", Val&: I.ReturnType);
299 // clang::AccessSpecifier::AS_none is used as the default here because it's
300 // the AS that shouldn't be part of the output. Even though AS_public is the
301 // default in the struct, it should be displayed in the YAML output.
302 IO.mapOptional(Key: "Access", Val&: I.Access, Default: clang::AccessSpecifier::AS_none);
303 IO.mapOptional(Key: "Template", Val&: I.Template);
304 }
305};
306
307template <> struct MappingTraits<TemplateParamInfo> {
308 static void mapping(IO &IO, TemplateParamInfo &I) {
309 IO.mapOptional(Key: "Contents", Val&: I.Contents);
310 }
311};
312
313template <> struct MappingTraits<TemplateSpecializationInfo> {
314 static void mapping(IO &IO, TemplateSpecializationInfo &I) {
315 IO.mapOptional(Key: "SpecializationOf", Val&: I.SpecializationOf);
316 IO.mapOptional(Key: "Params", Val&: I.Params);
317 }
318};
319
320template <> struct MappingTraits<TemplateInfo> {
321 static void mapping(IO &IO, TemplateInfo &I) {
322 IO.mapOptional(Key: "Params", Val&: I.Params);
323 IO.mapOptional(Key: "Specialization", Val&: I.Specialization,
324 Default: std::optional<TemplateSpecializationInfo>());
325 }
326};
327
328template <> struct MappingTraits<CommentInfo> {
329 static void mapping(IO &IO, CommentInfo &I) { commentInfoMapping(IO, I); }
330};
331
332template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
333 static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) {
334 if (I)
335 commentInfoMapping(IO, I&: *I);
336 }
337};
338
339} // end namespace yaml
340} // end namespace llvm
341
342namespace clang {
343namespace doc {
344
345/// Generator for YAML documentation.
346class YAMLGenerator : public Generator {
347public:
348 static const char *Format;
349
350 llvm::Error generateDocs(StringRef RootDir,
351 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
352 const ClangDocContext &CDCtx) override;
353 llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
354 const ClangDocContext &CDCtx) override;
355};
356
357const char *YAMLGenerator::Format = "yaml";
358
359llvm::Error
360YAMLGenerator::generateDocs(StringRef RootDir,
361 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
362 const ClangDocContext &CDCtx) {
363 for (const auto &Group : Infos) {
364 doc::Info *Info = Group.getValue().get();
365
366 // Output file names according to the USR except the global namesapce.
367 // Anonymous namespaces are taken care of in serialization, so here we can
368 // safely assume an unnamed namespace is the global one.
369 llvm::SmallString<128> Path;
370 llvm::sys::path::native(path: RootDir, result&: Path);
371 if (Info->IT == InfoType::IT_namespace && Info->Name.empty()) {
372 llvm::sys::path::append(path&: Path, a: "index.yaml");
373 } else {
374 llvm::sys::path::append(path&: Path, a: Group.getKey() + ".yaml");
375 }
376
377 std::error_code FileErr;
378 llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_Text);
379 if (FileErr) {
380 return llvm::createStringError(EC: FileErr, Fmt: "Error opening file '%s'",
381 Vals: Path.c_str());
382 }
383
384 if (llvm::Error Err = generateDocForInfo(I: Info, OS&: InfoOS, CDCtx)) {
385 return Err;
386 }
387 }
388
389 return llvm::Error::success();
390}
391
392llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
393 const ClangDocContext &CDCtx) {
394 llvm::yaml::Output InfoYAML(OS);
395 switch (I->IT) {
396 case InfoType::IT_namespace:
397 InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
398 break;
399 case InfoType::IT_record:
400 InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
401 break;
402 case InfoType::IT_enum:
403 InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
404 break;
405 case InfoType::IT_function:
406 InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
407 break;
408 case InfoType::IT_typedef:
409 InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);
410 break;
411 case InfoType::IT_default:
412 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
413 S: "unexpected InfoType");
414 }
415 return llvm::Error::success();
416}
417
418static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
419 "Generator for YAML output.");
420
421// This anchor is used to force the linker to link in the generated object file
422// and thus register the generator.
423volatile int YAMLGeneratorAnchorSource = 0;
424
425} // namespace doc
426} // namespace clang
427

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang-tools-extra/clang-doc/YAMLGenerator.cpp