aboutsummaryrefslogtreecommitdiff
path: root/lib/Tooling/Tooling.cpp
diff options
context:
space:
mode:
authorManuel Klimek <klimek@google.com>2011-06-02 16:58:33 +0000
committerManuel Klimek <klimek@google.com>2011-06-02 16:58:33 +0000
commit16f213142f8f8f5410672205a19f79ed3c232929 (patch)
treea11e620036d64fa4f97884a4ea22c26c06ee3b24 /lib/Tooling/Tooling.cpp
parentfb3f4aad0436a9c40e9130598162150890c405b5 (diff)
Reverts the Tooling changes as requested by Chris.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132462 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Tooling/Tooling.cpp')
-rw-r--r--lib/Tooling/Tooling.cpp403
1 files changed, 0 insertions, 403 deletions
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
deleted file mode 100644
index 97a9463852..0000000000
--- a/lib/Tooling/Tooling.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-//===--- Tooling.cpp - Running clang standalone tools ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements functions to run clang tools standalone instead
-// of running them as a plugin.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
-#include "clang/Basic/DiagnosticIDs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "JsonCompileCommandLineDatabase.h"
-#include <map>
-#include <cstdio>
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// Checks that the input conforms to the argv[] convention as in
-// main(). Namely:
-// - it must contain at least a program path,
-// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
-// - argv[argc] must be NULL.
-void ValidateArgv(int argc, char *argv[]) {
- if (argc < 1) {
- fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc);
- abort();
- }
-
- for (int i = 0; i < argc; ++i) {
- if (argv[i] == NULL) {
- fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i);
- abort();
- }
- }
-
- if (argv[argc] != NULL) {
- fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n");
- abort();
- }
-}
-
-} // end namespace
-
-// FIXME: This file contains structural duplication with other parts of the
-// code that sets up a compiler to run tools on it, and we should refactor
-// it to be based on the same framework.
-
-static clang::Diagnostic *NewTextDiagnostics() {
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
- new clang::DiagnosticIDs());
- clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(
- llvm::errs(), clang::DiagnosticOptions());
- return new clang::Diagnostic(DiagIDs, DiagClient);
-}
-
-// Exists solely for the purpose of lookup of the main executable.
-static int StaticSymbol;
-
-/// \brief Builds a clang driver initialized for running clang tools.
-static clang::driver::Driver *NewDriver(clang::Diagnostic *Diagnostics,
- const char *BinaryName) {
- // This just needs to be some symbol in the binary.
- void *const SymbolAddr = &StaticSymbol;
- const llvm::sys::Path ExePath =
- llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr);
-
- const std::string DefaultOutputName = "a.out";
- clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
- ExePath.str(), llvm::sys::getHostTriple(),
- DefaultOutputName, false, false, *Diagnostics);
- CompilerDriver->setTitle("clang_based_tool");
- return CompilerDriver;
-}
-
-/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
-/// Returns NULL on error.
-static const clang::driver::ArgStringList *GetCC1Arguments(
- clang::Diagnostic *Diagnostics, clang::driver::Compilation *Compilation) {
- // We expect to get back exactly one Command job, if we didn't something
- // failed. Extract that job from the Compilation.
- const clang::driver::JobList &Jobs = Compilation->getJobs();
- if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> error_msg;
- llvm::raw_svector_ostream error_stream(error_msg);
- Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
- Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
- << error_stream.str();
- return NULL;
- }
-
- // The one job we find should be to invoke clang again.
- const clang::driver::Command *Cmd =
- cast<clang::driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
- Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
- return NULL;
- }
-
- return &Cmd->getArguments();
-}
-
-/// \brief Returns a clang build invocation initialized from the CC1 flags.
-static clang::CompilerInvocation *NewInvocation(
- clang::Diagnostic *Diagnostics,
- const clang::driver::ArgStringList &CC1Args) {
- clang::CompilerInvocation *Invocation = new clang::CompilerInvocation;
- clang::CompilerInvocation::CreateFromArgs(
- *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(),
- *Diagnostics);
- Invocation->getFrontendOpts().DisableFree = false;
- return Invocation;
-}
-
-/// \brief Runs the specified clang tool action and returns whether it executed
-/// successfully.
-static bool RunInvocation(const char *BinaryName,
- clang::driver::Compilation *Compilation,
- clang::CompilerInvocation *Invocation,
- const clang::driver::ArgStringList &CC1Args,
- clang::FrontendAction *ToolAction) {
- llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
- // Show the invocation, with -v.
- if (Invocation->getHeaderSearchOpts().Verbose) {
- llvm::errs() << "clang Invocation:\n";
- Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
- llvm::errs() << "\n";
- }
-
- // Create a compiler instance to handle the actual work.
- clang::CompilerInstance Compiler;
- Compiler.setInvocation(Invocation);
-
- // Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics(CC1Args.size(),
- const_cast<char**>(CC1Args.data()));
- if (!Compiler.hasDiagnostics())
- return false;
-
- // Infer the builtin include path if unspecified.
- if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
- Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
- // This just needs to be some symbol in the binary.
- void *const SymbolAddr = &StaticSymbol;
- Compiler.getHeaderSearchOpts().ResourceDir =
- clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
- }
-
- const bool Success = Compiler.ExecuteAction(*ToolAction);
- return Success;
-}
-
-/// \brief Converts a string vector representing a Command line into a C
-/// string vector representing the Argv (including the trailing NULL).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string> *Command) {
- std::vector<char*> Result(Command->size() + 1);
- for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) {
- Result[I] = const_cast<char*>((*Command)[I].c_str());
- }
- Result[Command->size()] = NULL;
- return Result;
-}
-
-bool RunToolWithFlags(
- clang::FrontendAction *ToolAction, int Args, char *Argv[]) {
- ValidateArgv(Args, Argv);
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), Argv[0]));
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
- const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
- return RunInvocation(Argv[0], Compilation.get(), Invocation.take(),
- *CC1Args, ToolAction);
-}
-
-/// \brief Runs 'ToolAction' on the code specified by 'FileContents'.
-///
-/// \param FileContents A mapping from file name to source code. For each
-/// entry a virtual file mapping will be created when running the tool.
-bool RunToolWithFlagsOnCode(
- const std::vector<std::string> &CommandLine,
- const std::map<std::string, std::string> &FileContents,
- clang::FrontendAction *ToolAction) {
- const std::vector<char*> Argv = CommandLineToArgv(&CommandLine);
- const char *const BinaryName = Argv[0];
-
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), BinaryName));
-
- // Since the Input is only virtual, don't check whether it exists.
- Driver->setCheckInputsExist(false);
-
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0],
- Argv.size() - 1)));
- const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
-
- for (std::map<std::string, std::string>::const_iterator
- It = FileContents.begin(), End = FileContents.end();
- It != End; ++It) {
- // Inject the code as the given file name into the preprocessor options.
- const llvm::MemoryBuffer *Input =
- llvm::MemoryBuffer::getMemBuffer(It->second.c_str());
- Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input);
- }
-
- return RunInvocation(BinaryName, Compilation.get(),
- Invocation.take(), *CC1Args, ToolAction);
-}
-
-bool RunSyntaxOnlyToolOnCode(
- clang::FrontendAction *ToolAction, llvm::StringRef Code) {
- const char *const FileName = "input.cc";
- const char *const CommandLine[] = {
- "clang-tool", "-fsyntax-only", FileName
- };
- std::map<std::string, std::string> FileContents;
- FileContents[FileName] = Code;
- return RunToolWithFlagsOnCode(
- std::vector<std::string>(
- CommandLine,
- CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])),
- FileContents, ToolAction);
-}
-
-namespace {
-
-// A CompileCommandHandler implementation that finds compile commands for a
-// specific input file.
-//
-// FIXME: Implement early exit when JsonCompileCommandLineParser supports it.
-class FindHandler : public clang::tooling::CompileCommandHandler {
- public:
- explicit FindHandler(llvm::StringRef File)
- : FileToMatch(File), FoundMatchingCommand(false) {}
-
- virtual void EndTranslationUnits() {
- if (!FoundMatchingCommand && ErrorMessage.empty()) {
- ErrorMessage = "ERROR: No matching command found.";
- }
- }
-
- virtual void EndTranslationUnit() {
- if (File == FileToMatch) {
- FoundMatchingCommand = true;
- MatchingCommand.Directory = Directory;
- MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command);
- }
- }
-
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {
- if (Key == "directory") { Directory = Value; }
- else if (Key == "file") { File = Value; }
- else if (Key == "command") { Command = Value; }
- else {
- ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str();
- }
- }
-
- const llvm::StringRef FileToMatch;
- bool FoundMatchingCommand;
- CompileCommand MatchingCommand;
- std::string ErrorMessage;
-
- llvm::StringRef Directory;
- llvm::StringRef File;
- llvm::StringRef Command;
-};
-
-} // end namespace
-
-CompileCommand FindCompileArgsInJsonDatabase(
- llvm::StringRef FileName, llvm::StringRef JsonDatabase,
- std::string &ErrorMessage) {
- FindHandler find_handler(FileName);
- JsonCompileCommandLineParser parser(JsonDatabase, &find_handler);
- if (!parser.Parse()) {
- ErrorMessage = parser.GetErrorMessage();
- return CompileCommand();
- }
- return find_handler.MatchingCommand;
-}
-
-/// \brief Returns the absolute path of 'File', by prepending it with
-/// 'BaseDirectory' if 'File' is not absolute. Otherwise returns 'File'.
-/// If 'File' starts with "./", the returned path will not contain the "./".
-/// Otherwise, the returned path will contain the literal path-concatenation of
-/// 'BaseDirectory' and 'File'.
-///
-/// \param File Either an absolute or relative path.
-/// \param BaseDirectory An absolute path.
-static std::string GetAbsolutePath(
- llvm::StringRef File, llvm::StringRef BaseDirectory) {
- assert(llvm::sys::path::is_absolute(BaseDirectory));
- if (llvm::sys::path::is_absolute(File)) {
- return File;
- }
- llvm::StringRef RelativePath(File);
- if (RelativePath.startswith("./")) {
- RelativePath = RelativePath.substr(strlen("./"));
- }
- llvm::SmallString<1024> AbsolutePath(BaseDirectory);
- llvm::sys::path::append(AbsolutePath, RelativePath);
- return AbsolutePath.str();
-}
-
-FrontendActionFactory::~FrontendActionFactory() {}
-
-ClangTool::ClangTool(int argc, char **argv) {
- if (argc < 3) {
- llvm::outs() << "Usage: " << argv[0] << " <cmake-output-dir> "
- << "<file1> <file2> ...\n";
- exit(1);
- }
- llvm::SmallString<1024> JsonDatabasePath(argv[1]);
- llvm::sys::path::append(JsonDatabasePath, "compile_commands.json");
- llvm::error_code Result =
- llvm::MemoryBuffer::getFile(JsonDatabasePath, JsonDatabase);
- if (Result != 0) {
- llvm::outs() << "Error while opening JSON database: " << Result.message()
- << "\n";
- exit(1);
- }
- Files = std::vector<std::string>(argv + 2, argv + argc);
-}
-
-int ClangTool::Run(FrontendActionFactory *ActionFactory) {
- llvm::StringRef BaseDirectory(::getenv("PWD"));
- bool ProcessingFailed = false;
- for (unsigned I = 0; I < Files.size(); ++I) {
- llvm::SmallString<1024> File(GetAbsolutePath(Files[I], BaseDirectory));
- llvm::outs() << "Processing " << File << ".\n";
- std::string ErrorMessage;
- clang::tooling::CompileCommand LookupResult =
- clang::tooling::FindCompileArgsInJsonDatabase(
- File.str(), JsonDatabase->getBuffer(), ErrorMessage);
- if (!LookupResult.CommandLine.empty()) {
- if (!LookupResult.Directory.empty()) {
- // FIXME: What should happen if CommandLine includes -working-directory
- // as well?
- LookupResult.CommandLine.push_back(
- "-working-directory=" + LookupResult.Directory);
- }
- if (!clang::tooling::RunToolWithFlags(
- ActionFactory->New(),
- LookupResult.CommandLine.size(),
- &clang::tooling::CommandLineToArgv(
- &LookupResult.CommandLine)[0])) {
- llvm::outs() << "Error while processing " << File << ".\n";
- ProcessingFailed = true;
- }
- } else {
- // FIXME: There are two use cases here: doing a fuzzy
- // "find . -name '*.cc' |xargs tool" match, where as a user I don't care
- // about the .cc files that were not found, and the use case where I
- // specify all files I want to run over explicitly, where this should
- // be an error. We'll want to add an option for this.
- llvm::outs() << "Skipping " << File << ". Command line not found.\n";
- }
- }
- return ProcessingFailed ? 1 : 0;
-}
-
-} // end namespace tooling
-} // end namespace clang
-