Index: lib/Tooling/CommonOptionsParser.cpp =================================================================== --- lib/Tooling/CommonOptionsParser.cpp +++ lib/Tooling/CommonOptionsParser.cpp @@ -25,6 +25,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/CommandLine.h" +#include "llvm/Support/StringSaver.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" @@ -116,6 +117,14 @@ cl::HideUnrelatedOptions(Category); + // Expand response files before loading compilation database from command line. + SmallVector NewArgv(argv, argv + argc); + BumpPtrAllocator A; + StringSaver Saver(A); + cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, NewArgv); + argv = &NewArgv[0]; + argc = static_cast(NewArgv.size()); + std::string ErrorMessage; Compilations = FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); Index: unittests/Tooling/CMakeLists.txt =================================================================== --- unittests/Tooling/CMakeLists.txt +++ unittests/Tooling/CMakeLists.txt @@ -14,6 +14,7 @@ CastExprTest.cpp CommentHandlerTest.cpp CompilationDatabaseTest.cpp + CommonOptionsParserTest.cpp DiagnosticsYamlTest.cpp FixItTest.cpp LookupTest.cpp Index: unittests/Tooling/CommonOptionsParserTest.cpp =================================================================== --- /dev/null +++ unittests/Tooling/CommonOptionsParserTest.cpp @@ -0,0 +1,72 @@ +//===- unittests/Tooling/CommonOptionsParserTest.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/CommonOptionsParser.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "gtest/gtest.h" + +#include + +namespace clang { +namespace tooling { + +class CommonOptionsParserTest : public testing::Test { +public: + SmallString<128> TestDir; + SmallString<128> ResponseFileName; + + CommonOptionsParserTest() { + std::error_code EC = llvm::sys::fs::createUniqueDirectory("unittest", TestDir); + EXPECT_TRUE(!EC); + llvm::sys::path::append(ResponseFileName, TestDir, "resp"); + } + + void setResponseFileContent(const std::string &Content) { + std::ofstream File(ResponseFileName.c_str()); + EXPECT_TRUE(File.is_open()); + File << Content; + File.close(); + } + + ~CommonOptionsParserTest() override { + llvm::sys::fs::remove(ResponseFileName); + llvm::sys::fs::remove(TestDir); + } +}; + +TEST_F(CommonOptionsParserTest, ExpandResponseFilesBeforeLoadingCompilationDatabase) { + setResponseFileContent("-- -a=true -b"); + SmallString<128> ResponseFileRef; + ResponseFileRef.append(1, '@'); + ResponseFileRef.append(ResponseFileName.c_str()); + int Argc = 3; + const char *Argv[] = { "1", "2", ResponseFileRef.c_str() }; + llvm::cl::OptionCategory Category("options"); + llvm::cl::opt option1("a", llvm::cl::desc(""), llvm::cl::init(false), + llvm::cl::cat(Category)); + llvm::cl::opt option2("b", llvm::cl::desc(""), llvm::cl::init(false), + llvm::cl::cat(Category)); + CommonOptionsParser Parser(Argc, Argv, Category); + CompilationDatabase &Database = Parser.getCompilations(); + std::vector ActualCC = Database.getCompileCommands("source"); + ASSERT_EQ(1u, ActualCC.size()); + std::vector ExpectedCmd; + ExpectedCmd.push_back("clang-tool"); + ExpectedCmd.push_back("-a=true"); + ExpectedCmd.push_back("-b"); + ExpectedCmd.push_back("source"); + + ASSERT_EQ(ExpectedCmd, ActualCC[0].CommandLine); +} + +} // end namespace tooling +} // end namespace clang