brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.7 KiB · ce4ef58 Raw
430 lines · cpp
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-exception6//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 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",72                clang::doc::CommentKind::CK_ParagraphComment);73    IO.enumCase(Value, "TextComment", clang::doc::CommentKind::CK_TextComment);74    IO.enumCase(Value, "InlineCommandComment",75                clang::doc::CommentKind::CK_InlineCommandComment);76    IO.enumCase(Value, "HTMLStartTagComment",77                clang::doc::CommentKind::CK_HTMLStartTagComment);78    IO.enumCase(Value, "HTMLEndTagComment",79                clang::doc::CommentKind::CK_HTMLEndTagComment);80    IO.enumCase(Value, "BlockCommandComment",81                clang::doc::CommentKind::CK_BlockCommandComment);82    IO.enumCase(Value, "ParamCommandComment",83                clang::doc::CommentKind::CK_ParamCommandComment);84    IO.enumCase(Value, "TParamCommandComment",85                clang::doc::CommentKind::CK_TParamCommandComment);86    IO.enumCase(Value, "VerbatimBlockComment",87                clang::doc::CommentKind::CK_VerbatimBlockComment);88    IO.enumCase(Value, "VerbatimBlockLineComment",89                clang::doc::CommentKind::CK_VerbatimBlockLineComment);90    IO.enumCase(Value, "VerbatimLineComment",91                clang::doc::CommentKind::CK_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<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(toStringRef(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(Scalar);124    return StringRef();125  }126 127  static SymbolID stringToSymbol(llvm::StringRef Value) {128    SymbolID USR;129    std::string HexString = fromHex(Value);130    std::copy(HexString.begin(), HexString.end(), 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("Type", I.Type, Reference());141}142 143static void fieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {144  typeInfoMapping(IO, I);145  IO.mapOptional("Name", I.Name, SmallString<16>());146  IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());147}148 149static void infoMapping(IO &IO, Info &I) {150  IO.mapRequired("USR", I.USR);151  IO.mapOptional("Name", I.Name, SmallString<16>());152  IO.mapOptional("Path", I.Path, SmallString<128>());153  IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());154  IO.mapOptional("Description", I.Description);155}156 157static void symbolInfoMapping(IO &IO, SymbolInfo &I) {158  infoMapping(IO, I);159  IO.mapOptional("DefLocation", I.DefLoc, std::optional<Location>());160  IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());161}162 163static void recordInfoMapping(IO &IO, RecordInfo &I) {164  symbolInfoMapping(IO, I);165  IO.mapOptional("TagType", I.TagType);166  IO.mapOptional("IsTypeDef", I.IsTypeDef, false);167  IO.mapOptional("Members", I.Members);168  IO.mapOptional("Bases", I.Bases);169  IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());170  IO.mapOptional("VirtualParents", I.VirtualParents,171                 llvm::SmallVector<Reference, 4>());172  IO.mapOptional("ChildRecords", I.Children.Records, std::vector<Reference>());173  IO.mapOptional("ChildFunctions", I.Children.Functions);174  IO.mapOptional("ChildEnums", I.Children.Enums);175  IO.mapOptional("ChildTypedefs", I.Children.Typedefs);176  IO.mapOptional("Template", I.Template);177}178 179static void commentInfoMapping(IO &IO, CommentInfo &I) {180  IO.mapOptional("Kind", I.Kind, CommentKind::CK_Unknown);181  IO.mapOptional("Text", I.Text, SmallString<64>());182  IO.mapOptional("Name", I.Name, SmallString<16>());183  IO.mapOptional("Direction", I.Direction, SmallString<8>());184  IO.mapOptional("ParamName", I.ParamName, SmallString<16>());185  IO.mapOptional("CloseName", I.CloseName, SmallString<16>());186  IO.mapOptional("SelfClosing", I.SelfClosing, false);187  IO.mapOptional("Explicit", I.Explicit, false);188  IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>());189  IO.mapOptional("AttrKeys", I.AttrKeys,190                 llvm::SmallVector<SmallString<16>, 4>());191  IO.mapOptional("AttrValues", I.AttrValues,192                 llvm::SmallVector<SmallString<16>, 4>());193  IO.mapOptional("Children", 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("LineNumber", Loc.StartLineNumber, 0);201    IO.mapOptional("Filename", Loc.Filename, SmallString<32>());202  }203};204 205template <> struct MappingTraits<Reference> {206  static void mapping(IO &IO, Reference &Ref) {207    IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);208    IO.mapOptional("Name", Ref.Name, SmallString<16>());209    IO.mapOptional("QualName", Ref.QualName, SmallString<16>());210    IO.mapOptional("USR", Ref.USR, SymbolID());211    IO.mapOptional("Path", Ref.Path, 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("Name", I.Name, SmallString<16>());223    IO.mapOptional("DefaultValue", I.DefaultValue, 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's231    // the AS that shouldn't be part of the output. Even though AS_public is the232    // default in the struct, it should be displayed in the YAML output.233    IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);234    IO.mapOptional("Description", I.Description);235  }236};237 238template <> struct MappingTraits<NamespaceInfo> {239  static void mapping(IO &IO, NamespaceInfo &I) {240    infoMapping(IO, I);241    IO.mapOptional("ChildNamespaces", I.Children.Namespaces,242                   std::vector<Reference>());243    IO.mapOptional("ChildRecords", I.Children.Records,244                   std::vector<Reference>());245    IO.mapOptional("ChildFunctions", I.Children.Functions);246    IO.mapOptional("ChildEnums", I.Children.Enums);247    IO.mapOptional("ChildTypedefs", 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("IsVirtual", I.IsVirtual, false);259    // clang::AccessSpecifier::AS_none is used as the default here because it's260    // the AS that shouldn't be part of the output. Even though AS_public is the261    // default in the struct, it should be displayed in the YAML output.262    IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);263    IO.mapOptional("IsParent", I.IsParent, false);264  }265};266 267template <> struct MappingTraits<EnumValueInfo> {268  static void mapping(IO &IO, EnumValueInfo &I) {269    IO.mapOptional("Name", I.Name);270    IO.mapOptional("Value", I.Value);271    IO.mapOptional("Expr", I.ValueExpr, SmallString<16>());272  }273};274 275template <> struct MappingTraits<EnumInfo> {276  static void mapping(IO &IO, EnumInfo &I) {277    symbolInfoMapping(IO, I);278    IO.mapOptional("Scoped", I.Scoped, false);279    IO.mapOptional("BaseType", I.BaseType);280    IO.mapOptional("Members", I.Members);281  }282};283 284template <> struct MappingTraits<TypedefInfo> {285  static void mapping(IO &IO, TypedefInfo &I) {286    symbolInfoMapping(IO, I);287    IO.mapOptional("Underlying", I.Underlying.Type);288    IO.mapOptional("IsUsing", I.IsUsing, false);289  }290};291 292template <> struct MappingTraits<FunctionInfo> {293  static void mapping(IO &IO, FunctionInfo &I) {294    symbolInfoMapping(IO, I);295    IO.mapOptional("IsMethod", I.IsMethod, false);296    IO.mapOptional("Parent", I.Parent, Reference());297    IO.mapOptional("Params", I.Params);298    IO.mapOptional("ReturnType", I.ReturnType);299    // clang::AccessSpecifier::AS_none is used as the default here because it's300    // the AS that shouldn't be part of the output. Even though AS_public is the301    // default in the struct, it should be displayed in the YAML output.302    IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);303    IO.mapOptional("Template", I.Template);304  }305};306 307template <> struct MappingTraits<TemplateParamInfo> {308  static void mapping(IO &IO, TemplateParamInfo &I) {309    IO.mapOptional("Contents", I.Contents);310  }311};312 313template <> struct MappingTraits<TemplateSpecializationInfo> {314  static void mapping(IO &IO, TemplateSpecializationInfo &I) {315    IO.mapOptional("SpecializationOf", I.SpecializationOf);316    IO.mapOptional("Params", I.Params);317  }318};319 320template <> struct MappingTraits<TemplateInfo> {321  static void mapping(IO &IO, TemplateInfo &I) {322    IO.mapOptional("Params", I.Params);323    IO.mapOptional("Specialization", I.Specialization,324                   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);336  }337};338 339} // end namespace yaml340} // end namespace llvm341 342namespace clang {343namespace doc {344 345/// Generator for YAML documentation.346class YAMLGenerator : public Generator {347public:348  static const char *Format;349 350  llvm::Error generateDocumentation(351      StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,352      const ClangDocContext &CDCtx, std::string DirName) 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 YAMLGenerator::generateDocumentation(360    StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,361    const ClangDocContext &CDCtx, std::string DirName) {362  for (const auto &Group : Infos) {363    doc::Info *Info = Group.getValue().get();364 365    // Output file names according to the USR except the global namesapce.366    // Anonymous namespaces are taken care of in serialization, so here we can367    // safely assume an unnamed namespace is the global one.368    llvm::SmallString<128> Path;369    llvm::sys::path::native(RootDir, Path);370    if (Info->IT == InfoType::IT_namespace && Info->Name.empty()) {371      llvm::sys::path::append(Path, "index.yaml");372    } else {373      llvm::sys::path::append(Path, Group.getKey() + ".yaml");374    }375 376    std::error_code FileErr;377    llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_Text);378    if (FileErr) {379      return llvm::createStringError(FileErr, "Error opening file '%s'",380                                     Path.c_str());381    }382 383    if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {384      return Err;385    }386  }387 388  return llvm::Error::success();389}390 391llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,392                                              const ClangDocContext &CDCtx) {393  llvm::yaml::Output InfoYAML(OS);394  switch (I->IT) {395  case InfoType::IT_namespace:396    InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);397    break;398  case InfoType::IT_record:399    InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);400    break;401  case InfoType::IT_enum:402    InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);403    break;404  case InfoType::IT_function:405    InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);406    break;407  case InfoType::IT_typedef:408    InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);409    break;410  case InfoType::IT_concept:411  case InfoType::IT_variable:412  case InfoType::IT_friend:413    break;414  case InfoType::IT_default:415    return llvm::createStringError(llvm::inconvertibleErrorCode(),416                                   "unexpected InfoType");417  }418  return llvm::Error::success();419}420 421static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,422                                                  "Generator for YAML output.");423 424// This anchor is used to force the linker to link in the generated object file425// and thus register the generator.426volatile int YAMLGeneratorAnchorSource = 0;427 428} // namespace doc429} // namespace clang430