25#include "clang/ASTMatchers/ASTMatchersInternal.h"
26#include "clang/Tooling/AllTUsExecution.h"
27#include "clang/Tooling/CommonOptionsParser.h"
28#include "clang/Tooling/Execution.h"
29#include "llvm/ADT/APFloat.h"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/Error.h"
32#include "llvm/Support/FileSystem.h"
33#include "llvm/Support/Mutex.h"
34#include "llvm/Support/Path.h"
35#include "llvm/Support/Process.h"
36#include "llvm/Support/Signals.h"
37#include "llvm/Support/ThreadPool.h"
38#include "llvm/Support/TimeProfiler.h"
39#include "llvm/Support/raw_ostream.h"
48static llvm::cl::extrahelp
CommonHelp(CommonOptionsParser::HelpMessage);
51static llvm::cl::opt<std::string>
52 ProjectName(
"project-name", llvm::cl::desc(
"Name of project."),
57 llvm::cl::desc(
"Continue if files are not mapped correctly."),
60static llvm::cl::opt<std::string>
62 llvm::cl::desc(
"Directory for outputting generated files."),
65static llvm::cl::opt<std::string>
67 llvm::cl::desc(R
"(Base Directory for generated documentation.
68URLs will be rooted at this directory for HTML links.)"),
71static llvm::cl::opt<bool>
72 PublicOnly(
"public", llvm::cl::desc(
"Document only public declarations."),
77 llvm::cl::desc(
"Use only doxygen-style comments to generate docs."),
81 "stylesheets", llvm::cl::CommaSeparated,
82 llvm::cl::desc(
"CSS stylesheets to extend the default styles."),
87 llvm::cl::desc(
"User supplied asset path to "
88 "override the default css and js files for html output"),
91static llvm::cl::opt<std::string>
SourceRoot(
"source-root", llvm::cl::desc(R
"(
92Directory where processed files are stored.
93Links to definition locations will only be
94generated if the file is in this dir.)"),
97static llvm::cl::opt<std::string>
99URL of repository that hosts code.
100Used for links to definition locations.)"),
104 "repository-line-prefix",
105 llvm::cl::desc(
"Prefix of line code for repository."),
108static llvm::cl::opt<bool>
FTimeTrace(
"ftime-trace", llvm::cl::desc(R
"(
109Turn on time profiler. Generates clang-doc-tracing.json)"),
110 llvm::cl::init(false),
115static llvm::cl::opt<OutputFormatTy>
FormatEnum(
116 "format", llvm::cl::desc(
"Format for outputted docs."),
118 "Documentation in YAML format."),
120 "Documentation in MD format."),
122 "Documentation in HTML format."),
124 "Documentation in mustache HTML format"),
126 "Documentation in JSON format")),
144 llvm_unreachable(
"Unknown OutputFormatTy");
153 return llvm::sys::fs::getMainExecutable(
Argv0, MainAddr);
157 using DirIt = llvm::sys::fs::directory_iterator;
158 std::error_code FileErr;
161 !FileErr && DirStart != DirEnd; DirStart.increment(FileErr)) {
162 FilePath = DirStart->path();
163 if (llvm::sys::fs::is_regular_file(FilePath)) {
164 if (llvm::sys::path::extension(FilePath) ==
".css")
166 std::string(FilePath));
167 else if (llvm::sys::path::extension(FilePath) ==
".js")
168 CDCtx.
JsScripts.emplace_back(FilePath.str());
172 return llvm::createFileError(FilePath, FileErr);
173 return llvm::Error::success();
180 llvm::SmallString<128> NativeClangDocPath;
181 llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
183 llvm::SmallString<128> AssetsPath;
184 AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
185 llvm::sys::path::append(AssetsPath,
"..",
"share",
"clang-doc");
186 llvm::SmallString<128> DefaultStylesheet =
190 if (!llvm::sys::fs::is_regular_file(IndexJS))
191 return llvm::createStringError(llvm::inconvertibleErrorCode(),
192 "default index.js file missing at " +
195 if (!llvm::sys::fs::is_regular_file(DefaultStylesheet))
196 return llvm::createStringError(
197 llvm::inconvertibleErrorCode(),
198 "default clang-doc-default-stylesheet.css file missing at " +
199 DefaultStylesheet +
"\n");
202 std::string(DefaultStylesheet));
203 CDCtx.
JsScripts.emplace_back(IndexJS.str());
205 return llvm::Error::success();
213 <<
" falling back to default\n";
223 llvm::outs() <<
"Asset path supply is not a directory: " <<
UserAssetPath
224 <<
" falling back to default\n";
227 return llvm::Error::success();
231 llvm::SmallString<128> NativeClangDocPath;
232 llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
234 llvm::SmallString<128> AssetsPath;
235 AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
236 llvm::sys::path::append(AssetsPath,
"..",
"share",
"clang-doc");
240 return llvm::Error::success();
246sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) {
247 for (
auto &I : USRToInfo) {
248 auto &
Info = I.second;
255 Record->Children.sort();
262 return llvm::Error::success();
264 llvm::errs() <<
"Error mapping decls in files. Clang-doc will ignore these "
265 "files and continue:\n"
266 << toString(std::move(Err)) <<
"\n";
267 return llvm::Error::success();
273 if (std::error_code Err = llvm::sys::fs::create_directories(
OutDirectory))
275 "failed to create directory.");
276 return llvm::Error::success();
279int main(
int argc,
const char **argv) {
280 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
283 ExitOnErr.setBanner(
"clang-doc error: ");
285 const char *Overview =
286 R
"(Generates documentation from source code and comments.
288Example usage for files without flags (default):
290 $ clang-doc File1.cpp File2.cpp ... FileN.cpp
292Example usage for a project using a compile commands database:
294 $ clang-doc --executor=all-TUs compile_commands.json
297 auto Executor =
ExitOnErr(clang::tooling::createExecutorFromCommandLineArgs(
302 llvm::timeTraceProfilerInitialize(200,
"clang-doc");
304 llvm::TimeTraceScope(
"main");
308 llvm::outs() <<
"Emiting docs in " << Format <<
" format.\n";
311 ArgumentsAdjuster ArgAdjuster;
313 ArgAdjuster = combineAdjusters(
314 getInsertArgumentAdjuster(
"-fparse-all-comments",
315 tooling::ArgumentInsertPosition::END),
319 Executor->getExecutionContext(),
330 if (Format ==
"html") {
332 }
else if (Format ==
"mustache") {
336 llvm::timeTraceProfilerBegin(
"Executor Launch",
"total runtime");
338 llvm::outs() <<
"Mapping decls...\n";
341 llvm::timeTraceProfilerEnd();
346 llvm::timeTraceProfilerBegin(
"Collect Info",
"total runtime");
347 llvm::outs() <<
"Collecting infos...\n";
348 llvm::StringMap<std::vector<StringRef>> USRToBitcode;
349 Executor->getToolResults()->forEachResult(
350 [&](StringRef Key, StringRef Value) {
351 USRToBitcode[
Key].emplace_back(Value);
353 llvm::timeTraceProfilerEnd();
357 llvm::sys::Mutex USRToInfoMutex;
358 llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo;
361 llvm::outs() <<
"Reducing " << USRToBitcode.size() <<
" infos...\n";
362 std::atomic<bool>
Error;
364 llvm::sys::Mutex IndexMutex;
366 llvm::DefaultThreadPool Pool(
367 llvm::hardware_concurrency(ExecutorConcurrency));
369 llvm::TimeTraceScope TS(
"Reduce");
370 for (
auto &Group : USRToBitcode) {
373 llvm::timeTraceProfilerInitialize(200,
"clang-doc");
375 std::vector<std::unique_ptr<doc::Info>> Infos;
377 llvm::TimeTraceScope Red(
"decoding bitcode");
378 for (
auto &Bitcode : Group.getValue()) {
379 llvm::BitstreamCursor Stream(Bitcode);
381 auto ReadInfos = Reader.readBitcode();
383 llvm::errs() << toString(ReadInfos.takeError()) <<
"\n";
387 std::move(ReadInfos->begin(), ReadInfos->end(),
388 std::back_inserter(Infos));
392 std::unique_ptr<doc::Info> Reduced;
395 llvm::TimeTraceScope
Merge(
"merging bitcode");
399 llvm::errs() << llvm::toString(ExpReduced.takeError());
402 Reduced = std::move(*ExpReduced);
407 llvm::TimeTraceScope
Merge(
"addInfoToIndex");
408 std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex);
413 llvm::TimeTraceScope
Merge(
"USRToInfo");
414 std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex);
415 USRToInfo[Group.getKey()] = std::move(Reduced);
419 llvm::timeTraceProfilerFinishThread();
430 llvm::TimeTraceScope Sort(
"Sort USRToInfo");
434 llvm::timeTraceProfilerBegin(
"Writing output",
"total runtime");
439 llvm::outs() <<
"Generating docs...\n";
442 llvm::outs() <<
"Generating assets for docs...\n";
444 llvm::timeTraceProfilerEnd();
449 llvm::raw_fd_ostream OS(
"clang-doc-tracing.json", EC,
450 llvm::sys::fs::OF_Text);
452 llvm::timeTraceProfilerWrite(OS);
453 llvm::timeTraceProfilerCleanup();
static llvm::cl::opt< std::string > UserAssetPath("asset", llvm::cl::desc("User supplied asset path to " "override the default css and js files for html output"), llvm::cl::cat(ClangDocCategory))
static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage)
static std::string getExecutablePath(const char *Argv0, void *MainAddr)
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
static llvm::cl::opt< std::string > RepositoryCodeLinePrefix("repository-line-prefix", llvm::cl::desc("Prefix of line code for repository."), llvm::cl::cat(ClangDocCategory))
int main(int argc, const char **argv)
static llvm::cl::opt< OutputFormatTy > FormatEnum("format", llvm::cl::desc("Format for outputted docs."), llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml", "Documentation in YAML format."), clEnumValN(OutputFormatTy::md, "md", "Documentation in MD format."), clEnumValN(OutputFormatTy::html, "html", "Documentation in HTML format."), clEnumValN(OutputFormatTy::mustache, "mustache", "Documentation in mustache HTML format"), clEnumValN(OutputFormatTy::json, "json", "Documentation in JSON format")), llvm::cl::init(OutputFormatTy::yaml), llvm::cl::cat(ClangDocCategory))
static void sortUsrToInfo(llvm::StringMap< std::unique_ptr< doc::Info > > &USRToInfo)
Make the output of clang-doc deterministic by sorting the children of namespaces and records.
static llvm::cl::opt< std::string > ProjectName("project-name", llvm::cl::desc("Name of project."), llvm::cl::cat(ClangDocCategory))
static llvm::Error handleMappingFailures(llvm::Error Err)
static llvm::Error getHtmlAssetFiles(const char *Argv0, clang::doc::ClangDocContext &CDCtx)
static llvm::Error createDirectories(llvm::StringRef OutDirectory)
static llvm::cl::opt< bool > FTimeTrace("ftime-trace", llvm::cl::desc(R"(
Turn on time profiler. Generates clang-doc-tracing.json)"), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
static llvm::cl::list< std::string > UserStylesheets("stylesheets", llvm::cl::CommaSeparated, llvm::cl::desc("CSS stylesheets to extend the default styles."), llvm::cl::cat(ClangDocCategory))
static llvm::ExitOnError ExitOnErr
static llvm::cl::opt< std::string > SourceRoot("source-root", llvm::cl::desc(R"(
Directory where processed files are stored.
Links to definition locations will only be
generated if the file is in this dir.)"), llvm::cl::cat(ClangDocCategory))
static std::string getFormatString()
static llvm::cl::opt< std::string > BaseDirectory("base", llvm::cl::desc(R"(Base Directory for generated documentation.
URLs will be rooted at this directory for HTML links.)"), llvm::cl::init(""), llvm::cl::cat(ClangDocCategory))
static llvm::cl::opt< bool > IgnoreMappingFailures("ignore-map-errors", llvm::cl::desc("Continue if files are not mapped correctly."), llvm::cl::init(true), llvm::cl::cat(ClangDocCategory))
static llvm::cl::opt< std::string > OutDirectory("output", llvm::cl::desc("Directory for outputting generated files."), llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory))
static llvm::Error getMustacheHtmlFiles(const char *Argv0, clang::doc::ClangDocContext &CDCtx)
static llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx)
static llvm::cl::opt< bool > DoxygenOnly("doxygen", llvm::cl::desc("Use only doxygen-style comments to generate docs."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
static llvm::Error getDefaultAssetFiles(const char *Argv0, clang::doc::ClangDocContext &CDCtx)
static llvm::cl::OptionCategory ClangDocCategory("clang-doc options")
static llvm::cl::opt< std::string > RepositoryUrl("repository", llvm::cl::desc(R"(
URL of repository that hosts code.
Used for links to definition locations.)"), llvm::cl::cat(ClangDocCategory))
SmallString< 128 > appendPathNative(StringRef Base, StringRef Path)
static void addInfoToIndex(Index &Idx, const doc::Info *Info)
@ Info
An information message.
llvm::Expected< std::unique_ptr< Info > > mergeInfos(std::vector< std::unique_ptr< Info > > &Values)
std::unique_ptr< tooling::FrontendActionFactory > newMapperActionFactory(ClangDocContext CDCtx)
llvm::Expected< std::unique_ptr< Generator > > findGeneratorByName(llvm::StringRef Format)
bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< std::string > UserStylesheets
std::vector< std::string > JsScripts