1e975a473SJulie Hockett //===-- ClangDocMain.cpp - ClangDoc -----------------------------*- C++ -*-===// 2e975a473SJulie Hockett // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e975a473SJulie Hockett // 7e975a473SJulie Hockett //===----------------------------------------------------------------------===// 8e975a473SJulie Hockett // 9b7ecf1c1SKazuaki Ishizaki // This tool for generating C and C++ documentation from source code 10e975a473SJulie Hockett // and comments. Generally, it runs a LibTooling FrontendAction on source files, 11e975a473SJulie Hockett // mapping each declaration in those files to its USR and serializing relevant 12e975a473SJulie Hockett // information into LLVM bitcode. It then runs a pass over the collected 13e975a473SJulie Hockett // declaration information, reducing by USR. There is an option to dump this 14e975a473SJulie Hockett // intermediate result to bitcode. Finally, it hands the reduced information 15e975a473SJulie Hockett // off to a generator, which does the final parsing from the intermediate 16e975a473SJulie Hockett // representation to the desired output format. 17e975a473SJulie Hockett // 18e975a473SJulie Hockett //===----------------------------------------------------------------------===// 19e975a473SJulie Hockett 20d0f9a872SJulie Hockett #include "BitcodeReader.h" 21d0f9a872SJulie Hockett #include "BitcodeWriter.h" 22e975a473SJulie Hockett #include "ClangDoc.h" 23e78f3018SJulie Hockett #include "Generators.h" 24d0f9a872SJulie Hockett #include "Representation.h" 25e975a473SJulie Hockett #include "clang/AST/AST.h" 26e975a473SJulie Hockett #include "clang/AST/Decl.h" 27e975a473SJulie Hockett #include "clang/ASTMatchers/ASTMatchFinder.h" 28e975a473SJulie Hockett #include "clang/ASTMatchers/ASTMatchersInternal.h" 29e975a473SJulie Hockett #include "clang/Driver/Options.h" 30e975a473SJulie Hockett #include "clang/Frontend/FrontendActions.h" 316ab28e8cSDiego Astiazaran #include "clang/Tooling/AllTUsExecution.h" 32e975a473SJulie Hockett #include "clang/Tooling/CommonOptionsParser.h" 33e975a473SJulie Hockett #include "clang/Tooling/Execution.h" 34e975a473SJulie Hockett #include "clang/Tooling/Tooling.h" 35e975a473SJulie Hockett #include "llvm/ADT/APFloat.h" 36ac68cab9SJulie Hockett #include "llvm/Support/CommandLine.h" 37d0f9a872SJulie Hockett #include "llvm/Support/Error.h" 38e975a473SJulie Hockett #include "llvm/Support/FileSystem.h" 39e2d45770SDiego Astiazaran #include "llvm/Support/Mutex.h" 40e975a473SJulie Hockett #include "llvm/Support/Path.h" 41e975a473SJulie Hockett #include "llvm/Support/Process.h" 42e975a473SJulie Hockett #include "llvm/Support/Signals.h" 436ab28e8cSDiego Astiazaran #include "llvm/Support/ThreadPool.h" 44e975a473SJulie Hockett #include "llvm/Support/raw_ostream.h" 456ab28e8cSDiego Astiazaran #include <atomic> 467b8c7e02SBrett Wilson #include <mutex> 47e975a473SJulie Hockett #include <string> 48e975a473SJulie Hockett 49e975a473SJulie Hockett using namespace clang::ast_matchers; 50e975a473SJulie Hockett using namespace clang::tooling; 51e975a473SJulie Hockett using namespace clang; 52e975a473SJulie Hockett 53e975a473SJulie Hockett static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); 54e975a473SJulie Hockett static llvm::cl::OptionCategory ClangDocCategory("clang-doc options"); 55e975a473SJulie Hockett 563550da79SDiego Astiazaran static llvm::cl::opt<std::string> 573550da79SDiego Astiazaran ProjectName("project-name", llvm::cl::desc("Name of project."), 583550da79SDiego Astiazaran llvm::cl::cat(ClangDocCategory)); 593550da79SDiego Astiazaran 608fb7074dSDiego Astiazaran static llvm::cl::opt<bool> IgnoreMappingFailures( 618fb7074dSDiego Astiazaran "ignore-map-errors", 628fb7074dSDiego Astiazaran llvm::cl::desc("Continue if files are not mapped correctly."), 638fb7074dSDiego Astiazaran llvm::cl::init(true), llvm::cl::cat(ClangDocCategory)); 648fb7074dSDiego Astiazaran 65e975a473SJulie Hockett static llvm::cl::opt<std::string> 66e975a473SJulie Hockett OutDirectory("output", 67e975a473SJulie Hockett llvm::cl::desc("Directory for outputting generated files."), 68e975a473SJulie Hockett llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory)); 69e975a473SJulie Hockett 70e975a473SJulie Hockett static llvm::cl::opt<bool> 71eb50a2e8SJulie Hockett PublicOnly("public", llvm::cl::desc("Document only public declarations."), 72eb50a2e8SJulie Hockett llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); 73eb50a2e8SJulie Hockett 74229c63b0SJulie Hockett static llvm::cl::opt<bool> DoxygenOnly( 75229c63b0SJulie Hockett "doxygen", 76229c63b0SJulie Hockett llvm::cl::desc("Use only doxygen-style comments to generate docs."), 77229c63b0SJulie Hockett llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); 78229c63b0SJulie Hockett 79acd35f6cSDiego Astiazaran static llvm::cl::list<std::string> UserStylesheets( 80acd35f6cSDiego Astiazaran "stylesheets", llvm::cl::CommaSeparated, 81acd35f6cSDiego Astiazaran llvm::cl::desc("CSS stylesheets to extend the default styles."), 82acd35f6cSDiego Astiazaran llvm::cl::cat(ClangDocCategory)); 83acd35f6cSDiego Astiazaran 84f14ad744SPeterChou1 static llvm::cl::opt<std::string> UserAssetPath( 85f14ad744SPeterChou1 "asset", 86f14ad744SPeterChou1 llvm::cl::desc("User supplied asset path to " 87f14ad744SPeterChou1 "override the default css and js files for html output"), 88f14ad744SPeterChou1 llvm::cl::cat(ClangDocCategory)); 89f14ad744SPeterChou1 90665e9676SDiego Astiazaran static llvm::cl::opt<std::string> SourceRoot("source-root", llvm::cl::desc(R"( 91665e9676SDiego Astiazaran Directory where processed files are stored. 92665e9676SDiego Astiazaran Links to definition locations will only be 93665e9676SDiego Astiazaran generated if the file is in this dir.)"), 94665e9676SDiego Astiazaran llvm::cl::cat(ClangDocCategory)); 95665e9676SDiego Astiazaran 96665e9676SDiego Astiazaran static llvm::cl::opt<std::string> 97665e9676SDiego Astiazaran RepositoryUrl("repository", llvm::cl::desc(R"( 98665e9676SDiego Astiazaran URL of repository that hosts code. 99665e9676SDiego Astiazaran Used for links to definition locations.)"), 100665e9676SDiego Astiazaran llvm::cl::cat(ClangDocCategory)); 101665e9676SDiego Astiazaran 102d0f9a872SJulie Hockett enum OutputFormatTy { 103ac68cab9SJulie Hockett md, 104d0f9a872SJulie Hockett yaml, 105671bac74SJulie Hockett html, 106d0f9a872SJulie Hockett }; 107d0f9a872SJulie Hockett 108ac68cab9SJulie Hockett static llvm::cl::opt<OutputFormatTy> 109ac68cab9SJulie Hockett FormatEnum("format", llvm::cl::desc("Format for outputted docs."), 110ac68cab9SJulie Hockett llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml", 111ac68cab9SJulie Hockett "Documentation in YAML format."), 112ac68cab9SJulie Hockett clEnumValN(OutputFormatTy::md, "md", 113671bac74SJulie Hockett "Documentation in MD format."), 114671bac74SJulie Hockett clEnumValN(OutputFormatTy::html, "html", 115671bac74SJulie Hockett "Documentation in HTML format.")), 116ac68cab9SJulie Hockett llvm::cl::init(OutputFormatTy::yaml), 117ac68cab9SJulie Hockett llvm::cl::cat(ClangDocCategory)); 118d0f9a872SJulie Hockett 119229c63b0SJulie Hockett std::string getFormatString() { 120229c63b0SJulie Hockett switch (FormatEnum) { 121229c63b0SJulie Hockett case OutputFormatTy::yaml: 122229c63b0SJulie Hockett return "yaml"; 123229c63b0SJulie Hockett case OutputFormatTy::md: 124229c63b0SJulie Hockett return "md"; 125671bac74SJulie Hockett case OutputFormatTy::html: 126671bac74SJulie Hockett return "html"; 127229c63b0SJulie Hockett } 128229c63b0SJulie Hockett llvm_unreachable("Unknown OutputFormatTy"); 129229c63b0SJulie Hockett } 130e975a473SJulie Hockett 131db5d8e3dSDiego Astiazaran // This function isn't referenced outside its translation unit, but it 132db5d8e3dSDiego Astiazaran // can't use the "static" keyword because its address is used for 133db5d8e3dSDiego Astiazaran // GetMainExecutable (since some platforms don't support taking the 134db5d8e3dSDiego Astiazaran // address of main, and some platforms can't implement GetMainExecutable 135db5d8e3dSDiego Astiazaran // without being given the address of a function in the main executable). 136f14ad744SPeterChou1 std::string getExecutablePath(const char *Argv0, void *MainAddr) { 137db5d8e3dSDiego Astiazaran return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); 138db5d8e3dSDiego Astiazaran } 139db5d8e3dSDiego Astiazaran 140f14ad744SPeterChou1 llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) { 141f14ad744SPeterChou1 using DirIt = llvm::sys::fs::directory_iterator; 142f14ad744SPeterChou1 std::error_code FileErr; 143f14ad744SPeterChou1 llvm::SmallString<128> FilePath(UserAssetPath); 144f14ad744SPeterChou1 for (DirIt DirStart = DirIt(UserAssetPath, FileErr), 145f14ad744SPeterChou1 DirEnd; 146f14ad744SPeterChou1 !FileErr && DirStart != DirEnd; DirStart.increment(FileErr)) { 147f14ad744SPeterChou1 FilePath = DirStart->path(); 148f14ad744SPeterChou1 if (llvm::sys::fs::is_regular_file(FilePath)) { 149f14ad744SPeterChou1 if (llvm::sys::path::extension(FilePath) == ".css") 150f14ad744SPeterChou1 CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), 151f14ad744SPeterChou1 std::string(FilePath)); 152f14ad744SPeterChou1 else if (llvm::sys::path::extension(FilePath) == ".js") 153f14ad744SPeterChou1 CDCtx.JsScripts.emplace_back(FilePath.str()); 154f14ad744SPeterChou1 } 155f14ad744SPeterChou1 } 156f14ad744SPeterChou1 if (FileErr) 157f14ad744SPeterChou1 return llvm::createFileError(FilePath, FileErr); 158f14ad744SPeterChou1 return llvm::Error::success(); 159f14ad744SPeterChou1 } 160f14ad744SPeterChou1 161f14ad744SPeterChou1 llvm::Error getDefaultAssetFiles(const char *Argv0, 162f14ad744SPeterChou1 clang::doc::ClangDocContext &CDCtx) { 163f14ad744SPeterChou1 void *MainAddr = (void *)(intptr_t)getExecutablePath; 164f14ad744SPeterChou1 std::string ClangDocPath = getExecutablePath(Argv0, MainAddr); 165f14ad744SPeterChou1 llvm::SmallString<128> NativeClangDocPath; 166f14ad744SPeterChou1 llvm::sys::path::native(ClangDocPath, NativeClangDocPath); 167f14ad744SPeterChou1 168f14ad744SPeterChou1 llvm::SmallString<128> AssetsPath; 169f14ad744SPeterChou1 AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); 170f14ad744SPeterChou1 llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc"); 171f14ad744SPeterChou1 llvm::SmallString<128> DefaultStylesheet; 172f14ad744SPeterChou1 llvm::sys::path::native(AssetsPath, DefaultStylesheet); 173f14ad744SPeterChou1 llvm::sys::path::append(DefaultStylesheet, 174f14ad744SPeterChou1 "clang-doc-default-stylesheet.css"); 175f14ad744SPeterChou1 llvm::SmallString<128> IndexJS; 176f14ad744SPeterChou1 llvm::sys::path::native(AssetsPath, IndexJS); 177f14ad744SPeterChou1 llvm::sys::path::append(IndexJS, "index.js"); 178f14ad744SPeterChou1 179f14ad744SPeterChou1 if (!llvm::sys::fs::is_regular_file(IndexJS)) 180f14ad744SPeterChou1 return llvm::createStringError(llvm::inconvertibleErrorCode(), 181f14ad744SPeterChou1 "default index.js file missing at " + 182f14ad744SPeterChou1 IndexJS + "\n"); 183f14ad744SPeterChou1 184f14ad744SPeterChou1 if (!llvm::sys::fs::is_regular_file(DefaultStylesheet)) 185f14ad744SPeterChou1 return llvm::createStringError( 186f14ad744SPeterChou1 llvm::inconvertibleErrorCode(), 187f14ad744SPeterChou1 "default clang-doc-default-stylesheet.css file missing at " + 188f14ad744SPeterChou1 DefaultStylesheet + "\n"); 189f14ad744SPeterChou1 190f14ad744SPeterChou1 CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), 191f14ad744SPeterChou1 std::string(DefaultStylesheet)); 192f14ad744SPeterChou1 CDCtx.JsScripts.emplace_back(IndexJS.str()); 193f14ad744SPeterChou1 194f14ad744SPeterChou1 return llvm::Error::success(); 195f14ad744SPeterChou1 } 196f14ad744SPeterChou1 197f14ad744SPeterChou1 llvm::Error getHtmlAssetFiles(const char *Argv0, 198f14ad744SPeterChou1 clang::doc::ClangDocContext &CDCtx) { 199f14ad744SPeterChou1 if (!UserAssetPath.empty() && 200f14ad744SPeterChou1 !llvm::sys::fs::is_directory(std::string(UserAssetPath))) 201f14ad744SPeterChou1 llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath 202f14ad744SPeterChou1 << " falling back to default\n"; 203f14ad744SPeterChou1 if (llvm::sys::fs::is_directory(std::string(UserAssetPath))) 204f14ad744SPeterChou1 return getAssetFiles(CDCtx); 205f14ad744SPeterChou1 return getDefaultAssetFiles(Argv0, CDCtx); 206f14ad744SPeterChou1 } 207f14ad744SPeterChou1 2083c9e3457SPeterChou1 /// Make the output of clang-doc deterministic by sorting the children of 2093c9e3457SPeterChou1 /// namespaces and records. 2103c9e3457SPeterChou1 void sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) { 2113c9e3457SPeterChou1 for (auto &I : USRToInfo) { 2123c9e3457SPeterChou1 auto &Info = I.second; 2133c9e3457SPeterChou1 if (Info->IT == doc::InfoType::IT_namespace) { 2143c9e3457SPeterChou1 auto *Namespace = static_cast<clang::doc::NamespaceInfo *>(Info.get()); 2153c9e3457SPeterChou1 Namespace->Children.sort(); 2163c9e3457SPeterChou1 } 2173c9e3457SPeterChou1 if (Info->IT == doc::InfoType::IT_record) { 2183c9e3457SPeterChou1 auto *Record = static_cast<clang::doc::RecordInfo *>(Info.get()); 2193c9e3457SPeterChou1 Record->Children.sort(); 2203c9e3457SPeterChou1 } 2213c9e3457SPeterChou1 } 2223c9e3457SPeterChou1 } 2233c9e3457SPeterChou1 224e975a473SJulie Hockett int main(int argc, const char **argv) { 2256f773205SNico Weber llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); 226e78f3018SJulie Hockett std::error_code OK; 227e78f3018SJulie Hockett 228ea50901aSPetr Hosek const char *Overview = 229ea50901aSPetr Hosek R"(Generates documentation from source code and comments. 230e975a473SJulie Hockett 231ea50901aSPetr Hosek Example usage for files without flags (default): 232ea50901aSPetr Hosek 233ea50901aSPetr Hosek $ clang-doc File1.cpp File2.cpp ... FileN.cpp 234ea50901aSPetr Hosek 235ea50901aSPetr Hosek Example usage for a project using a compile commands database: 236ea50901aSPetr Hosek 237ea50901aSPetr Hosek $ clang-doc --executor=all-TUs compile_commands.json 238ea50901aSPetr Hosek )"; 239ea50901aSPetr Hosek 240ea50901aSPetr Hosek auto Executor = clang::tooling::createExecutorFromCommandLineArgs( 241ea50901aSPetr Hosek argc, argv, ClangDocCategory, Overview); 242ea50901aSPetr Hosek 243ea50901aSPetr Hosek if (!Executor) { 244ea50901aSPetr Hosek llvm::errs() << toString(Executor.takeError()) << "\n"; 245e975a473SJulie Hockett return 1; 246e975a473SJulie Hockett } 247e975a473SJulie Hockett 248ac68cab9SJulie Hockett // Fail early if an invalid format was provided. 249ac68cab9SJulie Hockett std::string Format = getFormatString(); 250ac68cab9SJulie Hockett llvm::outs() << "Emiting docs in " << Format << " format.\n"; 251ac68cab9SJulie Hockett auto G = doc::findGeneratorByName(Format); 252ac68cab9SJulie Hockett if (!G) { 253ac68cab9SJulie Hockett llvm::errs() << toString(G.takeError()) << "\n"; 254ac68cab9SJulie Hockett return 1; 255ac68cab9SJulie Hockett } 256ac68cab9SJulie Hockett 257e975a473SJulie Hockett ArgumentsAdjuster ArgAdjuster; 258e975a473SJulie Hockett if (!DoxygenOnly) 259e975a473SJulie Hockett ArgAdjuster = combineAdjusters( 260e975a473SJulie Hockett getInsertArgumentAdjuster("-fparse-all-comments", 261e975a473SJulie Hockett tooling::ArgumentInsertPosition::END), 262e975a473SJulie Hockett ArgAdjuster); 263e975a473SJulie Hockett 264acd35f6cSDiego Astiazaran clang::doc::ClangDocContext CDCtx = { 265ea50901aSPetr Hosek Executor->get()->getExecutionContext(), 2663550da79SDiego Astiazaran ProjectName, 267acd35f6cSDiego Astiazaran PublicOnly, 268acd35f6cSDiego Astiazaran OutDirectory, 26977dc05b9SDiego Astiazaran SourceRoot, 270665e9676SDiego Astiazaran RepositoryUrl, 27180d1c6acSPeterChou1 {UserStylesheets.begin(), UserStylesheets.end()} 27280d1c6acSPeterChou1 }; 273acd35f6cSDiego Astiazaran 274acd35f6cSDiego Astiazaran if (Format == "html") { 275f14ad744SPeterChou1 if (auto Err = getHtmlAssetFiles(argv[0], CDCtx)) { 276f14ad744SPeterChou1 llvm::errs() << toString(std::move(Err)) << "\n"; 277f14ad744SPeterChou1 return 1; 278f14ad744SPeterChou1 } 279acd35f6cSDiego Astiazaran } 280acd35f6cSDiego Astiazaran 281acd35f6cSDiego Astiazaran // Mapping phase 282acd35f6cSDiego Astiazaran llvm::outs() << "Mapping decls...\n"; 283eb50a2e8SJulie Hockett auto Err = 284ea50901aSPetr Hosek Executor->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster); 285d0f9a872SJulie Hockett if (Err) { 2868fb7074dSDiego Astiazaran if (IgnoreMappingFailures) 2878fb7074dSDiego Astiazaran llvm::errs() << "Error mapping decls in files. Clang-doc will ignore " 2888fb7074dSDiego Astiazaran "these files and continue:\n" 2898fb7074dSDiego Astiazaran << toString(std::move(Err)) << "\n"; 2908fb7074dSDiego Astiazaran else { 291e975a473SJulie Hockett llvm::errs() << toString(std::move(Err)) << "\n"; 292d0f9a872SJulie Hockett return 1; 293d0f9a872SJulie Hockett } 2948fb7074dSDiego Astiazaran } 295e975a473SJulie Hockett 296d0f9a872SJulie Hockett // Collect values into output by key. 297d0f9a872SJulie Hockett // In ToolResults, the Key is the hashed USR and the value is the 298d0f9a872SJulie Hockett // bitcode-encoded representation of the Info object. 2998899c29bSJulie Hockett llvm::outs() << "Collecting infos...\n"; 3006ab28e8cSDiego Astiazaran llvm::StringMap<std::vector<StringRef>> USRToBitcode; 301ea50901aSPetr Hosek Executor->get()->getToolResults()->forEachResult( 3026ab28e8cSDiego Astiazaran [&](StringRef Key, StringRef Value) { 303*b43cfa7eSKazu Hirata USRToBitcode[Key].emplace_back(Value); 3046ab28e8cSDiego Astiazaran }); 305a9cb2dd8SJulie Hockett 3067b8c7e02SBrett Wilson // Collects all Infos according to their unique USR value. This map is added 3077b8c7e02SBrett Wilson // to from the thread pool below and is protected by the USRToInfoMutex. 3087b8c7e02SBrett Wilson llvm::sys::Mutex USRToInfoMutex; 3097b8c7e02SBrett Wilson llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo; 3107b8c7e02SBrett Wilson 3118899c29bSJulie Hockett // First reducing phase (reduce all decls into one info per decl). 3126ab28e8cSDiego Astiazaran llvm::outs() << "Reducing " << USRToBitcode.size() << " infos...\n"; 3136ab28e8cSDiego Astiazaran std::atomic<bool> Error; 3146ab28e8cSDiego Astiazaran Error = false; 315e2d45770SDiego Astiazaran llvm::sys::Mutex IndexMutex; 3166ab28e8cSDiego Astiazaran // ExecutorConcurrency is a flag exposed by AllTUsExecution.h 317716042a6SMehdi Amini llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency)); 3186ab28e8cSDiego Astiazaran for (auto &Group : USRToBitcode) { 3196ab28e8cSDiego Astiazaran Pool.async([&]() { 3207868c04dSPeterChou1 std::vector<std::unique_ptr<doc::Info>> Infos; 3216ab28e8cSDiego Astiazaran for (auto &Bitcode : Group.getValue()) { 3226ab28e8cSDiego Astiazaran llvm::BitstreamCursor Stream(Bitcode); 3236ab28e8cSDiego Astiazaran doc::ClangDocBitcodeReader Reader(Stream); 3246ab28e8cSDiego Astiazaran auto ReadInfos = Reader.readBitcode(); 3256ab28e8cSDiego Astiazaran if (!ReadInfos) { 3266ab28e8cSDiego Astiazaran llvm::errs() << toString(ReadInfos.takeError()) << "\n"; 3276ab28e8cSDiego Astiazaran Error = true; 3286ab28e8cSDiego Astiazaran return; 3296ab28e8cSDiego Astiazaran } 3306ab28e8cSDiego Astiazaran std::move(ReadInfos->begin(), ReadInfos->end(), 3316ab28e8cSDiego Astiazaran std::back_inserter(Infos)); 3326ab28e8cSDiego Astiazaran } 3336ab28e8cSDiego Astiazaran 3346ab28e8cSDiego Astiazaran auto Reduced = doc::mergeInfos(Infos); 3358899c29bSJulie Hockett if (!Reduced) { 336a9cb2dd8SJulie Hockett llvm::errs() << llvm::toString(Reduced.takeError()); 3376ab28e8cSDiego Astiazaran return; 3388899c29bSJulie Hockett } 339d0f9a872SJulie Hockett 34048bb1471SPaul Kirth // Add a reference to this Info in the Index 3417b8c7e02SBrett Wilson { 342c9951209SPetr Hosek std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex); 3437b8c7e02SBrett Wilson clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get().get()); 3447b8c7e02SBrett Wilson } 3457868c04dSPeterChou1 34680d1c6acSPeterChou1 // Save in the result map (needs a lock due to threaded access). 3477b8c7e02SBrett Wilson { 348c9951209SPetr Hosek std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex); 3497b8c7e02SBrett Wilson USRToInfo[Group.getKey()] = std::move(Reduced.get()); 3507b8c7e02SBrett Wilson } 3516ab28e8cSDiego Astiazaran }); 352e975a473SJulie Hockett } 353e975a473SJulie Hockett 3546ab28e8cSDiego Astiazaran Pool.wait(); 3556ab28e8cSDiego Astiazaran 3566ab28e8cSDiego Astiazaran if (Error) 3576ab28e8cSDiego Astiazaran return 1; 3586ab28e8cSDiego Astiazaran 3593c9e3457SPeterChou1 sortUsrToInfo(USRToInfo); 3603c9e3457SPeterChou1 3617b8c7e02SBrett Wilson // Ensure the root output directory exists. 3627b8c7e02SBrett Wilson if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory); 3637b8c7e02SBrett Wilson Err != std::error_code()) { 3647b8c7e02SBrett Wilson llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n"; 3657b8c7e02SBrett Wilson return 1; 3667b8c7e02SBrett Wilson } 3677b8c7e02SBrett Wilson 3687b8c7e02SBrett Wilson // Run the generator. 3697b8c7e02SBrett Wilson llvm::outs() << "Generating docs...\n"; 3707b8c7e02SBrett Wilson if (auto Err = 3717b8c7e02SBrett Wilson G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) { 3727b8c7e02SBrett Wilson llvm::errs() << toString(std::move(Err)) << "\n"; 3737b8c7e02SBrett Wilson return 1; 3747b8c7e02SBrett Wilson } 3757b8c7e02SBrett Wilson 3767dfe0bc3SDiego Astiazaran llvm::outs() << "Generating assets for docs...\n"; 37772e1f7f9SJulie Hockett Err = G->get()->createResources(CDCtx); 37872e1f7f9SJulie Hockett if (Err) { 37970ec8419SPeterChou1 llvm::outs() << "warning: " << toString(std::move(Err)) << "\n"; 38072e1f7f9SJulie Hockett } 381db5d8e3dSDiego Astiazaran 382e975a473SJulie Hockett return 0; 383e975a473SJulie Hockett } 384