| //===-- YAMLGenerator.cpp - ClangDoc YAML -----------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // Implementation of the YAML generator, converting decl info into YAML output. |
| //===----------------------------------------------------------------------===// |
| |
| #include "Generators.h" |
| #include "llvm/Support/YAMLTraits.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| using namespace clang::doc; |
| |
| LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(Reference) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(Location) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>) |
| LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>) |
| |
| namespace llvm { |
| namespace yaml { |
| |
| // Enumerations to YAML output. |
| |
| template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> { |
| static void enumeration(IO &IO, clang::AccessSpecifier &Value) { |
| IO.enumCase(Value, "Public", clang::AccessSpecifier::AS_public); |
| IO.enumCase(Value, "Protected", clang::AccessSpecifier::AS_protected); |
| IO.enumCase(Value, "Private", clang::AccessSpecifier::AS_private); |
| IO.enumCase(Value, "None", clang::AccessSpecifier::AS_none); |
| } |
| }; |
| |
| template <> struct ScalarEnumerationTraits<clang::TagTypeKind> { |
| static void enumeration(IO &IO, clang::TagTypeKind &Value) { |
| IO.enumCase(Value, "Struct", clang::TagTypeKind::TTK_Struct); |
| IO.enumCase(Value, "Interface", clang::TagTypeKind::TTK_Interface); |
| IO.enumCase(Value, "Union", clang::TagTypeKind::TTK_Union); |
| IO.enumCase(Value, "Class", clang::TagTypeKind::TTK_Class); |
| IO.enumCase(Value, "Enum", clang::TagTypeKind::TTK_Enum); |
| } |
| }; |
| |
| template <> struct ScalarEnumerationTraits<InfoType> { |
| static void enumeration(IO &IO, InfoType &Value) { |
| IO.enumCase(Value, "Namespace", InfoType::IT_namespace); |
| IO.enumCase(Value, "Record", InfoType::IT_record); |
| IO.enumCase(Value, "Function", InfoType::IT_function); |
| IO.enumCase(Value, "Enum", InfoType::IT_enum); |
| IO.enumCase(Value, "Default", InfoType::IT_default); |
| } |
| }; |
| |
| // Scalars to YAML output. |
| template <unsigned U> struct ScalarTraits<SmallString<U>> { |
| |
| static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) { |
| for (const auto &C : S) |
| OS << C; |
| } |
| |
| static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) { |
| Value.assign(Scalar.begin(), Scalar.end()); |
| return StringRef(); |
| } |
| |
| static QuotingType mustQuote(StringRef) { return QuotingType::Single; } |
| }; |
| |
| template <> struct ScalarTraits<std::array<unsigned char, 20>> { |
| |
| static void output(const std::array<unsigned char, 20> &S, void *, |
| llvm::raw_ostream &OS) { |
| OS << toHex(toStringRef(S)); |
| } |
| |
| static StringRef input(StringRef Scalar, void *, |
| std::array<unsigned char, 20> &Value) { |
| if (Scalar.size() != 40) |
| return "Error: Incorrect scalar size for USR."; |
| Value = StringToSymbol(Scalar); |
| return StringRef(); |
| } |
| |
| static SymbolID StringToSymbol(llvm::StringRef Value) { |
| SymbolID USR; |
| std::string HexString = fromHex(Value); |
| std::copy(HexString.begin(), HexString.end(), USR.begin()); |
| return SymbolID(USR); |
| } |
| |
| static QuotingType mustQuote(StringRef) { return QuotingType::Single; } |
| }; |
| |
| // Helper functions to map infos to YAML. |
| |
| static void TypeInfoMapping(IO &IO, TypeInfo &I) { |
| IO.mapOptional("Type", I.Type, Reference()); |
| } |
| |
| static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) { |
| TypeInfoMapping(IO, I); |
| IO.mapOptional("Name", I.Name, SmallString<16>()); |
| } |
| |
| static void InfoMapping(IO &IO, Info &I) { |
| IO.mapRequired("USR", I.USR); |
| IO.mapOptional("Name", I.Name, SmallString<16>()); |
| IO.mapOptional("Path", I.Path, SmallString<128>()); |
| IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>()); |
| IO.mapOptional("Description", I.Description); |
| } |
| |
| static void SymbolInfoMapping(IO &IO, SymbolInfo &I) { |
| InfoMapping(IO, I); |
| IO.mapOptional("DefLocation", I.DefLoc, Optional<Location>()); |
| IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>()); |
| } |
| |
| static void RecordInfoMapping(IO &IO, RecordInfo &I) { |
| SymbolInfoMapping(IO, I); |
| IO.mapOptional("TagType", I.TagType, clang::TagTypeKind::TTK_Struct); |
| IO.mapOptional("Members", I.Members); |
| IO.mapOptional("Bases", I.Bases); |
| IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>()); |
| IO.mapOptional("VirtualParents", I.VirtualParents, |
| llvm::SmallVector<Reference, 4>()); |
| IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>()); |
| IO.mapOptional("ChildFunctions", I.ChildFunctions); |
| IO.mapOptional("ChildEnums", I.ChildEnums); |
| } |
| |
| static void CommentInfoMapping(IO &IO, CommentInfo &I) { |
| IO.mapOptional("Kind", I.Kind, SmallString<16>()); |
| IO.mapOptional("Text", I.Text, SmallString<64>()); |
| IO.mapOptional("Name", I.Name, SmallString<16>()); |
| IO.mapOptional("Direction", I.Direction, SmallString<8>()); |
| IO.mapOptional("ParamName", I.ParamName, SmallString<16>()); |
| IO.mapOptional("CloseName", I.CloseName, SmallString<16>()); |
| IO.mapOptional("SelfClosing", I.SelfClosing, false); |
| IO.mapOptional("Explicit", I.Explicit, false); |
| IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>()); |
| IO.mapOptional("AttrKeys", I.AttrKeys, |
| llvm::SmallVector<SmallString<16>, 4>()); |
| IO.mapOptional("AttrValues", I.AttrValues, |
| llvm::SmallVector<SmallString<16>, 4>()); |
| IO.mapOptional("Children", I.Children); |
| } |
| |
| // Template specialization to YAML traits for Infos. |
| |
| template <> struct MappingTraits<Location> { |
| static void mapping(IO &IO, Location &Loc) { |
| IO.mapOptional("LineNumber", Loc.LineNumber, 0); |
| IO.mapOptional("Filename", Loc.Filename, SmallString<32>()); |
| } |
| }; |
| |
| template <> struct MappingTraits<Reference> { |
| static void mapping(IO &IO, Reference &Ref) { |
| IO.mapOptional("Type", Ref.RefType, InfoType::IT_default); |
| IO.mapOptional("Name", Ref.Name, SmallString<16>()); |
| IO.mapOptional("USR", Ref.USR, SymbolID()); |
| IO.mapOptional("Path", Ref.Path, SmallString<128>()); |
| IO.mapOptional("IsInGlobalNamespace", Ref.IsInGlobalNamespace, false); |
| } |
| }; |
| |
| template <> struct MappingTraits<TypeInfo> { |
| static void mapping(IO &IO, TypeInfo &I) { TypeInfoMapping(IO, I); } |
| }; |
| |
| template <> struct MappingTraits<FieldTypeInfo> { |
| static void mapping(IO &IO, FieldTypeInfo &I) { |
| TypeInfoMapping(IO, I); |
| IO.mapOptional("Name", I.Name, SmallString<16>()); |
| } |
| }; |
| |
| template <> struct MappingTraits<MemberTypeInfo> { |
| static void mapping(IO &IO, MemberTypeInfo &I) { |
| FieldTypeInfoMapping(IO, I); |
| // clang::AccessSpecifier::AS_none is used as the default here because it's |
| // the AS that shouldn't be part of the output. Even though AS_public is the |
| // default in the struct, it should be displayed in the YAML output. |
| IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none); |
| } |
| }; |
| |
| template <> struct MappingTraits<NamespaceInfo> { |
| static void mapping(IO &IO, NamespaceInfo &I) { |
| InfoMapping(IO, I); |
| IO.mapOptional("ChildNamespaces", I.ChildNamespaces, |
| std::vector<Reference>()); |
| IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>()); |
| IO.mapOptional("ChildFunctions", I.ChildFunctions); |
| IO.mapOptional("ChildEnums", I.ChildEnums); |
| } |
| }; |
| |
| template <> struct MappingTraits<RecordInfo> { |
| static void mapping(IO &IO, RecordInfo &I) { RecordInfoMapping(IO, I); } |
| }; |
| |
| template <> struct MappingTraits<BaseRecordInfo> { |
| static void mapping(IO &IO, BaseRecordInfo &I) { |
| RecordInfoMapping(IO, I); |
| IO.mapOptional("IsVirtual", I.IsVirtual, false); |
| // clang::AccessSpecifier::AS_none is used as the default here because it's |
| // the AS that shouldn't be part of the output. Even though AS_public is the |
| // default in the struct, it should be displayed in the YAML output. |
| IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none); |
| IO.mapOptional("IsParent", I.IsParent, false); |
| } |
| }; |
| |
| template <> struct MappingTraits<EnumInfo> { |
| static void mapping(IO &IO, EnumInfo &I) { |
| SymbolInfoMapping(IO, I); |
| IO.mapOptional("Scoped", I.Scoped, false); |
| IO.mapOptional("Members", I.Members); |
| } |
| }; |
| |
| template <> struct MappingTraits<FunctionInfo> { |
| static void mapping(IO &IO, FunctionInfo &I) { |
| SymbolInfoMapping(IO, I); |
| IO.mapOptional("IsMethod", I.IsMethod, false); |
| IO.mapOptional("Parent", I.Parent, Reference()); |
| IO.mapOptional("Params", I.Params); |
| IO.mapOptional("ReturnType", I.ReturnType); |
| // clang::AccessSpecifier::AS_none is used as the default here because it's |
| // the AS that shouldn't be part of the output. Even though AS_public is the |
| // default in the struct, it should be displayed in the YAML output. |
| IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none); |
| } |
| }; |
| |
| template <> struct MappingTraits<CommentInfo> { |
| static void mapping(IO &IO, CommentInfo &I) { CommentInfoMapping(IO, I); } |
| }; |
| |
| template <> struct MappingTraits<std::unique_ptr<CommentInfo>> { |
| static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) { |
| if (I) |
| CommentInfoMapping(IO, *I); |
| } |
| }; |
| |
| } // end namespace yaml |
| } // end namespace llvm |
| |
| namespace clang { |
| namespace doc { |
| |
| /// Generator for YAML documentation. |
| class YAMLGenerator : public Generator { |
| public: |
| static const char *Format; |
| |
| llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, |
| const ClangDocContext &CDCtx) override; |
| }; |
| |
| const char *YAMLGenerator::Format = "yaml"; |
| |
| llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, |
| const ClangDocContext &CDCtx) { |
| llvm::yaml::Output InfoYAML(OS); |
| switch (I->IT) { |
| case InfoType::IT_namespace: |
| InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I); |
| break; |
| case InfoType::IT_record: |
| InfoYAML << *static_cast<clang::doc::RecordInfo *>(I); |
| break; |
| case InfoType::IT_enum: |
| InfoYAML << *static_cast<clang::doc::EnumInfo *>(I); |
| break; |
| case InfoType::IT_function: |
| InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I); |
| break; |
| case InfoType::IT_default: |
| return llvm::createStringError(llvm::inconvertibleErrorCode(), |
| "unexpected InfoType"); |
| } |
| return llvm::Error::success(); |
| } |
| |
| static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format, |
| "Generator for YAML output."); |
| |
| // This anchor is used to force the linker to link in the generated object file |
| // and thus register the generator. |
| volatile int YAMLGeneratorAnchorSource = 0; |
| |
| } // namespace doc |
| } // namespace clang |