Skip to content

Commit ff94ba6

Browse files
authored
[clang-doc] Refactor error handling to use ExitOnError (#141699)
This patch refactors the clang-doc tool to replace manual error handling (e.g., checking error codes and calling exit()) with llvm::ExitOnError. Fixes #140085
1 parent 7a80a8b commit ff94ba6

File tree

2 files changed

+63
-49
lines changed

2 files changed

+63
-49
lines changed

clang-tools-extra/clang-doc/tool/ClangDocMain.cpp

Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ static llvm::cl::opt<OutputFormatTy> FormatEnum(
118118
"Documentation in mustache HTML format")),
119119
llvm::cl::init(OutputFormatTy::yaml), llvm::cl::cat(ClangDocCategory));
120120

121+
static llvm::ExitOnError ExitOnErr;
122+
121123
static std::string getFormatString() {
122124
switch (FormatEnum) {
123125
case OutputFormatTy::yaml:
@@ -245,10 +247,30 @@ sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> &USRToInfo) {
245247
}
246248
}
247249

250+
static llvm::Error handleMappingFailures(llvm::Error Err) {
251+
if (!Err)
252+
return llvm::Error::success();
253+
if (IgnoreMappingFailures) {
254+
llvm::errs() << "Error mapping decls in files. Clang-doc will ignore these "
255+
"files and continue:\n"
256+
<< toString(std::move(Err)) << "\n";
257+
return llvm::Error::success();
258+
}
259+
return Err;
260+
}
261+
262+
static llvm::Error createDirectories(llvm::StringRef OutDirectory) {
263+
if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory))
264+
return llvm::createFileError(OutDirectory, Err);
265+
return llvm::Error::success();
266+
}
267+
248268
int main(int argc, const char **argv) {
249269
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
250270
std::error_code OK;
251271

272+
ExitOnErr.setBanner("clang-doc error: ");
273+
252274
const char *Overview =
253275
R"(Generates documentation from source code and comments.
254276
@@ -261,22 +283,13 @@ Example usage for a project using a compile commands database:
261283
$ clang-doc --executor=all-TUs compile_commands.json
262284
)";
263285

264-
auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
265-
argc, argv, ClangDocCategory, Overview);
266-
267-
if (!Executor) {
268-
llvm::errs() << toString(Executor.takeError()) << "\n";
269-
return 1;
270-
}
286+
auto Executor = ExitOnErr(clang::tooling::createExecutorFromCommandLineArgs(
287+
argc, argv, ClangDocCategory, Overview));
271288

272289
// Fail early if an invalid format was provided.
273290
std::string Format = getFormatString();
274291
llvm::outs() << "Emiting docs in " << Format << " format.\n";
275-
auto G = doc::findGeneratorByName(Format);
276-
if (!G) {
277-
llvm::errs() << toString(G.takeError()) << "\n";
278-
return 1;
279-
}
292+
auto G = ExitOnErr(doc::findGeneratorByName(Format));
280293

281294
ArgumentsAdjuster ArgAdjuster;
282295
if (!DoxygenOnly)
@@ -286,7 +299,7 @@ Example usage for a project using a compile commands database:
286299
ArgAdjuster);
287300

288301
clang::doc::ClangDocContext CDCtx = {
289-
Executor->get()->getExecutionContext(),
302+
Executor->getExecutionContext(),
290303
ProjectName,
291304
PublicOnly,
292305
OutDirectory,
@@ -297,40 +310,24 @@ Example usage for a project using a compile commands database:
297310
{UserStylesheets.begin(), UserStylesheets.end()}};
298311

299312
if (Format == "html") {
300-
if (auto Err = getHtmlAssetFiles(argv[0], CDCtx)) {
301-
llvm::errs() << toString(std::move(Err)) << "\n";
302-
return 1;
303-
}
313+
ExitOnErr(getHtmlAssetFiles(argv[0], CDCtx));
304314
}
305315

306316
if (Format == "mustache") {
307-
if (auto Err = getMustacheHtmlFiles(argv[0], CDCtx)) {
308-
llvm::errs() << toString(std::move(Err)) << "\n";
309-
return 1;
310-
}
317+
ExitOnErr(getMustacheHtmlFiles(argv[0], CDCtx));
311318
}
312319

