1 //===--  ClangDocYAML.cpp - ClangDoc YAML -----------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // Implementation of the YAML generator, converting decl info into YAML output.
10 //===----------------------------------------------------------------------===//
11 
12 #include "Generators.h"
13 #include "llvm/Support/YAMLTraits.h"
14 #include "llvm/Support/raw_ostream.h"
15 
16 using namespace clang::doc;
17 
18 LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo)
19 LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo)
20 LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
21 LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
22 LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
23 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
24 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
25 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
26 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
27 
28 namespace llvm {
29 namespace yaml {
30 
31 // Enumerations to YAML output.
32 
33 template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
enumerationllvm::yaml::ScalarEnumerationTraits34   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);
39   }
40 };
41 
42 template <> struct ScalarEnumerationTraits<clang::TagTypeKind> {
enumerationllvm::yaml::ScalarEnumerationTraits43   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);
49   }
50 };
51 
52 template <> struct ScalarEnumerationTraits<InfoType> {
enumerationllvm::yaml::ScalarEnumerationTraits53   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);
59   }
60 };
61 
62 // Scalars to YAML output.
63 template <unsigned U> struct ScalarTraits<SmallString<U>> {
64 
outputllvm::yaml::ScalarTraits65   static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
66     for (const auto &C : S)
67       OS << C;
68   }
69 
inputllvm::yaml::ScalarTraits70   static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
71     Value.assign(Scalar.begin(), Scalar.end());
72     return StringRef();
73   }
74 
mustQuotellvm::yaml::ScalarTraits75   static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
76 };
77 
78 template <> struct ScalarTraits<std::array<unsigned char, 20>> {
79 
outputllvm::yaml::ScalarTraits80   static void output(const std::array<unsigned char, 20> &S, void *,
81                      llvm::raw_ostream &OS) {
82     OS << toHex(toStringRef(S));
83   }
84 
inputllvm::yaml::ScalarTraits85   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);
90     return StringRef();
91   }
92 
StringToSymbolllvm::yaml::ScalarTraits93   static SymbolID StringToSymbol(llvm::StringRef Value) {
94     SymbolID USR;
95     std::string HexString = fromHex(Value);
96     std::copy(HexString.begin(), HexString.end(), USR.begin());
97     return SymbolID(USR);
98   }
99 
mustQuotellvm::yaml::ScalarTraits100   static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
101 };
102 
103 // Helper functions to map infos to YAML.
104 
TypeInfoMapping(IO & IO,TypeInfo & I)105 static void TypeInfoMapping(IO &IO, TypeInfo &I) {
106   IO.mapOptional("Type", I.Type, Reference());
107 }
108 
FieldTypeInfoMapping(IO & IO,FieldTypeInfo & I)109 static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
110   TypeInfoMapping(IO, I);
111   IO.mapOptional("Name", I.Name, SmallString<16>());
112 }
113 
InfoMapping(IO & IO,Info & I)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("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
118   IO.mapOptional("Description", I.Description);
119 }
120 
SymbolInfoMapping(IO & IO,SymbolInfo & I)121 static void SymbolInfoMapping(IO &IO, SymbolInfo &I) {
122   InfoMapping(IO, I);
123   IO.mapOptional("DefLocation", I.DefLoc, Optional<Location>());
124   IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
125 }
126 
CommentInfoMapping(IO & IO,CommentInfo & I)127 static void CommentInfoMapping(IO &IO, CommentInfo &I) {
128   IO.mapOptional("Kind", I.Kind, SmallString<16>());
129   IO.mapOptional("Text", I.Text, SmallString<64>());
130   IO.mapOptional("Name", I.Name, SmallString<16>());
131   IO.mapOptional("Direction", I.Direction, SmallString<8>());
132   IO.mapOptional("ParamName", I.ParamName, SmallString<16>());
133   IO.mapOptional("CloseName", I.CloseName, SmallString<16>());
134   IO.mapOptional("SelfClosing", I.SelfClosing, false);
135   IO.mapOptional("Explicit", I.Explicit, false);
136   IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>());
137   IO.mapOptional("AttrKeys", I.AttrKeys,
138                  llvm::SmallVector<SmallString<16>, 4>());
139   IO.mapOptional("AttrValues", I.AttrValues,
140                  llvm::SmallVector<SmallString<16>, 4>());
141   IO.mapOptional("Children", I.Children);
142 }
143 
144 // Template specialization to YAML traits for Infos.
145 
146 template <> struct MappingTraits<Location> {
mappingllvm::yaml::MappingTraits147   static void mapping(IO &IO, Location &Loc) {
148     IO.mapOptional("LineNumber", Loc.LineNumber, 0);
149     IO.mapOptional("Filename", Loc.Filename, SmallString<32>());
150   }
151 };
152 
153 template <> struct MappingTraits<Reference> {
mappingllvm::yaml::MappingTraits154   static void mapping(IO &IO, Reference &Ref) {
155     IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
156     IO.mapOptional("Name", Ref.Name, SmallString<16>());
157     IO.mapOptional("USR", Ref.USR, SymbolID());
158   }
159 };
160 
161 template <> struct MappingTraits<TypeInfo> {
mappingllvm::yaml::MappingTraits162   static void mapping(IO &IO, TypeInfo &I) { TypeInfoMapping(IO, I); }
163 };
164 
165 template <> struct MappingTraits<FieldTypeInfo> {
mappingllvm::yaml::MappingTraits166   static void mapping(IO &IO, FieldTypeInfo &I) {
167     TypeInfoMapping(IO, I);
168     IO.mapOptional("Name", I.Name, SmallString<16>());
169   }
170 };
171 
172 template <> struct MappingTraits<MemberTypeInfo> {
mappingllvm::yaml::MappingTraits173   static void mapping(IO &IO, MemberTypeInfo &I) {
174     FieldTypeInfoMapping(IO, I);
175     IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
176   }
177 };
178 
179 template <> struct MappingTraits<NamespaceInfo> {
mappingllvm::yaml::MappingTraits180   static void mapping(IO &IO, NamespaceInfo &I) {
181     InfoMapping(IO, I);
182     IO.mapOptional("ChildNamespaces", I.ChildNamespaces,
183                    std::vector<Reference>());
184     IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
185     IO.mapOptional("ChildFunctions", I.ChildFunctions);
186     IO.mapOptional("ChildEnums", I.ChildEnums);
187   }
188 };
189 
190 template <> struct MappingTraits<RecordInfo> {
mappingllvm::yaml::MappingTraits191   static void mapping(IO &IO, RecordInfo &I) {
192     SymbolInfoMapping(IO, I);
193     IO.mapOptional("TagType", I.TagType, clang::TagTypeKind::TTK_Struct);
194     IO.mapOptional("Members", I.Members);
195     IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
196     IO.mapOptional("VirtualParents", I.VirtualParents,
197                    llvm::SmallVector<Reference, 4>());
198     IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
199     IO.mapOptional("ChildFunctions", I.ChildFunctions);
200     IO.mapOptional("ChildEnums", I.ChildEnums);
201   }
202 };
203 
204 template <> struct MappingTraits<EnumInfo> {
mappingllvm::yaml::MappingTraits205   static void mapping(IO &IO, EnumInfo &I) {
206     SymbolInfoMapping(IO, I);
207     IO.mapOptional("Scoped", I.Scoped, false);
208     IO.mapOptional("Members", I.Members);
209   }
210 };
211 
212 template <> struct MappingTraits<FunctionInfo> {
mappingllvm::yaml::MappingTraits213   static void mapping(IO &IO, FunctionInfo &I) {
214     SymbolInfoMapping(IO, I);
215     IO.mapOptional("IsMethod", I.IsMethod, false);
216     IO.mapOptional("Parent", I.Parent, Reference());
217     IO.mapOptional("Params", I.Params);
218     IO.mapOptional("ReturnType", I.ReturnType);
219     IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
220   }
221 };
222 
223 template <> struct MappingTraits<CommentInfo> {
mappingllvm::yaml::MappingTraits224   static void mapping(IO &IO, CommentInfo &I) { CommentInfoMapping(IO, I); }
225 };
226 
227 template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
mappingllvm::yaml::MappingTraits228   static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) {
229     if (I)
230       CommentInfoMapping(IO, *I);
231   }
232 };
233 
234 } // end namespace yaml
235 } // end namespace llvm
236 
237 namespace clang {
238 namespace doc {
239 
240 /// Generator for YAML documentation.
241 class YAMLGenerator : public Generator {
242 public:
243   static const char *Format;
244 
245   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
246 };
247 
248 const char *YAMLGenerator::Format = "yaml";
249 
generateDocForInfo(Info * I,llvm::raw_ostream & OS)250 llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
251   llvm::yaml::Output InfoYAML(OS);
252   switch (I->IT) {
253   case InfoType::IT_namespace:
254     InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
255     break;
256   case InfoType::IT_record:
257     InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
258     break;
259   case InfoType::IT_enum:
260     InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
261     break;
262   case InfoType::IT_function:
263     InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
264     break;
265   case InfoType::IT_default:
266     return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
267                                                llvm::inconvertibleErrorCode());
268   }
269   return llvm::Error::success();
270 }
271 
272 static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
273                                                   "Generator for YAML output.");
274 
275 // This anchor is used to force the linker to link in the generated object file
276 // and thus register the generator.
277 volatile int YAMLGeneratorAnchorSource = 0;
278 
279 } // namespace doc
280 } // namespace clang
281