clang-tools 23.0.0git
YAMLGenerator.cpp
Go to the documentation of this file.
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(OwnedPtr<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(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);
45 }
46};
47
48template <> struct ScalarEnumerationTraits<clang::TagTypeKind> {
49 static void enumeration(IO &IO, clang::TagTypeKind &Value) {
50 IO.enumCase(Value, "Struct", clang::TagTypeKind::Struct);
51 IO.enumCase(Value, "Interface", clang::TagTypeKind::Interface);
52 IO.enumCase(Value, "Union", clang::TagTypeKind::Union);
53 IO.enumCase(Value, "Class", clang::TagTypeKind::Class);
54 IO.enumCase(Value, "Enum", clang::TagTypeKind::Enum);
55 }
56};
57
58template <> 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);
65 }
66};
67
68template <> struct ScalarEnumerationTraits<clang::doc::CommentKind> {
69 static void enumeration(IO &IO, clang::doc::CommentKind &Value) {
70 IO.enumCase(Value, "FullComment", clang::doc::CommentKind::CK_FullComment);
71 IO.enumCase(Value, "ParagraphComment",
73 IO.enumCase(Value, "TextComment", clang::doc::CommentKind::CK_TextComment);
74 IO.enumCase(Value, "InlineCommandComment",
76 IO.enumCase(Value, "HTMLStartTagComment",
78 IO.enumCase(Value, "HTMLEndTagComment",
80 IO.enumCase(Value, "BlockCommandComment",
82 IO.enumCase(Value, "ParamCommandComment",
84 IO.enumCase(Value, "TParamCommandComment",
86 IO.enumCase(Value, "VerbatimBlockComment",
88 IO.enumCase(Value, "VerbatimBlockLineComment",
90 IO.enumCase(Value, "VerbatimLineComment",
92 IO.enumCase(Value, "Unknown", 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<SymbolID> {
113
114 static void output(const SymbolID &S, void *, llvm::raw_ostream &OS) {
115 OS << toHex(toStringRef(S));
116 }
117
118 static StringRef input(StringRef Scalar, void *, SymbolID &Value) {
119 if (Scalar.size() != 40)
120 return "Error: Incorrect scalar size for USR.";
121 Value = stringToSymbol(Scalar);
122 return StringRef();
123 }
124
125 static SymbolID stringToSymbol(llvm::StringRef Value) {
126 SymbolID USR;
127 std::string HexString = fromHex(Value);
128 std::copy(HexString.begin(), HexString.end(), USR.begin());
129 return SymbolID(USR);
130 }
131
132 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
133};
134
135// Helper functions to map infos to YAML.
136
137static void typeInfoMapping(IO &IO, TypeInfo &I) {
138 IO.mapOptional("Type", I.Type, Reference());
139}
140
141static void fieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
142 typeInfoMapping(IO, I);
143 IO.mapOptional("Name", I.Name, SmallString<16>());
144 IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());
145}
146
147static void infoMapping(IO &IO, Info &I) {
148 IO.mapRequired("USR", I.USR);
149 IO.mapOptional("Name", I.Name, SmallString<16>());
150 IO.mapOptional("Path", I.Path, SmallString<128>());
151 IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
152 IO.mapOptional("Description", I.Description);
153}
154
155static void symbolInfoMapping(IO &IO, SymbolInfo &I) {
156 infoMapping(IO, I);
157 IO.mapOptional("DefLocation", I.DefLoc, std::optional<Location>());
158 IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
159}
160
161static void recordInfoMapping(IO &IO, RecordInfo &I) {
162 symbolInfoMapping(IO, I);
163 IO.mapOptional("TagType", I.TagType);
164 IO.mapOptional("IsTypeDef", I.IsTypeDef, false);
165 IO.mapOptional("Members", I.Members);
166 IO.mapOptional("Bases", I.Bases);
167 IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
168 IO.mapOptional("VirtualParents", I.VirtualParents,
169 llvm::SmallVector<Reference, 4>());
170 IO.mapOptional("ChildRecords", I.Children.Records, OwningVec<Reference>());
171 IO.mapOptional("ChildFunctions", I.Children.Functions);
172 IO.mapOptional("ChildEnums", I.Children.Enums);
173 IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
174 IO.mapOptional("Template", I.Template);
175}
176
177static void commentInfoMapping(IO &IO, CommentInfo &I) {
178 IO.mapOptional("Kind", I.Kind, CommentKind::CK_Unknown);
179 IO.mapOptional("Text", I.Text, SmallString<64>());
180 IO.mapOptional("Name", I.Name, SmallString<16>());
181 IO.mapOptional("Direction", I.Direction, SmallString<8>());
182 IO.mapOptional("ParamName", I.ParamName, SmallString<16>());
183 IO.mapOptional("CloseName", I.CloseName, SmallString<16>());
184 IO.mapOptional("SelfClosing", I.SelfClosing, false);
185 IO.mapOptional("Explicit", I.Explicit, false);
186 IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>());
187 IO.mapOptional("AttrKeys", I.AttrKeys,
188 llvm::SmallVector<SmallString<16>, 4>());
189 IO.mapOptional("AttrValues", I.AttrValues,
190 llvm::SmallVector<SmallString<16>, 4>());
191 IO.mapOptional("Children", I.Children);
192}
193
194// Template specialization to YAML traits for Infos.
195
196template <> struct MappingTraits<Location> {
197 static void mapping(IO &IO, Location &Loc) {
198 IO.mapOptional("LineNumber", Loc.StartLineNumber, 0);
199 IO.mapOptional("Filename", Loc.Filename, SmallString<32>());
200 }
201};
202
203template <> struct MappingTraits<Reference> {
204 static void mapping(IO &IO, Reference &Ref) {
205 IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
206 IO.mapOptional("Name", Ref.Name, SmallString<16>());
207 IO.mapOptional("QualName", Ref.QualName, SmallString<16>());
208 IO.mapOptional("USR", Ref.USR, SymbolID());
209 IO.mapOptional("Path", Ref.Path, SmallString<128>());
210 }
211};
212
213template <> struct MappingTraits<TypeInfo> {
214 static void mapping(IO &IO, TypeInfo &I) { typeInfoMapping(IO, I); }
215};
216
217template <> struct MappingTraits<FieldTypeInfo> {
218 static void mapping(IO &IO, FieldTypeInfo &I) {
219 typeInfoMapping(IO, I);
220 IO.mapOptional("Name", I.Name, SmallString<16>());
221 IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());
222 }
223};
224
225template <> struct MappingTraits<MemberTypeInfo> {
226 static void mapping(IO &IO, MemberTypeInfo &I) {
228 // clang::AccessSpecifier::AS_none is used as the default here because it's
229 // the AS that shouldn't be part of the output. Even though AS_public is the
230 // default in the struct, it should be displayed in the YAML output.
231 IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
232 IO.mapOptional("Description", I.Description);
233 }
234};
235
236template <> struct MappingTraits<NamespaceInfo> {
237 static void mapping(IO &IO, NamespaceInfo &I) {
238 infoMapping(IO, I);
239 IO.mapOptional("ChildNamespaces", I.Children.Namespaces,
241 IO.mapOptional("ChildRecords", I.Children.Records, OwningVec<Reference>());
242 IO.mapOptional("ChildFunctions", I.Children.Functions);
243 IO.mapOptional("ChildEnums", I.Children.Enums);
244 IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
245 }
246};
247
248template <> struct MappingTraits<RecordInfo> {
249 static void mapping(IO &IO, RecordInfo &I) { recordInfoMapping(IO, I); }
250};
251
252template <> struct MappingTraits<BaseRecordInfo> {
253 static void mapping(IO &IO, BaseRecordInfo &I) {
254 recordInfoMapping(IO, I);
255 IO.mapOptional("IsVirtual", I.IsVirtual, false);
256 // clang::AccessSpecifier::AS_none is used as the default here because it's
257 // the AS that shouldn't be part of the output. Even though AS_public is the
258 // default in the struct, it should be displayed in the YAML output.
259 IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
260 IO.mapOptional("IsParent", I.IsParent, false);
261 }
262};
263
264template <> struct MappingTraits<EnumValueInfo> {
265 static void mapping(IO &IO, EnumValueInfo &I) {
266 IO.mapOptional("Name", I.Name);
267 IO.mapOptional("Value", I.Value);
268 IO.mapOptional("Expr", I.ValueExpr, SmallString<16>());
269 }
270};
271
272template <> struct MappingTraits<EnumInfo> {
273 static void mapping(IO &IO, EnumInfo &I) {
274 symbolInfoMapping(IO, I);
275 IO.mapOptional("Scoped", I.Scoped, false);
276 IO.mapOptional("BaseType", I.BaseType);
277 IO.mapOptional("Members", I.Members);
278 }
279};
280
281template <> struct MappingTraits<TypedefInfo> {
282 static void mapping(IO &IO, TypedefInfo &I) {
283 symbolInfoMapping(IO, I);
284 IO.mapOptional("Underlying", I.Underlying.Type);
285 IO.mapOptional("IsUsing", I.IsUsing, false);
286 }
287};
288
289template <> struct MappingTraits<FunctionInfo> {
290 static void mapping(IO &IO, FunctionInfo &I) {
291 symbolInfoMapping(IO, I);
292 IO.mapOptional("IsMethod", I.IsMethod, false);
293 IO.mapOptional("Parent", I.Parent, Reference());
294 IO.mapOptional("Params", I.Params);
295 IO.mapOptional("ReturnType", I.ReturnType);
296 // clang::AccessSpecifier::AS_none is used as the default here because it's
297 // the AS that shouldn't be part of the output. Even though AS_public is the
298 // default in the struct, it should be displayed in the YAML output.
299 IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
300 IO.mapOptional("Template", I.Template);
301 }
302};
303
304template <> struct MappingTraits<TemplateParamInfo> {
305 static void mapping(IO &IO, TemplateParamInfo &I) {
306 IO.mapOptional("Contents", I.Contents);
307 }
308};
309
310template <> struct MappingTraits<TemplateSpecializationInfo> {
311 static void mapping(IO &IO, TemplateSpecializationInfo &I) {
312 IO.mapOptional("SpecializationOf", I.SpecializationOf);
313 IO.mapOptional("Params", I.Params);
314 }
315};
316
317template <> struct MappingTraits<TemplateInfo> {
318 static void mapping(IO &IO, TemplateInfo &I) {
319 IO.mapOptional("Params", I.Params);
320 IO.mapOptional("Specialization", I.Specialization,
321 std::optional<TemplateSpecializationInfo>());
322 }
323};
324
325template <> struct MappingTraits<CommentInfo> {
326 static void mapping(IO &IO, CommentInfo &I) { commentInfoMapping(IO, I); }
327};
328
329template <> struct MappingTraits<OwnedPtr<CommentInfo>> {
330 static void mapping(IO &IO, OwnedPtr<CommentInfo> &I) {
331 if (I)
332 commentInfoMapping(IO, *I);
333 }
334};
335
336} // end namespace yaml
337} // end namespace llvm
338
339namespace clang {
340namespace doc {
341
342/// Generator for YAML documentation.
343class YAMLGenerator : public Generator {
344public:
345 static const char *Format;
346
347 llvm::Error generateDocumentation(
348 StringRef RootDir, llvm::StringMap<doc::OwnedPtr<doc::Info>> Infos,
349 const ClangDocContext &CDCtx, std::string DirName) override;
350 llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
351 const ClangDocContext &CDCtx) override;
352};
353
354const char *YAMLGenerator::Format = "yaml";
355
357 StringRef RootDir, llvm::StringMap<doc::OwnedPtr<doc::Info>> Infos,
358 const ClangDocContext &CDCtx, std::string DirName) {
359 for (const auto &Group : Infos) {
360 doc::Info *Info = getPtr(Group.getValue());
361
362 // Output file names according to the USR except the global namesapce.
363 // Anonymous namespaces are taken care of in serialization, so here we can
364 // safely assume an unnamed namespace is the global one.
365 llvm::SmallString<128> Path;
366 llvm::sys::path::native(RootDir, Path);
367 if (Info->IT == InfoType::IT_namespace && Info->Name.empty()) {
368 llvm::sys::path::append(Path, "index.yaml");
369 } else {
370 llvm::sys::path::append(Path, Group.getKey() + ".yaml");
371 }
372
373 std::error_code FileErr;
374 llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_Text);
375 if (FileErr) {
376 return llvm::createStringError(FileErr, "Error opening file '%s'",
377 Path.c_str());
378 }
379
380 if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
381 return Err;
382 }
383 }
384
385 return llvm::Error::success();
386}
387
388llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
389 const ClangDocContext &CDCtx) {
390 llvm::yaml::Output InfoYAML(OS);
391 switch (I->IT) {
393 InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
394 break;
396 InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
397 break;
399 InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
400 break;
402 InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
403 break;
405 InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);
406 break;
410 break;
412 return llvm::createStringError(llvm::inconvertibleErrorCode(),
413 "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.
424
425} // namespace doc
426} // namespace clang
Generator for YAML documentation.
llvm::Error generateDocumentation(StringRef RootDir, llvm::StringMap< doc::OwnedPtr< doc::Info > > Infos, const ClangDocContext &CDCtx, std::string DirName) override
static const char * Format
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override
std::unique_ptr< T > OwnedPtr
T * getPtr(const OwnedPtr< T > &O)
static GeneratorRegistry::Add< YAMLGenerator > YAML(YAMLGenerator::Format, "Generator for YAML output.")
volatile int YAMLGeneratorAnchorSource
std::vector< T > OwningVec
std::array< uint8_t, 20 > SymbolID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static void infoMapping(IO &IO, Info &I)
static void commentInfoMapping(IO &IO, CommentInfo &I)
static void fieldTypeInfoMapping(IO &IO, FieldTypeInfo &I)
static void symbolInfoMapping(IO &IO, SymbolInfo &I)
static void typeInfoMapping(IO &IO, TypeInfo &I)
static void recordInfoMapping(IO &IO, RecordInfo &I)
Some operations such as code completion produce a set of candidates.
Definition Generators.h:150
Represents a symbol occurrence in the source file.
Definition Ref.h:88
SmallString< 8 > Direction
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
SmallString< 16 > CloseName
SmallString< 16 > Name
SmallString< 64 > Text
OwningPtrVec< CommentInfo > Children
llvm::SmallVector< SmallString< 16 >, 4 > AttrKeys
llvm::SmallVector< SmallString< 16 >, 4 > Args
SmallString< 16 > ParamName
llvm::SmallVector< EnumValueInfo, 4 > Members
std::optional< TypeInfo > BaseType
SmallString< 16 > ValueExpr
SmallString< 16 > DefaultValue
llvm::SmallVector< FieldTypeInfo, 4 > Params
std::optional< TemplateInfo > Template
A base struct for Infos.
OwningVec< CommentInfo > Description
SmallString< 16 > Name
llvm::SmallString< 128 > Path
llvm::SmallVector< Reference, 4 > Namespace
SmallString< 32 > Filename
OwningVec< CommentInfo > Description
OwningVec< BaseRecordInfo > Bases
llvm::SmallVector< MemberTypeInfo, 4 > Members
std::optional< TemplateInfo > Template
llvm::SmallVector< Reference, 4 > VirtualParents
llvm::SmallVector< Reference, 4 > Parents
OwningVec< FunctionInfo > Functions
OwningVec< TypedefInfo > Typedefs
OwningVec< EnumInfo > Enums
OwningVec< Reference > Records
OwningVec< Reference > Namespaces
llvm::SmallVector< Location, 2 > Loc
std::optional< Location > DefLoc
OwningVec< TemplateParamInfo > Params
std::optional< TemplateSpecializationInfo > Specialization
OwningVec< TemplateParamInfo > Params
static void mapping(IO &IO, BaseRecordInfo &I)
static void mapping(IO &IO, CommentInfo &I)
static void mapping(IO &IO, EnumInfo &I)
static void mapping(IO &IO, EnumValueInfo &I)
static void mapping(IO &IO, FieldTypeInfo &I)
static void mapping(IO &IO, FunctionInfo &I)
static void mapping(IO &IO, Location &Loc)
static void mapping(IO &IO, MemberTypeInfo &I)
static void mapping(IO &IO, NamespaceInfo &I)
static void mapping(IO &IO, OwnedPtr< CommentInfo > &I)
static void mapping(IO &IO, RecordInfo &I)
static void mapping(IO &IO, Reference &Ref)
static void mapping(IO &IO, TemplateInfo &I)
static void mapping(IO &IO, TemplateParamInfo &I)
static void mapping(IO &IO, TemplateSpecializationInfo &I)
static void mapping(IO &IO, TypeInfo &I)
static void mapping(IO &IO, TypedefInfo &I)
static void enumeration(IO &IO, InfoType &Value)
static void enumeration(IO &IO, clang::AccessSpecifier &Value)
static void enumeration(IO &IO, clang::TagTypeKind &Value)
static void enumeration(IO &IO, clang::doc::CommentKind &Value)
static void output(const SmallString< U > &S, void *, llvm::raw_ostream &OS)
static StringRef input(StringRef Scalar, void *, SmallString< U > &Value)
static SymbolID stringToSymbol(llvm::StringRef Value)
static StringRef input(StringRef Scalar, void *, SymbolID &Value)
static void output(const SymbolID &S, void *, llvm::raw_ostream &OS)
static QuotingType mustQuote(StringRef)