[clang-doc] Implement a YAML generator
Implmenting a YAML generator from the emitted bitcode summary of
declarations. Emits one YAML file for each declaration information.
For a more detailed overview of the tool, see the design document on the mailing list: http://lists.llvm.org/pipermail/cfe-dev/2017-December/056203.html
llvm-svn: 334103
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 7593429..9345dad 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -21,6 +21,7 @@
#include "BitcodeReader.h"
#include "BitcodeWriter.h"
#include "ClangDoc.h"
+#include "Generators.h"
#include "Representation.h"
#include "clang/AST/AST.h"
#include "clang/AST/Decl.h"
@@ -67,10 +68,10 @@
yaml,
};
-static llvm::cl::opt<OutputFormatTy>
- Format("format", llvm::cl::desc("Format for outputted docs."),
- llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
- llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
+static llvm::cl::opt<OutputFormatTy> FormatEnum(
+ "format", llvm::cl::desc("Format for outputted docs."),
+ llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
+ llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
static llvm::cl::opt<bool> DoxygenOnly(
"doxygen",
@@ -116,8 +117,41 @@
return false;
}
+llvm::Expected<llvm::SmallString<128>>
+getPath(StringRef Root, StringRef Ext, StringRef Name,
+ llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
+ std::error_code OK;
+ llvm::SmallString<128> Path;
+ llvm::sys::path::native(Root, Path);
+ for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
+ llvm::sys::path::append(Path, R->Name);
+
+ if (CreateDirectory(Path))
+ return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
+ llvm::inconvertibleErrorCode());
+
+ llvm::sys::path::append(Path, Name + Ext);
+ return Path;
+}
+
+std::string getFormatString(OutputFormatTy Ty) {
+ switch (Ty) {
+ case yaml:
+ return "yaml";
+ }
+}
+
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ std::error_code OK;
+
+ // Fail early if an invalid format was provided.
+ std::string Format = getFormatString(FormatEnum);
+ auto G = doc::findGeneratorByName(Format);
+ if (!G) {
+ llvm::errs() << toString(G.takeError()) << "\n";
+ return 1;
+ }
auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
argc, argv, ClangDocCategory);
@@ -173,7 +207,7 @@
}
});
- // Reducing phase
+ // Reducing and generation phases
llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
for (auto &Group : MapOutput) {
@@ -186,16 +220,27 @@
llvm::BitstreamWriter Stream(Buffer);
doc::ClangDocBitcodeWriter Writer(Stream);
Writer.dispatchInfoForWrite(Reduced.get().get());
- if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer)) {
- llvm::errs() << "Error writing " << Group.getKey() << " to file.\n";
- continue;
- }
+ if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer))
+ llvm::errs() << "Error dumping to bitcode.\n";
+ continue;
}
- ReduceOutput.insert(
- std::make_pair(Group.getKey(), std::move(Reduced.get())));
+ // Create the relevant ostream and emit the documentation for this decl.
+ doc::Info *I = Reduced.get().get();
+ auto InfoPath = getPath(OutDirectory, "." + Format, I->Name, I->Namespace);
+ if (!InfoPath) {
+ llvm::errs() << toString(InfoPath.takeError()) << "\n";
+ continue;
+ }
+ std::error_code FileErr;
+ llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
+ if (FileErr != OK) {
+ llvm::errs() << "Error opening index file: " << FileErr.message() << "\n";
+ continue;
+ }
- // FIXME: Add support for emitting different output formats.
+ if (G->get()->generateDocForInfo(I, InfoOS))
+ llvm::errs() << "Unable to generate docs for info.\n";
}
return 0;