YAMLGenerator.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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. #include "Generators.h"
  11. #include "Representation.h"
  12. #include "llvm/Support/YAMLTraits.h"
  13. #include "llvm/Support/raw_ostream.h"
  14. #include <optional>
  15. using namespace clang::doc;
  16. // These define YAML traits for decoding the listed values within a vector.
  17. LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo)
  18. LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo)
  19. LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
  20. LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
  21. LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
  22. LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
  23. LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
  24. LLVM_YAML_IS_SEQUENCE_VECTOR(EnumValueInfo)
  25. LLVM_YAML_IS_SEQUENCE_VECTOR(TemplateParamInfo)
  26. LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo)
  27. LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
  28. LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
  29. LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
  30. namespace llvm {
  31. namespace yaml {
  32. // Enumerations to YAML output.
  33. template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
  34. 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. template <> struct ScalarEnumerationTraits<clang::TagTypeKind> {
  42. static void enumeration(IO &IO, clang::TagTypeKind &Value) {
  43. IO.enumCase(Value, "Struct", clang::TagTypeKind::TTK_Struct);
  44. IO.enumCase(Value, "Interface", clang::TagTypeKind::TTK_Interface);
  45. IO.enumCase(Value, "Union", clang::TagTypeKind::TTK_Union);
  46. IO.enumCase(Value, "Class", clang::TagTypeKind::TTK_Class);
  47. IO.enumCase(Value, "Enum", clang::TagTypeKind::TTK_Enum);
  48. }
  49. };
  50. template <> struct ScalarEnumerationTraits<InfoType> {
  51. static void enumeration(IO &IO, InfoType &Value) {
  52. IO.enumCase(Value, "Namespace", InfoType::IT_namespace);
  53. IO.enumCase(Value, "Record", InfoType::IT_record);
  54. IO.enumCase(Value, "Function", InfoType::IT_function);
  55. IO.enumCase(Value, "Enum", InfoType::IT_enum);
  56. IO.enumCase(Value, "Default", InfoType::IT_default);
  57. }
  58. };
  59. // Scalars to YAML output.
  60. template <unsigned U> struct ScalarTraits<SmallString<U>> {
  61. static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
  62. for (const auto &C : S)
  63. OS << C;
  64. }
  65. static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
  66. Value.assign(Scalar.begin(), Scalar.end());
  67. return StringRef();
  68. }
  69. static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
  70. };
  71. template <> struct ScalarTraits<std::array<unsigned char, 20>> {
  72. static void output(const std::array<unsigned char, 20> &S, void *,
  73. llvm::raw_ostream &OS) {
  74. OS << toHex(toStringRef(S));
  75. }
  76. static StringRef input(StringRef Scalar, void *,
  77. std::array<unsigned char, 20> &Value) {
  78. if (Scalar.size() != 40)
  79. return "Error: Incorrect scalar size for USR.";
  80. Value = StringToSymbol(Scalar);
  81. return StringRef();
  82. }
  83. static SymbolID StringToSymbol(llvm::StringRef Value) {
  84. SymbolID USR;
  85. std::string HexString = fromHex(Value);
  86. std::copy(HexString.begin(), HexString.end(), USR.begin());
  87. return SymbolID(USR);
  88. }
  89. static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
  90. };
  91. // Helper functions to map infos to YAML.
  92. static void TypeInfoMapping(IO &IO, TypeInfo &I) {
  93. IO.mapOptional("Type", I.Type, Reference());
  94. }
  95. static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
  96. TypeInfoMapping(IO, I);
  97. IO.mapOptional("Name", I.Name, SmallString<16>());
  98. IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());
  99. }
  100. static void InfoMapping(IO &IO, Info &I) {
  101. IO.mapRequired("USR", I.USR);
  102. IO.mapOptional("Name", I.Name, SmallString<16>());
  103. IO.mapOptional("Path", I.Path, SmallString<128>());
  104. IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
  105. IO.mapOptional("Description", I.Description);
  106. }
  107. static void SymbolInfoMapping(IO &IO, SymbolInfo &I) {
  108. InfoMapping(IO, I);
  109. IO.mapOptional("DefLocation", I.DefLoc, std::optional<Location>());
  110. IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
  111. }
  112. static void RecordInfoMapping(IO &IO, RecordInfo &I) {
  113. SymbolInfoMapping(IO, I);
  114. IO.mapOptional("TagType", I.TagType);
  115. IO.mapOptional("IsTypeDef", I.IsTypeDef, false);
  116. IO.mapOptional("Members", I.Members);
  117. IO.mapOptional("Bases", I.Bases);
  118. IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
  119. IO.mapOptional("VirtualParents", I.VirtualParents,
  120. llvm::SmallVector<Reference, 4>());
  121. IO.mapOptional("ChildRecords", I.Children.Records, std::vector<Reference>());
  122. IO.mapOptional("ChildFunctions", I.Children.Functions);
  123. IO.mapOptional("ChildEnums", I.Children.Enums);
  124. IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
  125. IO.mapOptional("Template", I.Template);
  126. }
  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. // Template specialization to YAML traits for Infos.
  144. template <> struct MappingTraits<Location> {
  145. static void mapping(IO &IO, Location &Loc) {
  146. IO.mapOptional("LineNumber", Loc.LineNumber, 0);
  147. IO.mapOptional("Filename", Loc.Filename, SmallString<32>());
  148. }
  149. };
  150. template <> struct MappingTraits<Reference> {
  151. static void mapping(IO &IO, Reference &Ref) {
  152. IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
  153. IO.mapOptional("Name", Ref.Name, SmallString<16>());
  154. IO.mapOptional("QualName", Ref.QualName, SmallString<16>());
  155. IO.mapOptional("USR", Ref.USR, SymbolID());
  156. IO.mapOptional("Path", Ref.Path, SmallString<128>());
  157. }
  158. };
  159. template <> struct MappingTraits<TypeInfo> {
  160. static void mapping(IO &IO, TypeInfo &I) { TypeInfoMapping(IO, I); }
  161. };
  162. template <> struct MappingTraits<FieldTypeInfo> {
  163. static void mapping(IO &IO, FieldTypeInfo &I) {
  164. TypeInfoMapping(IO, I);
  165. IO.mapOptional("Name", I.Name, SmallString<16>());
  166. IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());
  167. }
  168. };
  169. template <> struct MappingTraits<MemberTypeInfo> {
  170. static void mapping(IO &IO, MemberTypeInfo &I) {
  171. FieldTypeInfoMapping(IO, I);
  172. // clang::AccessSpecifier::AS_none is used as the default here because it's
  173. // the AS that shouldn't be part of the output. Even though AS_public is the
  174. // default in the struct, it should be displayed in the YAML output.
  175. IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
  176. IO.mapOptional("Description", I.Description);
  177. }
  178. };
  179. template <> struct MappingTraits<NamespaceInfo> {
  180. static void mapping(IO &IO, NamespaceInfo &I) {
  181. InfoMapping(IO, I);
  182. IO.mapOptional("ChildNamespaces", I.Children.Namespaces,
  183. std::vector<Reference>());
  184. IO.mapOptional("ChildRecords", I.Children.Records,
  185. std::vector<Reference>());
  186. IO.mapOptional("ChildFunctions", I.Children.Functions);
  187. IO.mapOptional("ChildEnums", I.Children.Enums);
  188. IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
  189. }
  190. };
  191. template <> struct MappingTraits<RecordInfo> {
  192. static void mapping(IO &IO, RecordInfo &I) { RecordInfoMapping(IO, I); }
  193. };
  194. template <> struct MappingTraits<BaseRecordInfo> {
  195. static void mapping(IO &IO, BaseRecordInfo &I) {
  196. RecordInfoMapping(IO, I);
  197. IO.mapOptional("IsVirtual", I.IsVirtual, false);
  198. // clang::AccessSpecifier::AS_none is used as the default here because it's
  199. // the AS that shouldn't be part of the output. Even though AS_public is the
  200. // default in the struct, it should be displayed in the YAML output.
  201. IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
  202. IO.mapOptional("IsParent", I.IsParent, false);
  203. }
  204. };
  205. template <> struct MappingTraits<EnumValueInfo> {
  206. static void mapping(IO &IO, EnumValueInfo &I) {
  207. IO.mapOptional("Name", I.Name);
  208. IO.mapOptional("Value", I.Value);
  209. IO.mapOptional("Expr", I.ValueExpr, SmallString<16>());
  210. }
  211. };
  212. template <> struct MappingTraits<EnumInfo> {
  213. static void mapping(IO &IO, EnumInfo &I) {
  214. SymbolInfoMapping(IO, I);
  215. IO.mapOptional("Scoped", I.Scoped, false);
  216. IO.mapOptional("BaseType", I.BaseType);
  217. IO.mapOptional("Members", I.Members);
  218. }
  219. };
  220. template <> struct MappingTraits<TypedefInfo> {
  221. static void mapping(IO &IO, TypedefInfo &I) {
  222. SymbolInfoMapping(IO, I);
  223. IO.mapOptional("Underlying", I.Underlying.Type);
  224. IO.mapOptional("IsUsing", I.IsUsing, false);
  225. }
  226. };
  227. template <> struct MappingTraits<FunctionInfo> {
  228. static void mapping(IO &IO, FunctionInfo &I) {
  229. SymbolInfoMapping(IO, I);
  230. IO.mapOptional("IsMethod", I.IsMethod, false);
  231. IO.mapOptional("Parent", I.Parent, Reference());
  232. IO.mapOptional("Params", I.Params);
  233. IO.mapOptional("ReturnType", I.ReturnType);
  234. // clang::AccessSpecifier::AS_none is used as the default here because it's
  235. // the AS that shouldn't be part of the output. Even though AS_public is the
  236. // default in the struct, it should be displayed in the YAML output.
  237. IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
  238. IO.mapOptional("Template", I.Template);
  239. }
  240. };
  241. template <> struct MappingTraits<TemplateParamInfo> {
  242. static void mapping(IO &IO, TemplateParamInfo &I) {
  243. IO.mapOptional("Contents", I.Contents);
  244. }
  245. };
  246. template <> struct MappingTraits<TemplateSpecializationInfo> {
  247. static void mapping(IO &IO, TemplateSpecializationInfo &I) {
  248. IO.mapOptional("SpecializationOf", I.SpecializationOf);
  249. IO.mapOptional("Params", I.Params);
  250. }
  251. };
  252. template <> struct MappingTraits<TemplateInfo> {
  253. static void mapping(IO &IO, TemplateInfo &I) {
  254. IO.mapOptional("Params", I.Params);
  255. IO.mapOptional("Specialization", I.Specialization,
  256. std::optional<TemplateSpecializationInfo>());
  257. }
  258. };
  259. template <> struct MappingTraits<CommentInfo> {
  260. static void mapping(IO &IO, CommentInfo &I) { CommentInfoMapping(IO, I); }
  261. };
  262. template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
  263. static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) {
  264. if (I)
  265. CommentInfoMapping(IO, *I);
  266. }
  267. };
  268. } // end namespace yaml
  269. } // end namespace llvm
  270. namespace clang {
  271. namespace doc {
  272. /// Generator for YAML documentation.
  273. class YAMLGenerator : public Generator {
  274. public:
  275. static const char *Format;
  276. llvm::Error generateDocs(StringRef RootDir,
  277. llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
  278. const ClangDocContext &CDCtx) override;
  279. llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
  280. const ClangDocContext &CDCtx) override;
  281. };
  282. const char *YAMLGenerator::Format = "yaml";
  283. llvm::Error
  284. YAMLGenerator::generateDocs(StringRef RootDir,
  285. llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
  286. const ClangDocContext &CDCtx) {
  287. for (const auto &Group : Infos) {
  288. doc::Info *Info = Group.getValue().get();
  289. // Output file names according to the USR except the global namesapce.
  290. // Anonymous namespaces are taken care of in serialization, so here we can
  291. // safely assume an unnamed namespace is the global one.
  292. llvm::SmallString<128> Path;
  293. llvm::sys::path::native(RootDir, Path);
  294. if (Info->IT == InfoType::IT_namespace && Info->Name.empty()) {
  295. llvm::sys::path::append(Path, "index.yaml");
  296. } else {
  297. llvm::sys::path::append(Path, Group.getKey() + ".yaml");
  298. }
  299. std::error_code FileErr;
  300. llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_None);
  301. if (FileErr) {
  302. return llvm::createStringError(FileErr, "Error opening file '%s'",
  303. Path.c_str());
  304. }
  305. if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
  306. return Err;
  307. }
  308. }
  309. return llvm::Error::success();
  310. }
  311. llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
  312. const ClangDocContext &CDCtx) {
  313. llvm::yaml::Output InfoYAML(OS);
  314. switch (I->IT) {
  315. case InfoType::IT_namespace:
  316. InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
  317. break;
  318. case InfoType::IT_record:
  319. InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
  320. break;
  321. case InfoType::IT_enum:
  322. InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
  323. break;
  324. case InfoType::IT_function:
  325. InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
  326. break;
  327. case InfoType::IT_typedef:
  328. InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);
  329. break;
  330. case InfoType::IT_default:
  331. return llvm::createStringError(llvm::inconvertibleErrorCode(),
  332. "unexpected InfoType");
  333. }
  334. return llvm::Error::success();
  335. }
  336. static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
  337. "Generator for YAML output.");
  338. // This anchor is used to force the linker to link in the generated object file
  339. // and thus register the generator.
  340. volatile int YAMLGeneratorAnchorSource = 0;
  341. } // namespace doc
  342. } // namespace clang