313320
// Mapping phase
314321
llvm::outs() << "Mapping decls...\n";
315-
auto Err =
316-
Executor->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster);
317-
if (Err) {
318-
if (IgnoreMappingFailures)
319-
llvm::errs() << "Error mapping decls in files. Clang-doc will ignore "
320-
"these files and continue:\n"
321-
<< toString(std::move(Err)) << "\n";
322-
else {
323-
llvm::errs() << toString(std::move(Err)) << "\n";
324-
return 1;
325-
}
326-
}
322+
ExitOnErr(handleMappingFailures(
323+
Executor->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster)));
327324

328325
// Collect values into output by key.
329326
// In ToolResults, the Key is the hashed USR and the value is the
330327
// bitcode-encoded representation of the Info object.
331328
llvm::outs() << "Collecting infos...\n";
332329
llvm::StringMap<std::vector<StringRef>> USRToBitcode;
333-
Executor->get()->getToolResults()->forEachResult(
330+
Executor->getToolResults()->forEachResult(
334331
[&](StringRef Key, StringRef Value) {
335332
USRToBitcode[Key].emplace_back(Value);
336333
});
@@ -391,25 +388,13 @@ Example usage for a project using a compile commands database:
391388
sortUsrToInfo(USRToInfo);
392389

393390
// Ensure the root output directory exists.
394-
if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory);
395-
Err != std::error_code()) {
396-
llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n";
397-
return 1;
398-
}
391+
ExitOnErr(createDirectories(OutDirectory));
399392

400393
// Run the generator.
401394
llvm::outs() << "Generating docs...\n";
402-
if (auto Err =
403-
G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) {
404-
llvm::errs() << toString(std::move(Err)) << "\n";
405-
return 1;
406-
}
407-
395+
ExitOnErr(G->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx));
408396
llvm::outs() << "Generating assets for docs...\n";
409-
Err = G->get()->createResources(CDCtx);
410-
if (Err) {
411-
llvm::outs() << "warning: " << toString(std::move(Err)) << "\n";
412-
}
397+
ExitOnErr(G->createResources(CDCtx));
413398

414399
return 0;
415400
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/// Invalid output path (%t is a file, not a directory).
2+
// RUN: rm -rf %t && touch %t
3+
// RUN: not clang-doc %s -output=%t/subdir 2>&1 | FileCheck %s --check-prefix=OUTPUT-FAIL
4+
// OUTPUT-FAIL: clang-doc error:
5+
// OUTPUT-FAIL: {{(Not a directory|no such file or directory)}}
6+
7+
/// Invalid format option.
8+
// RUN: rm -rf %t && mkdir %t && touch %t/file
9+
// RUN: not clang-doc %s --output=%t/file -format=badformat 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
10+
// BAD-FORMAT: clang-doc: for the --format option: Cannot find option named 'badformat'!
11+
12+
/// Missing HTML asset directory (warning only).
13+
// RUN: clang-doc %s -format=html -asset=%t/nonexistent-assets 2>&1 | FileCheck %s --check-prefix=ASSET-WARN
14+
// ASSET-WARN: Asset path supply is not a directory
15+
16+
/// Mapping failure (with --ignore-map-errors=false).
17+
// RUN: not clang-doc %t/nonexistent.cpp -ignore-map-errors=false 2>&1 | FileCheck %s --check-prefix=MAP-FAIL
18+
// MAP-FAIL: clang-doc error: Failed to run action
19+
20+
/// Mapping failure (with --ignore-map-errors=true).
21+
// RUN: clang-doc %t/nonexistent.cpp 2>&1 | FileCheck %s --check-prefix=MAP-WARN
22+
// MAP-WARN: Error mapping decls in files. Clang-doc will ignore these files and continue
23+
24+
///Invalid executor type
25+
// RUN: not clang-doc --executor=invalid %s 2>&1 | FileCheck %s --check-prefix=EXECUTOR-FAIL
26+
// EXECUTOR-FAIL: clang-doc error:
27+
// EXECUTOR-FAIL: Executor "invalid" is not registered
28+
29+
///TODO: Add tests for failures in generateDocs() and in createResources().

0 commit comments

Comments
 (0)