clang-tools 19.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(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(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
68// Scalars to YAML output.
69template <unsigned U> struct ScalarTraits<SmallString<U>> {
70
71 static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
72 for (const auto &C : S)
73 OS << C;
74 }
75
76 static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
77 Value.assign(Scalar.begin(), Scalar.end());
78 return StringRef();
79 }
80
81 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
82};
83
84template <> struct ScalarTraits<std::array<unsigned char, 20>> {
85
86 static void output(const std::array<unsigned char, 20> &S, void *,
87 llvm::raw_ostream &OS) {
88 OS << toHex(toStringRef(S));
89 }
90
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);
96 return StringRef();
97 }
98
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);
104 }
105
106 static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
107};
108
109// Helper functions to map infos to YAML.
110
111static void TypeInfoMapping(IO &IO, TypeInfo &I) {
112 IO.mapOptional("Type", I.Type, Reference());
113}
114
115static 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>());
119}
120
121static 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);
127}
128
129static void SymbolInfoMapping(IO &IO, SymbolInfo &I) {
130 InfoMapping(IO, I);
131 IO.mapOptional("DefLocation", I.DefLoc, std::optional<Location>());
132 IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
133}
134
135static 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);
149}
150
151static 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);
166}
167
168// Template specialization to YAML traits for Infos.
169
170template <> 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>());
174 }
175};
176
177template <> 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>());
184 }
185};
186
187template <> struct MappingTraits<TypeInfo> {
188 static void mapping(IO &IO, TypeInfo &I) { TypeInfoMapping(IO, I); }
189};
190
191template <> 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>());
196 }
197};
198
199template <> struct MappingTraits<MemberTypeInfo> {
200 static void mapping(IO &IO, MemberTypeInfo &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);
207 }
208};
209
210template <> struct MappingTraits<NamespaceInfo> {
211 static void mapping(IO &IO, NamespaceInfo &I) {
212 InfoMapping(IO, 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);
220 }
221};
222
223template <> struct MappingTraits<RecordInfo> {
224 static void mapping(IO &IO, RecordInfo &I) { RecordInfoMapping(IO, I); }
225};
226
227template <> 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);
236 }
237};
238
239template <> 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>());
244 }
245};
246
247template <> 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);
253 }
254};
255
256template <> 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);
261 }
262};
263
264template <> 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);
276 }
277};
278
279template <> struct MappingTraits<TemplateParamInfo> {
280 static void mapping(IO &IO, TemplateParamInfo &I) {
281 IO.mapOptional("Contents", I.Contents);
282 }
283};
284
285template <> struct MappingTraits<TemplateSpecializationInfo> {
286 static void mapping(IO &IO, TemplateSpecializationInfo &I) {
287 IO.mapOptional("SpecializationOf", I.SpecializationOf);
288 IO.mapOptional("Params", I.Params);
289 }
290};
291
292template <> 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>());
297 }
298};
299
300template <> struct MappingTraits<CommentInfo> {
301 static void mapping(IO &IO, CommentInfo &I) { CommentInfoMapping(IO, I); }
302};
303
304template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
305 static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) {
306 if (I)
307 CommentInfoMapping(IO, *I);
308 }
309};
310
311} // end namespace yaml
312} // end namespace llvm
313
314namespace clang {
315namespace doc {
316
317/// Generator for YAML documentation.
318class YAMLGenerator : public Generator {
319public:
320 static const char *Format;
321
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;
327};
328
329const char *YAMLGenerator::Format = "yaml";
330
331llvm::Error
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();
337
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");
345 } else {
346 llvm::sys::path::append(Path, Group.getKey() + ".yaml");
347 }
348
349 std::error_code FileErr;
350 llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_None);
351 if (FileErr) {
352 return llvm::createStringError(FileErr, "Error opening file '%s'",
353 Path.c_str());
354 }
355
356 if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
357 return Err;
358 }
359 }
360
361 return llvm::Error::success();
362}
363
364llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
365 const ClangDocContext &CDCtx) {
366 llvm::yaml::Output InfoYAML(OS);
367 switch (I->IT) {
369 InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
370 break;
372 InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
373 break;
375 InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
376 break;
378 InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
379 break;
381 InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);
382 break;
384 return llvm::createStringError(llvm::inconvertibleErrorCode(),
385 "unexpected InfoType");
386 }
387 return llvm::Error::success();
388}
389
390static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
391 "Generator for YAML output.");
392
393// This anchor is used to force the linker to link in the generated object file
394// and thus register the generator.
396
397} // namespace doc
398} // namespace clang
@ yaml
const Criteria C
SourceLocation Loc
std::vector< HeaderHandle > Path
std::string USR
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:160
Generator for YAML documentation.
llvm::Error generateDocs(StringRef RootDir, llvm::StringMap< std::unique_ptr< doc::Info > > Infos, const ClangDocContext &CDCtx) override
static const char * Format
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override
static GeneratorRegistry::Add< YAMLGenerator > YAML(YAMLGenerator::Format, "Generator for YAML output.")
volatile int YAMLGeneratorAnchorSource
std::array< uint8_t, 20 > SymbolID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static void TypeInfoMapping(IO &IO, TypeInfo &I)
static void SymbolInfoMapping(IO &IO, SymbolInfo &I)
static void RecordInfoMapping(IO &IO, RecordInfo &I)
static void InfoMapping(IO &IO, Info &I)
static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I)
static void CommentInfoMapping(IO &IO, CommentInfo &I)
Some operations such as code completion produce a set of candidates.
Represents a symbol occurrence in the source file.
Definition: Ref.h:85
SmallString< 8 > Direction
SmallString< 16 > Kind
std::vector< std::unique_ptr< CommentInfo > > Children
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
SmallString< 16 > CloseName
SmallString< 16 > Name
SmallString< 64 > Text
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 > Value
SmallString< 16 > Name
SmallString< 16 > ValueExpr
SmallString< 16 > Name
SmallString< 16 > DefaultValue
llvm::SmallVector< FieldTypeInfo, 4 > Params
std::optional< TemplateInfo > Template
A base struct for Infos.
SmallString< 16 > Name
std::vector< CommentInfo > Description
llvm::SmallString< 128 > Path
const InfoType IT
llvm::SmallVector< Reference, 4 > Namespace
std::vector< CommentInfo > Description
llvm::SmallVector< MemberTypeInfo, 4 > Members
std::optional< TemplateInfo > Template
llvm::SmallVector< Reference, 4 > VirtualParents
llvm::SmallVector< Reference, 4 > Parents
std::vector< BaseRecordInfo > Bases
std::vector< Reference > Records
std::vector< TypedefInfo > Typedefs
std::vector< FunctionInfo > Functions
std::vector< Reference > Namespaces
std::vector< EnumInfo > Enums
llvm::SmallVector< Location, 2 > Loc
std::optional< Location > DefLoc
std::vector< TemplateParamInfo > Params
std::optional< TemplateSpecializationInfo > Specialization
std::vector< 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, 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 mapping(IO &IO, std::unique_ptr< CommentInfo > &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 output(const SmallString< U > &S, void *, llvm::raw_ostream &OS)
static QuotingType mustQuote(StringRef)
static StringRef input(StringRef Scalar, void *, SmallString< U > &Value)
static SymbolID StringToSymbol(llvm::StringRef Value)
static StringRef input(StringRef Scalar, void *, std::array< unsigned char, 20 > &Value)
static void output(const std::array< unsigned char, 20 > &S, void *, llvm::raw_ostream &OS)