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<
"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">;
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
#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"
#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;
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);
+}
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) {
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));