Add ASTUnit::LoadFromCommandLine, which creates an ASTUnit out of a list of

(clang/driver) command line arguments (including the source file).
 - The arguments are expected to include the source file.

 - The idea is that even though this is a somewhat odd API, its the form which
   many tools can most easily use (for example, by interposing with the compiler).

Also, switch index-test's -ast-from-source to use this entry point, and provide
a -arg command line argument which can be used to test that the command line
arguments are handled correctly.

llvm-svn: 90288
This commit is contained in:
Daniel Dunbar 2009-12-02 03:23:45 +00:00
parent 120c77e4e9
commit 55a17b66cd
4 changed files with 98 additions and 13 deletions

View File

@ -15,8 +15,8 @@ def err_fe_error_reading_stdin : Error<"error reading stdin">;
def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal;
def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal;
def err_fe_invalid_code_complete_file
: Error<"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
DefaultFatal;
def err_fe_dependency_file_requires_MT : Error<
@ -29,6 +29,10 @@ def err_fe_unable_to_find_fixit_file : Error<
"FIX-IT could not find file '%0'">;
def err_fe_invalid_plugin_name : Error<
"unable to find plugin '%0'">;
def err_fe_expected_compiler_job : Error<
"unable to handle compilation, expected exactly one compiler job in '%0'">;
def err_fe_expected_clang_command : Error<
"expected a clang compiler command">;
def err_verify_bogus_characters : Error<
"bogus characters before '{{' in expected string">;

View File

@ -122,6 +122,30 @@ public:
bool OnlyLocalDecls = false,
bool UseBumpAllocator = false);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
///
/// \param ArgBegin - The beginning of the argument vector.
///
/// \param ArgEnd - The end of the argument vector.
///
/// \param Diags - The diagnostics engine to use for reporting errors.
///
/// \param Argv0 - The program path (from argv[0]), for finding the builtin
/// compiler path.
///
/// \param MainAddr - The address of main (or some other function in the main
/// executable), for finding the builtin compiler path.
//
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
Diagnostic &Diags,
const char *Arg0,
void *MainAddr,
bool OnlyLocalDecls = false,
bool UseBumpAllocator = false);
};
} // namespace clang

View File

@ -17,8 +17,13 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
@ -26,6 +31,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/LLVMContext.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
using namespace clang;
@ -262,3 +268,52 @@ error:
Clang.takeDiagnostics();
return 0;
}
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
Diagnostic &Diags,
const char *Argv0,
void *MainAddr,
bool OnlyLocalDecls,
bool UseBumpAllocator) {
llvm::SmallVector<const char *, 16> Args;
Args.push_back("<clang>"); // FIXME: Remove dummy argument.
Args.insert(Args.end(), ArgBegin, ArgEnd);
// FIXME: Find a cleaner way to force the driver into restricted modes. We
// also want to force it to use clang.
Args.push_back("-fsyntax-only");
llvm::sys::Path Path = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
driver::Driver TheDriver(Path.getBasename().c_str(),Path.getDirname().c_str(),
llvm::sys::getHostTriple().c_str(),
"a.out", false, Diags);
llvm::OwningPtr<driver::Compilation> C(
TheDriver.BuildCompilation(Args.size(), Args.data()));
// We expect to get back exactly one command job, if we didn't something
// failed.
const driver::JobList &Jobs = C->getJobs();
if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
llvm::SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
return 0;
}
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Diags.Report(diag::err_fe_expected_clang_command);
return 0;
}
const driver::ArgStringList &CCArgs = Cmd->getArguments();
CompilerInvocation CI;
CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(),
(const char**) CCArgs.data()+CCArgs.size(),
Argv0, MainAddr, Diags);
return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls,
UseBumpAllocator);
}

View File

@ -208,20 +208,24 @@ static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
static llvm::cl::opt<bool>
ASTFromSource("ast-from-source",
llvm::cl::desc("Treat the inputs as source files to parse."));
llvm::cl::desc("Treat the inputs as source files to parse"));
static llvm::cl::list<std::string>
CompilerArgs("arg", llvm::cl::desc("Extra arguments to use during parsing"));
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
void CreateCompilerInvocation(const std::string &Filename,
CompilerInvocation &CI, Diagnostic &Diags,
const char *argv0) {
ASTUnit *CreateFromSource(const std::string &Filename, Diagnostic &Diags,
const char *Argv0) {
llvm::SmallVector<const char *, 16> Args;
Args.push_back(Filename.c_str());
for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i)
Args.push_back(CompilerArgs[i].c_str());
void *MainAddr = (void*) (intptr_t) CreateCompilerInvocation;
CompilerInvocation::CreateFromArgs(CI, Args.data(), Args.data() + Args.size(),
argv0, MainAddr, Diags);
return ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
Diags, Argv0,
(void*) (intptr_t) CreateFromSource);
}
int main(int argc, char **argv) {
@ -249,10 +253,8 @@ int main(int argc, char **argv) {
llvm::OwningPtr<ASTUnit> AST;
if (ASTFromSource) {
CompilerInvocation CI;
CreateCompilerInvocation(InFile, CI, *Diags, argv[0]);
AST.reset(ASTUnit::LoadFromCompilerInvocation(CI, *Diags));
if (!AST)
AST.reset(CreateFromSource(InFile, *Diags, argv[0]));
if (!AST || Diags->getNumErrors())
ErrMsg = "unable to create AST";
} else
AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg));