Index: include/clang/Tooling/CompilationDatabase.h =================================================================== --- include/clang/Tooling/CompilationDatabase.h +++ include/clang/Tooling/CompilationDatabase.h @@ -186,10 +186,11 @@ /// the number of arguments before "--", if "--" was found in the argument /// list. /// \param Argv Points to the command line arguments. + /// \param ErrorMsg Contains error text if the function returns null pointer. /// \param Directory The base directory used in the FixedCompilationDatabase. - static FixedCompilationDatabase *loadFromCommandLine(int &Argc, - const char *const *Argv, - Twine Directory = "."); + static std::unique_ptr loadFromCommandLine( + int &Argc, const char *const *Argv, std::string &ErrorMsg, + Twine Directory = "."); /// \brief Constructs a compilation data base from a specified directory /// and command line. Index: lib/Frontend/CreateInvocationFromCommandLine.cpp =================================================================== --- lib/Frontend/CreateInvocationFromCommandLine.cpp +++ lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -52,6 +52,8 @@ TheDriver.setCheckInputsExist(false); std::unique_ptr C(TheDriver.BuildCompilation(Args)); + if (!C) + return nullptr; // Just print the cc1 options if -### was present. if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) { Index: lib/Tooling/CommonOptionsParser.cpp =================================================================== --- lib/Tooling/CommonOptionsParser.cpp +++ lib/Tooling/CommonOptionsParser.cpp @@ -116,7 +116,11 @@ cl::HideUnrelatedOptions(Category); - Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + std::string ErrorMessage; + Compilations = + FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); + if (!Compilations && !ErrorMessage.empty()) + llvm::errs() << ErrorMessage; cl::ParseCommandLineOptions(argc, argv, Overview); cl::PrintOptionValues(); @@ -125,7 +129,6 @@ SourcePathList.empty()) return; if (!Compilations) { - std::string ErrorMessage; if (!BuildPath.empty()) { Compilations = CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage); Index: lib/Tooling/CompilationDatabase.cpp =================================================================== --- lib/Tooling/CompilationDatabase.cpp +++ lib/Tooling/CompilationDatabase.cpp @@ -27,6 +27,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include #include using namespace clang; @@ -150,23 +151,21 @@ // options. class UnusedInputDiagConsumer : public DiagnosticConsumer { public: - UnusedInputDiagConsumer() : Other(nullptr) {} - - // Useful for debugging, chain diagnostics to another consumer after - // recording for our own purposes. - UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {} + UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {} void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override { if (Info.getID() == clang::diag::warn_drv_input_file_unused) { // Arg 1 for this diagnostic is the option that didn't get used. UnusedInputs.push_back(Info.getArgStdStr(0)); + } else if (DiagLevel >= DiagnosticsEngine::Error) { + // If driver failed to create compilation object, show the diagnostics + // to user. + Other.HandleDiagnostic(DiagLevel, Info); } - if (Other) - Other->HandleDiagnostic(DiagLevel, Info); } - DiagnosticConsumer *Other; + DiagnosticConsumer &Other; SmallVector UnusedInputs; }; @@ -205,9 +204,12 @@ /// \li false if \c Args cannot be used for compilation jobs (e.g. /// contains an option like -E or -version). static bool stripPositionalArgs(std::vector Args, - std::vector &Result) { + std::vector &Result, + std::string &ErrorMsg) { IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - UnusedInputDiagConsumer DiagClient; + llvm::raw_string_ostream Output(ErrorMsg); + TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts); + UnusedInputDiagConsumer DiagClient(DiagnosticPrinter); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, &DiagClient, false); @@ -245,6 +247,8 @@ const std::unique_ptr Compilation( NewDriver->BuildCompilation(Args)); + if (!Compilation) + return false; const driver::JobList &Jobs = Compilation->getJobs(); @@ -258,8 +262,7 @@ } if (CompileAnalyzer.Inputs.empty()) { - // No compile jobs found. - // FIXME: Emit a warning of some kind? + ErrorMsg = "warning: no compile jobs found\n"; return false; } @@ -280,8 +283,14 @@ return true; } -FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine( - int &Argc, const char *const *Argv, Twine Directory) { +std::unique_ptr +FixedCompilationDatabase::loadFromCommandLine(int &Argc, + const char *const *Argv, + std::string &ErrorMsg, + Twine Directory) { + ErrorMsg.clear(); + if (Argc == 0) + return nullptr; const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--")); if (DoubleDash == Argv + Argc) return nullptr; @@ -289,9 +298,10 @@ Argc = DoubleDash - Argv; std::vector StrippedArgs; - if (!stripPositionalArgs(CommandLine, StrippedArgs)) + if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg)) return nullptr; - return new FixedCompilationDatabase(Directory, StrippedArgs); + return std::unique_ptr( + new FixedCompilationDatabase(Directory, StrippedArgs)); } FixedCompilationDatabase:: Index: lib/Tooling/Tooling.cpp =================================================================== --- lib/Tooling/Tooling.cpp +++ lib/Tooling/Tooling.cpp @@ -260,6 +260,8 @@ Driver->setCheckInputsExist(false); const std::unique_ptr Compilation( Driver->BuildCompilation(llvm::makeArrayRef(Argv))); + if (!Compilation) + return false; const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments( &Diagnostics, Compilation.get()); if (!CC1Args) { Index: unittests/Tooling/CompilationDatabaseTest.cpp =================================================================== --- unittests/Tooling/CompilationDatabaseTest.cpp +++ unittests/Tooling/CompilationDatabaseTest.cpp @@ -504,18 +504,22 @@ TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) { int Argc = 0; - std::unique_ptr Database( - FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr)); + std::string ErrorMsg; + std::unique_ptr Database = + FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr, ErrorMsg); EXPECT_FALSE(Database); + EXPECT_TRUE(ErrorMsg.empty()); EXPECT_EQ(0, Argc); } TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) { int Argc = 2; const char *Argv[] = { "1", "2" }; + std::string ErrorMsg; std::unique_ptr Database( - FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg)); EXPECT_FALSE(Database); + EXPECT_TRUE(ErrorMsg.empty()); EXPECT_EQ(2, Argc); } @@ -524,9 +528,11 @@ const char *Argv[] = { "1", "2", "--\0no-constant-folding", "-DDEF3", "-DDEF4" }; + std::string ErrorMsg; std::unique_ptr Database( - FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg)); ASSERT_TRUE((bool)Database); + ASSERT_TRUE(ErrorMsg.empty()); std::vector Result = Database->getCompileCommands("source"); ASSERT_EQ(1ul, Result.size()); @@ -543,9 +549,11 @@ TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) { int Argc = 3; const char *Argv[] = { "1", "2", "--\0no-constant-folding" }; - std::unique_ptr Database( - FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + std::string ErrorMsg; + std::unique_ptr Database = + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg); ASSERT_TRUE((bool)Database); + ASSERT_TRUE(ErrorMsg.empty()); std::vector Result = Database->getCompileCommands("source"); ASSERT_EQ(1ul, Result.size()); @@ -560,9 +568,11 @@ TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) { const char *Argv[] = {"1", "2", "--", "-c", "somefile.cpp", "-DDEF3"}; int Argc = sizeof(Argv) / sizeof(char*); - std::unique_ptr Database( - FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + std::string ErrorMsg; + std::unique_ptr Database = + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg); ASSERT_TRUE((bool)Database); + ASSERT_TRUE(ErrorMsg.empty()); std::vector Result = Database->getCompileCommands("source"); ASSERT_EQ(1ul, Result.size()); @@ -579,9 +589,11 @@ TEST(ParseFixedCompilationDatabase, HandlesArgv0) { const char *Argv[] = {"1", "2", "--", "mytool", "somefile.cpp"}; int Argc = sizeof(Argv) / sizeof(char*); - std::unique_ptr Database( - FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + std::string ErrorMsg; + std::unique_ptr Database = + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg); ASSERT_TRUE((bool)Database); + ASSERT_TRUE(ErrorMsg.empty()); std::vector Result = Database->getCompileCommands("source"); ASSERT_EQ(1ul, Result.size());