Adds a FixedCompilationDatabase to be able to specify tool parameters

at the command line.

llvm-svn: 154989
This commit is contained in:
Manuel Klimek 2012-04-18 07:41:50 +00:00
parent 4d4d025751
commit ff26efceb4
5 changed files with 170 additions and 9 deletions

View File

@ -33,6 +33,7 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
@ -45,8 +46,8 @@ namespace tooling {
/// \brief Specifies the working directory and command of a compilation.
struct CompileCommand {
CompileCommand() {}
CompileCommand(StringRef Directory, ArrayRef<std::string> CommandLine)
: Directory(Directory), CommandLine(CommandLine) {}
CompileCommand(Twine Directory, ArrayRef<std::string> CommandLine)
: Directory(Directory.str()), CommandLine(CommandLine) {}
/// \brief The working directory the command was executed from.
std::string Directory;
@ -93,6 +94,59 @@ public:
StringRef FilePath) const = 0;
};
/// \brief A compilation database that returns a single compile command line.
///
/// Useful when we want a tool to behave more like a compiler invocation.
class FixedCompilationDatabase : public CompilationDatabase {
public:
/// \brief Creates a FixedCompilationDatabase from the arguments after "--".
///
/// Parses the given command line for "--". If "--" is found, the rest of
/// the arguments will make up the command line in the returned
/// FixedCompilationDatabase.
/// The arguments after "--" must not include positional parameters or the
/// argv[0] of the tool. Those will be added by the FixedCompilationDatabase
/// when a CompileCommand is requested. The argv[0] of the returned command
/// line will be "clang-tool".
///
/// Returns NULL in case "--" is not found.
///
/// The argument list is meant to be compatible with normal llvm command line
/// parsing in main methods.
/// int main(int argc, char **argv) {
/// llvm::OwningPtr<FixedCompilationDatabase> Compilations(
/// FixedCompilationDatabase::loadFromCommandLine(argc, argv));
/// cl::ParseCommandLineOptions(argc, argv);
/// ...
/// }
///
/// \param Argc The number of command line arguments - will be changed to
/// the number of arguments before "--", if "--" was found in the argument
/// list.
/// \param Argv Points to the command line arguments.
/// \param Directory The base directory used in the FixedCompilationDatabase.
static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
const char **Argv,
Twine Directory = ".");
/// \brief Constructs a compilation data base from a specified directory
/// and command line.
FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine);
/// \brief Returns the given compile command.
///
/// Will always return a vector with one entry that contains the directory
/// and command line specified at construction with "clang-tool" as argv[0]
/// and 'FilePath' as positional argument.
virtual std::vector<CompileCommand> getCompileCommands(
StringRef FilePath) const;
private:
/// This is built up to contain a single entry vector to be returned from
/// getCompileCommands after adding the positional argument.
std::vector<CompileCommand> CompileCommands;
};
/// \brief A JSON based compilation database.
///
/// JSON compilation database files must contain a list of JSON objects which
@ -112,7 +166,6 @@ public:
/// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS.
class JSONCompilationDatabase : public CompilationDatabase {
public:
/// \brief Loads a JSON compilation database from the specified file.
///
/// Returns NULL and sets ErrorMessage if the database could not be

View File

@ -121,6 +121,33 @@ CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
return Database.take();
}
FixedCompilationDatabase *
FixedCompilationDatabase::loadFromCommandLine(int &Argc,
const char **Argv,
Twine Directory) {
const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
if (DoubleDash == Argv + Argc)
return NULL;
std::vector<std::string> CommandLine(DoubleDash + 1, Argv + Argc);
Argc = DoubleDash - Argv;
return new FixedCompilationDatabase(Directory, CommandLine);
}
FixedCompilationDatabase::
FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
std::vector<std::string> ToolCommandLine(1, "clang-tool");
ToolCommandLine.insert(ToolCommandLine.end(),
CommandLine.begin(), CommandLine.end());
CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine));
}
std::vector<CompileCommand>
FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
std::vector<CompileCommand> Result(CompileCommands);
Result[0].CommandLine.push_back(FilePath);
return Result;
}
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
std::string &ErrorMessage) {

View File

@ -0,0 +1,8 @@
// RUN: clang-check . "%s" -- -c 2>&1 | FileCheck %s
// CHECK: C++ requires
invalid;
// FIXME: JSON doesn't like path separator '\', on Win32 hosts.
// FIXME: clang-check doesn't like gcc driver on cygming.
// XFAIL: cygwin,mingw32,win32

View File

@ -50,13 +50,17 @@ cl::list<std::string> SourcePaths(
cl::desc("<source0> [... <sourceN>]"),
cl::OneOrMore);
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
std::string ErrorMessage;
int main(int argc, const char **argv) {
llvm::OwningPtr<CompilationDatabase> Compilations(
CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
std::string ErrorMessage;
Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
ErrorMessage));
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
ClangTool Tool(*Compilations, SourcePaths);
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
}

View File

@ -219,5 +219,74 @@ TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
EXPECT_EQ("", Empty[0]);
}
TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
std::vector<std::string> CommandLine;
CommandLine.push_back("one");
CommandLine.push_back("two");
FixedCompilationDatabase Database(".", CommandLine);
std::vector<CompileCommand> Result =
Database.getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
std::vector<std::string> ExpectedCommandLine(1, "clang-tool");
ExpectedCommandLine.insert(ExpectedCommandLine.end(),
CommandLine.begin(), CommandLine.end());
ExpectedCommandLine.push_back("source");
EXPECT_EQ(".", Result[0].Directory);
EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine);
}
TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
int Argc = 0;
llvm::OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, NULL));
EXPECT_FALSE(Database);
EXPECT_EQ(0, Argc);
}
TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
int Argc = 2;
const char *Argv[] = { "1", "2" };
llvm::OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
EXPECT_FALSE(Database);
EXPECT_EQ(2, Argc);
}
TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
int Argc = 5;
const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" };
llvm::OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
ASSERT_TRUE(Database);
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
ASSERT_EQ(".", Result[0].Directory);
std::vector<std::string> CommandLine;
CommandLine.push_back("clang-tool");
CommandLine.push_back("3");
CommandLine.push_back("4");
CommandLine.push_back("source");
ASSERT_EQ(CommandLine, Result[0].CommandLine);
EXPECT_EQ(2, Argc);
}
TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
int Argc = 3;
const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
llvm::OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
ASSERT_TRUE(Database);
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
ASSERT_EQ(".", Result[0].Directory);
std::vector<std::string> CommandLine;
CommandLine.push_back("clang-tool");
CommandLine.push_back("source");
ASSERT_EQ(CommandLine, Result[0].CommandLine);
EXPECT_EQ(2, Argc);
}
} // end namespace tooling
} // end namespace clang