Index: include/clang/Tooling/CommonOptionsParser.h =================================================================== --- include/clang/Tooling/CommonOptionsParser.h +++ include/clang/Tooling/CommonOptionsParser.h @@ -30,6 +30,7 @@ #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" namespace clang { namespace tooling { @@ -86,13 +87,16 @@ /// All options not belonging to \p Category become hidden. /// /// It also allows calls to set the required number of positional parameters. - /// - /// This constructor exits program in case of error. CommonOptionsParser(int &argc, const char **argv, llvm::cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview = nullptr); + static llvm::Expected> + create(int &argc, const char **argv, llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview = nullptr); + /// Returns a reference to the loaded compilations database. CompilationDatabase &getCompilations() { return *Compilations; @@ -106,6 +110,13 @@ static const char *const HelpMessage; private: + CommonOptionsParser() = default; + + static llvm::Error init(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview, CommonOptionsParser *Parser); + std::unique_ptr Compilations; std::vector SourcePathList; }; Index: lib/Tooling/CommonOptionsParser.cpp =================================================================== --- lib/Tooling/CommonOptionsParser.cpp +++ lib/Tooling/CommonOptionsParser.cpp @@ -24,9 +24,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/CommandLine.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" +#include "llvm/Support/CommandLine.h" using namespace clang::tooling; using namespace llvm; @@ -81,9 +81,11 @@ return Commands; } -CommonOptionsParser::CommonOptionsParser( - int &argc, const char **argv, cl::OptionCategory &Category, - llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { +llvm::Error +CommonOptionsParser::init(int &argc, const char **argv, + cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview, CommonOptionsParser *Parser) { static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden, cl::sub(*cl::AllSubCommands)); @@ -105,41 +107,76 @@ cl::desc("Additional argument to prepend to the compiler command line"), cl::cat(Category), cl::sub(*cl::AllSubCommands)); + cl::ResetAllOptionOccurrences(); + cl::HideUnrelatedOptions(Category); std::string ErrorMessage; - Compilations = + Parser->Compilations = FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); - if (!Compilations && !ErrorMessage.empty()) - llvm::errs() << ErrorMessage; - cl::ParseCommandLineOptions(argc, argv, Overview); + if (!ErrorMessage.empty()) + ErrorMessage.append("\n"); + llvm::raw_string_ostream OS(ErrorMessage); + // Stop initializing if command-line option parsing failed. + if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) { + OS.flush(); + return llvm::make_error("[CommonOptionsParser]: " + + ErrorMessage, + llvm::inconvertibleErrorCode()); + } + cl::PrintOptionValues(); - SourcePathList = SourcePaths; + Parser->SourcePathList = SourcePaths; if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) && - SourcePathList.empty()) - return; - if (!Compilations) { + Parser->SourcePathList.empty()) + return llvm::Error::success(); + if (!Parser->Compilations) { if (!BuildPath.empty()) { - Compilations = + Parser->Compilations = CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage); } else { - Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0], - ErrorMessage); + Parser->Compilations = CompilationDatabase::autoDetectFromSource( + SourcePaths[0], ErrorMessage); } - if (!Compilations) { + if (!Parser->Compilations) { llvm::errs() << "Error while trying to load a compilation database:\n" << ErrorMessage << "Running without flags.\n"; - Compilations.reset( + Parser->Compilations.reset( new FixedCompilationDatabase(".", std::vector())); } } auto AdjustingCompilations = llvm::make_unique( - std::move(Compilations)); + std::move(Parser->Compilations)); AdjustingCompilations->appendArgumentsAdjuster( getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN)); AdjustingCompilations->appendArgumentsAdjuster( getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END)); - Compilations = std::move(AdjustingCompilations); + Parser->Compilations = std::move(AdjustingCompilations); + return llvm::Error::success(); +} + +llvm::Expected> +CommonOptionsParser::create(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview) { + std::unique_ptr Parser(new CommonOptionsParser); + llvm::Error Err = + init(argc, argv, Category, OccurrencesFlag, Overview, Parser.get()); + if (Err) + return std::move(Err); + return Parser; +} + +CommonOptionsParser::CommonOptionsParser( + int &argc, const char **argv, cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { + llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview, this); + if (Err) { + llvm::report_fatal_error( + "CommonOptionsParser: failed to parse command-line arguments. " + + llvm::toString(std::move(Err))); + } }