25 #include "clang/AST/AST.h"
26 #include "clang/AST/Decl.h"
27 #include "clang/ASTMatchers/ASTMatchFinder.h"
28 #include "clang/ASTMatchers/ASTMatchersInternal.h"
29 #include "clang/Driver/Options.h"
30 #include "clang/Frontend/FrontendActions.h"
31 #include "clang/Tooling/AllTUsExecution.h"
32 #include "clang/Tooling/CommonOptionsParser.h"
33 #include "clang/Tooling/Execution.h"
34 #include "clang/Tooling/Tooling.h"
35 #include "llvm/ADT/APFloat.h"
36 #include "llvm/Support/CommandLine.h"
37 #include "llvm/Support/Error.h"
38 #include "llvm/Support/FileSystem.h"
39 #include "llvm/Support/Mutex.h"
40 #include "llvm/Support/Path.h"
41 #include "llvm/Support/Process.h"
42 #include "llvm/Support/Signals.h"
43 #include "llvm/Support/ThreadPool.h"
44 #include "llvm/Support/raw_ostream.h"
50 using namespace clang;
52 static llvm::cl::extrahelp
CommonHelp(CommonOptionsParser::HelpMessage);
55 static llvm::cl::opt<std::string>
56 ProjectName(
"project-name", llvm::cl::desc(
"Name of project."),
61 llvm::cl::desc(
"Continue if files are not mapped correctly."),
64 static llvm::cl::opt<std::string>
66 llvm::cl::desc(
"Directory for outputting generated files."),
69 static llvm::cl::opt<bool>
70 PublicOnly(
"public", llvm::cl::desc(
"Document only public declarations."),
75 llvm::cl::desc(
"Use only doxygen-style comments to generate docs."),
79 "stylesheets", llvm::cl::CommaSeparated,
80 llvm::cl::desc(
"CSS stylesheets to extend the default styles."),
83 static llvm::cl::opt<std::string>
SourceRoot(
"source-root", llvm::cl::desc(R
"(
84 Directory where processed files are stored.
85 Links to definition locations will only be
86 generated if the file is in this dir.)"),
89 static llvm::cl::opt<std::string>
91 URL of repository that hosts code.
92 Used for links to definition locations.)"),
101 static llvm::cl::opt<OutputFormatTy>
102 FormatEnum(
"format", llvm::cl::desc(
"Format for outputted docs."),
104 "Documentation in YAML format."),
106 "Documentation in MD format."),
108 "Documentation in HTML format.")),
121 llvm_unreachable(
"Unknown OutputFormatTy");
130 return llvm::sys::fs::getMainExecutable(
Argv0, MainAddr);
133 bool CreateDirectory(
const Twine &DirName,
bool ClearDirectory =
false) {
135 llvm::SmallString<128> DocsRootPath;
136 if (ClearDirectory) {
137 std::error_code RemoveStatus = llvm::sys::fs::remove_directories(DirName);
138 if (RemoveStatus != OK) {
139 llvm::errs() <<
"Unable to remove existing documentation directory for "
144 std::error_code DirectoryStatus = llvm::sys::fs::create_directories(DirName);
145 if (DirectoryStatus != OK) {
146 llvm::errs() <<
"Unable to create documentation directories.\n";
168 StringRef RelativePath,
171 llvm::SmallString<128>
Path;
172 llvm::sys::path::native(Root,
Path);
173 llvm::sys::path::append(
Path, RelativePath);
175 return llvm::createStringError(llvm::inconvertibleErrorCode(),
176 "failed to create directory");
177 llvm::sys::path::append(
Path,
Name + Ext);
181 int main(
int argc,
const char **argv) {
182 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
185 ExecutorName.setInitialValue(
"all-TUs");
186 auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
190 llvm::errs() <<
toString(Exec.takeError()) <<
"\n";
196 llvm::outs() <<
"Emiting docs in " << Format <<
" format.\n";
199 llvm::errs() <<
toString(G.takeError()) <<
"\n";
203 ArgumentsAdjuster ArgAdjuster;
205 ArgAdjuster = combineAdjusters(
206 getInsertArgumentAdjuster(
"-fparse-all-comments",
207 tooling::ArgumentInsertPosition::END),
211 Exec->get()->getExecutionContext(),
218 {
"index.js",
"index_json.js"}};
220 if (Format ==
"html") {
223 llvm::SmallString<128> AssetsPath;
224 llvm::sys::path::native(ClangDocPath, AssetsPath);
225 AssetsPath = llvm::sys::path::parent_path(AssetsPath);
226 llvm::sys::path::append(AssetsPath,
"..",
"share",
"clang");
227 llvm::SmallString<128> DefaultStylesheet;
228 llvm::sys::path::native(AssetsPath, DefaultStylesheet);
229 llvm::sys::path::append(DefaultStylesheet,
230 "clang-doc-default-stylesheet.css");
231 llvm::SmallString<128> IndexJS;
232 llvm::sys::path::native(AssetsPath, IndexJS);
233 llvm::sys::path::append(IndexJS,
"index.js");
235 std::string(DefaultStylesheet.str()));
240 llvm::outs() <<
"Mapping decls...\n";
245 llvm::errs() <<
"Error mapping decls in files. Clang-doc will ignore "
246 "these files and continue:\n"
247 <<
toString(std::move(Err)) <<
"\n";
249 llvm::errs() <<
toString(std::move(Err)) <<
"\n";
257 llvm::outs() <<
"Collecting infos...\n";
258 llvm::StringMap<std::vector<StringRef>> USRToBitcode;
259 Exec->get()->getToolResults()->forEachResult(
260 [&](StringRef Key, StringRef Value) {
261 auto R = USRToBitcode.try_emplace(Key, std::vector<StringRef>());
262 R.first->second.emplace_back(Value);
266 llvm::outs() <<
"Reducing " << USRToBitcode.size() <<
" infos...\n";
267 std::atomic<bool>
Error;
269 llvm::sys::Mutex IndexMutex;
271 llvm::ThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency));
272 for (
auto &Group : USRToBitcode) {
274 std::vector<std::unique_ptr<doc::Info>> Infos;
276 for (
auto &Bitcode : Group.getValue()) {
277 llvm::BitstreamCursor Stream(Bitcode);
279 auto ReadInfos = Reader.readBitcode();
281 llvm::errs() <<
toString(ReadInfos.takeError()) <<
"\n";
285 std::move(ReadInfos->begin(), ReadInfos->end(),
286 std::back_inserter(Infos));
300 llvm::errs() <<
toString(InfoPath.takeError()) <<
"\n";
304 std::error_code FileErr;
305 llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr,
306 llvm::sys::fs::OF_None);
308 llvm::errs() <<
"Error opening info file " << InfoPath.get() <<
": "
309 << FileErr.message() <<
"\n";
318 if (
auto Err = G->get()->generateDocForInfo(I, InfoOS, CDCtx))
319 llvm::errs() <<
toString(std::move(Err)) <<
"\n";
328 llvm::outs() <<
"Generating assets for docs...\n";
329 Err = G->get()->createResources(CDCtx);
331 llvm::errs() <<
toString(std::move(Err)) <<
"\n";