You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
11 KiB
307 lines
11 KiB
//===-- 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
|