Index: clang-doc/CMakeLists.txt =================================================================== --- clang-doc/CMakeLists.txt +++ clang-doc/CMakeLists.txt @@ -22,3 +22,4 @@ ) add_subdirectory(tool) +add_subdirectory(generators) Index: clang-doc/generators/CMakeLists.txt =================================================================== --- /dev/null +++ clang-doc/generators/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangDocGenerators + GeneratorBase.cpp + YAMLGenerator.cpp + + LINK_LIBS + clangDoc + ) Index: clang-doc/generators/GeneratorBase.cpp =================================================================== --- /dev/null +++ clang-doc/generators/GeneratorBase.cpp @@ -0,0 +1,41 @@ +//===-- GeneratorBase.cpp - ClangDoc Generator ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../Representation.h" +#include "Generators.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace clang { +namespace doc { + +bool Generator::buildDirectory(StringRef Dir) { + std::error_code DirectoryStatus = sys::fs::create_directories(Dir); + if (DirectoryStatus != OK) { + errs() << "Unable to create documentation directories.\n"; + return false; + } + return true; +} + +bool Generator::removeExistingDirectory(StringRef Dir) { + std::error_code DirectoryStatus = sys::fs::remove_directories(Dir); + if (DirectoryStatus != OK) { + errs() << "Unable to remove existing documentation directories.\n"; + return false; + } + return true; +} + +} // namespace doc +} // namespace clang Index: clang-doc/generators/Generators.h =================================================================== --- /dev/null +++ clang-doc/generators/Generators.h @@ -0,0 +1,68 @@ +//===-- Generators.h - ClangDoc Generator ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H + +#include +#include "../Representation.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace clang { +namespace doc { + +class Generator { + public: + Generator(std::unique_ptr &IS, StringRef Root, StringRef Format) + : IS(IS), Root(Root), Format(Format){}; + virtual ~Generator(){}; + + virtual int generate() = 0; + + protected: + virtual bool buildDirectory(StringRef Dir); + virtual bool removeExistingDirectory(StringRef Dir); + + std::unique_ptr &IS; + std::string Root; + std::string Format; + std::error_code OK; +}; + +class YAMLGenerator : public Generator { + public: + YAMLGenerator(std::unique_ptr &IS, StringRef Root, StringRef Format) + : Generator(IS, Root, Format){}; + virtual ~YAMLGenerator(){}; + + int generate() override; +}; + +class GeneratorFactory { + public: + static std::unique_ptr create(std::unique_ptr &IS, + StringRef Root, StringRef Format) { + if (Format == "yaml") + return llvm::make_unique(IS, Root, Format); + + errs() << "Unsupported documentation format.\n"; + return nullptr; + } +}; + +} // namespace doc +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H Index: clang-doc/generators/YAMLGenerator.cpp =================================================================== --- /dev/null +++ clang-doc/generators/YAMLGenerator.cpp @@ -0,0 +1,199 @@ +//===-- ClangDocYAML.h - ClangDoc YAML -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_YAML_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_YAML_H + +#include "Generators.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace clang::doc; + +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(Location) + +namespace llvm { +namespace yaml { + +template <> +struct ScalarEnumerationTraits { + 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 { + 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 MappingTraits { + static void mapping(IO &IO, Location &Location) { + IO.mapRequired("LineNumber", Location.LineNumber); + IO.mapRequired("Filename", Location.Filename); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &T) { + IO.mapRequired("Type", T->TypeUSR); + IO.mapRequired("Description", T->Description); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &T) { + IO.mapRequired("Type", T->TypeUSR); + IO.mapRequired("Name", T->Name); + IO.mapRequired("Description", T->Description); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &T) { + IO.mapRequired("Type", T->TypeUSR); + IO.mapRequired("Name", T->Name); + IO.mapRequired("Access", T->Access); + IO.mapRequired("Description", T->Description); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &N) { + IO.mapRequired("Name", N->Name); + if (!N->Namespace.empty()) IO.mapRequired("Namespace", N->Namespace); + if (!N->Description.empty()) IO.mapRequired("Description", N->Description); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &R) { + IO.mapRequired("Name", R->Name); + if (!R->Namespace.empty()) IO.mapRequired("Namespace", R->Namespace); + if (!R->Description.empty()) IO.mapRequired("Description", R->Description); + IO.mapRequired("TagType", R->TagType); + IO.mapRequired("IsDefinition", R->IsDefinition); + IO.mapRequired("DefinitionLocation", R->DefLoc); + IO.mapRequired("Location", R->Loc); + IO.mapRequired("Members", R->Members); + IO.mapRequired("ParentUSRs", R->ParentUSRs); + IO.mapRequired("VirtualParentUSRs", R->VirtualParentUSRs); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &E) { + IO.mapRequired("Name", E->Name); + if (!E->Namespace.empty()) IO.mapRequired("Namespace", E->Namespace); + if (!E->Description.empty()) IO.mapRequired("Description", E->Description); + IO.mapRequired("IsDefinition", E->IsDefinition); + IO.mapRequired("DefinitionLocation", E->DefLoc); + IO.mapRequired("Location", E->Loc); + IO.mapRequired("Scoped", E->Scoped); + IO.mapRequired("Members", E->Members); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &F) { + IO.mapRequired("Name", F->Name); + if (!F->Namespace.empty()) IO.mapRequired("Namespace", F->Namespace); + if (!F->Description.empty()) IO.mapRequired("Description", F->Description); + IO.mapRequired("IsDefinition", F->IsDefinition); + IO.mapRequired("DefinitionLocation", F->DefLoc); + IO.mapRequired("Location", F->Loc); + IO.mapRequired("ParentUSR", F->Name); + IO.mapRequired("Params", F->Params); + IO.mapRequired("ReturnType", F->ReturnType); + IO.mapRequired("Access", F->Access); + } +}; + +template <> +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &C) { + IO.mapRequired("Kind", C->Kind); + if (!C->Text.empty()) IO.mapRequired("Text", C->Text); + if (!C->Name.empty()) IO.mapRequired("Name", C->Name); + if (!C->Direction.empty()) IO.mapRequired("Direction", C->Direction); + if (!C->ParamName.empty()) IO.mapRequired("ParamName", C->ParamName); + if (!C->CloseName.empty()) IO.mapRequired("CloseName", C->CloseName); + if (C->SelfClosing) IO.mapRequired("SelfClosing", C->SelfClosing); + if (C->Explicit) IO.mapRequired("Explicit", C->Explicit); + if (!C->Args.empty()) IO.mapRequired("Args", C->Args); + if (!C->AttrValues.empty()) IO.mapRequired("AttrKeys", C->AttrKeys); + if (!C->AttrValues.empty()) IO.mapRequired("AttrValues", C->AttrValues); + if (!C->Position.empty()) IO.mapRequired("Position", C->Position); + if (!C->Children.empty()) IO.mapRequired("Children", C->Children); + } +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, InfoSet &IS) { + IO.mapRequired("Namespaces", IS.getNamespaceInfos()); + IO.mapRequired("Records", IS.getRecordInfos()); + IO.mapRequired("Functions", IS.getFunctionInfos()); + IO.mapRequired("Enums", IS.getEnumInfos()); + } +}; + +} // end namespace yaml +} // end namespace llvm + +namespace clang { +namespace doc { + +int YAMLGenerator::generate() { + SmallString<128> Path; + sys::path::native(Root, Path); + sys::path::append(Path, "docs.yaml"); + std::error_code OutErrorInfo; + raw_fd_ostream OS(Path, OutErrorInfo, sys::fs::F_None); + if (OutErrorInfo != OK) { + errs() << "Error opening yaml file.\n"; + return 1; + } + + yaml::Output Output(OS); + Output << *IS; + OS.close(); + return 0; +} + +} // namespace doc +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_YAML_H Index: clang-doc/tool/CMakeLists.txt =================================================================== --- clang-doc/tool/CMakeLists.txt +++ clang-doc/tool/CMakeLists.txt @@ -11,6 +11,7 @@ clangBasic clangFrontend clangDoc + clangDocGenerators clangTooling clangToolingCore ) Index: clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-doc/tool/ClangDocMain.cpp +++ clang-doc/tool/ClangDocMain.cpp @@ -26,6 +26,7 @@ #include "clang/Tooling/Execution.h" #include "clang/Tooling/StandaloneExecution.h" #include "clang/Tooling/Tooling.h" +#include "generators/Generators.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -47,6 +48,10 @@ "output", cl::desc("Directory for outputting generated files."), cl::init("docs"), cl::cat(ClangDocCategory)); +static cl::opt Format( + "format", cl::desc("Format for outputted docs (Current options are yaml)."), + cl::init("yaml"), cl::cat(ClangDocCategory)); + static cl::opt DumpResult( "dump", cl::desc("Dump intermediate results to bitcode file."), cl::init(false), cl::cat(ClangDocCategory)); @@ -116,5 +121,23 @@ OS.close(); } - return 0; + errs() << "Generating docs...\n"; + SmallString<128> DocsRootPath; + sys::path::native(OutDirectory, DocsRootPath); + sys::path::append(DocsRootPath, Format); + std::error_code RemoveStatus = sys::fs::remove_directories(DocsRootPath); + if (RemoveStatus != OK) { + errs() << "Unable to remove existing documentation directory for " << Format + << ".\n"; + return 1; + } + std::error_code DirectoryStatus = sys::fs::create_directories(DocsRootPath); + if (DirectoryStatus != OK) { + errs() << "Unable to create documentation directories.\n"; + return 1; + } + std::unique_ptr G = + doc::GeneratorFactory::create(Infos, DocsRootPath, Format); + if (!G) return 1; + return G->generate(); } Index: test/clang-doc/namespace-yaml.cpp =================================================================== --- /dev/null +++ test/clang-doc/namespace-yaml.cpp @@ -0,0 +1,72 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "" > %t/compile_flags.txt +// RUN: cp "%s" "%t/test.cpp" +// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs +// RUN: cat %t/docs/yaml/docs.yaml | FileCheck %s + +namespace A { + +void f(); +void f() {}; + +} // A + +namespace A { +namespace B { + +enum E { X }; + +E func(int i) { + return X; +} + +} +} + +// CHECK: --- +// CHECK: Namespaces: +// CHECK: - Name: A +// CHECK: - Name: B +// CHECK: Namespace: +// CHECK: - 'c:@N@A' +// CHECK: Records: +// CHECK: Functions: +// CHECK: - Name: f +// CHECK: Namespace: +// CHECK: - 'c:@N@A' +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: ParentUSR: f +// CHECK: Params: +// CHECK: ReturnType: +// CHECK: Type: void +// CHECK: Description: +// CHECK: Access: Public +// CHECK: - Name: func +// CHECK: Namespace: +// CHECK: - 'c:@N@A@N@B' +// CHECK: - 'c:@N@A' +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: ParentUSR: func +// CHECK: Params: +// CHECK: - Type: int +// CHECK: Name: i +// CHECK: Description: +// CHECK: ReturnType: +// CHECK: Type: 'enum A::B::E' +// CHECK: Description: +// CHECK: Access: Public +// CHECK: Enums: +// CHECK: - Name: E +// CHECK: Namespace: +// CHECK: - 'c:@N@A@N@B' +// CHECK: - 'c:@N@A' +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Scoped: false +// CHECK: Members: +// CHECK: - Type: 'A::B::X' +// CHECK: Description: +// CHECK: ... Index: test/clang-doc/record-yaml.cpp =================================================================== --- /dev/null +++ test/clang-doc/record-yaml.cpp @@ -0,0 +1,119 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "" > %t/compile_flags.txt +// RUN: cp "%s" "%t/test.cpp" +// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs +// RUN: cat %t/docs/yaml/docs.yaml | FileCheck %s + +union A { int X; int Y; }; + +enum B { X, Y }; + +struct C { int i; }; + +class D {}; + +class E { +public: + E() {} + ~E() {} + +protected: + void ProtectedMethod(); +}; + +void E::ProtectedMethod() {} + +class F : virtual private D, public E {}; + +// CHECK: --- +// CHECK: Namespaces: +// CHECK: Records: +// CHECK: - Name: A +// CHECK: TagType: Union +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Members: +// CHECK: - Type: int +// CHECK: Name: 'A::X' +// CHECK: Access: None +// CHECK: Description: +// CHECK: - Type: int +// CHECK: Name: 'A::Y' +// CHECK: Access: None +// CHECK: Description: +// CHECK: ParentUSRs: +// CHECK: VirtualParentUSRs: +// CHECK: - Name: C +// CHECK: TagType: Struct +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Members: +// CHECK: - Type: int +// CHECK: Name: 'C::i' +// CHECK: Access: None +// CHECK: Description: +// CHECK: ParentUSRs: +// CHECK: VirtualParentUSRs: +// CHECK: - Name: D +// CHECK: TagType: Class +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Members: +// CHECK: ParentUSRs: +// CHECK: VirtualParentUSRs: +// CHECK: - Name: E +// CHECK: TagType: Class +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Members: +// CHECK: ParentUSRs: +// CHECK: VirtualParentUSRs: +// CHECK: - Name: F +// CHECK: TagType: Class +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Members: +// CHECK: ParentUSRs: +// CHECK: - 'c:@S@E' +// CHECK: VirtualParentUSRs: +// CHECK: - 'c:@S@D' +// CHECK: Functions: +// CHECK: - Name: E +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: ParentUSR: E +// CHECK: Params: +// CHECK: ReturnType: +// CHECK: Type: void +// CHECK: Description: +// CHECK: Access: Public +// CHECK: - Name: '~E' +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: ParentUSR: '~E' +// CHECK: Params: +// CHECK: ReturnType: +// CHECK: Type: void +// CHECK: Description: +// CHECK: Access: Public +// CHECK: - Name: ProtectedMethod +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: ParentUSR: ProtectedMethod +// CHECK: Params: +// CHECK: ReturnType: +// CHECK: Type: void +// CHECK: Description: +// CHECK: Access: Public +// CHECK: Enums: +// CHECK: - Name: B +// CHECK: IsDefinition: true +// CHECK: Location: +// CHECK: Scoped: false +// CHECK: Members: +// CHECK: - Type: X +// CHECK: Description: +// CHECK: - Type: Y +// CHECK: Description: +// CHECK: ...