summaryrefslogtreecommitdiffstats
path: root/lib/Frontend/ASTUnit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend/ASTUnit.cpp')
-rw-r--r--lib/Frontend/ASTUnit.cpp130
1 files changed, 101 insertions, 29 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index f647c8a..48296c7 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -17,27 +17,29 @@
#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/TargetOptions.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;
-ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) {
- Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer());
+ASTUnit::ASTUnit(bool _MainFileIsAST)
+ : tempFile(false), MainFileIsAST(_MainFileIsAST) {
}
ASTUnit::~ASTUnit() {
if (tempFile)
llvm::sys::Path(getPCHFileName()).eraseFromDisk();
-
- // The ASTUnit object owns the DiagnosticClient.
- delete Diags.getClient();
}
namespace {
@@ -90,19 +92,19 @@ public:
} // anonymous namespace
const std::string &ASTUnit::getOriginalSourceFileName() {
- return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile();
+ return OriginalSourceFile;
}
const std::string &ASTUnit::getPCHFileName() {
+ assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName();
}
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
- std::string *ErrMsg,
- DiagnosticClient *diagClient,
+ Diagnostic &Diags,
bool OnlyLocalDecls,
bool UseBumpAllocator) {
- llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient));
+ llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
@@ -118,7 +120,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
llvm::OwningPtr<ExternalASTSource> Source;
Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
- AST->Diags));
+ Diags));
Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
@@ -128,11 +130,12 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
case PCHReader::Failure:
case PCHReader::IgnorePCH:
- if (ErrMsg)
- *ErrMsg = "Could not load PCH file";
+ Diags.Report(diag::err_fe_unable_to_load_pch);
return NULL;
}
+ AST->OriginalSourceFile = Reader->getOriginalSourceFile();
+
// PCH loaded successfully. Now create the preprocessor.
// Get information about the target being compiled for.
@@ -143,8 +146,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
TargetOpts.CPU = "";
TargetOpts.Features.clear();
TargetOpts.Triple = TargetTriple;
- AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts));
- AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(),
+ AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
+ AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
AST->getSourceManager(), HeaderInfo));
Preprocessor &PP = *AST->PP.get();
@@ -177,13 +180,30 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
namespace {
-class NullAction : public ASTFrontendAction {
+class TopLevelDeclTrackerConsumer : public ASTConsumer {
+ ASTUnit &Unit;
+
+public:
+ TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
+
+ void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
+ Unit.getTopLevelDecls().push_back(*it);
+ }
+};
+
+class TopLevelDeclTrackerAction : public ASTFrontendAction {
+public:
+ ASTUnit &Unit;
+
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return new ASTConsumer();
+ return new TopLevelDeclTrackerConsumer(Unit);
}
public:
+ TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
+
virtual bool hasCodeCompletionSupport() const { return false; }
};
@@ -191,12 +211,11 @@ public:
ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
Diagnostic &Diags,
- bool OnlyLocalDecls,
- bool UseBumpAllocator) {
+ bool OnlyLocalDecls) {
// Create the compiler instance to use for building the AST.
- CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ CompilerInstance Clang;
llvm::OwningPtr<ASTUnit> AST;
- NullAction Act;
+ llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
Clang.getInvocation() = CI;
@@ -221,9 +240,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
"FIXME: AST inputs not yet supported here!");
// Create the AST unit.
- //
- // FIXME: Use the provided diagnostic client.
- AST.reset(new ASTUnit());
+ AST.reset(new ASTUnit(false));
+
+ AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
// Create a file manager object to provide access to and cache the filesystem.
Clang.setFileManager(&AST->getFileManager());
@@ -234,20 +254,22 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
// Create the preprocessor.
Clang.createPreprocessor();
- if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+ Act.reset(new TopLevelDeclTrackerAction(*AST));
+ if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
/*IsAST=*/false))
goto error;
- Act.Execute();
+ Act->Execute();
- // Steal the created context and preprocessor, and take back the source and
- // file managers.
+ // Steal the created target, context, and preprocessor, and take back the
+ // source and file managers.
AST->Ctx.reset(Clang.takeASTContext());
AST->PP.reset(Clang.takePreprocessor());
Clang.takeSourceManager();
Clang.takeFileManager();
+ AST->Target.reset(Clang.takeTarget());
- Act.EndSourceFile();
+ Act->EndSourceFile();
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
@@ -261,3 +283,53 @@ error:
Clang.takeDiagnostics();
return 0;
}
+
+ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
+ const char **ArgEnd,
+ Diagnostic &Diags,
+ llvm::StringRef ResourceFilesPath,
+ 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");
+
+ // FIXME: We shouldn't have to pass in the path info.
+ driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
+ "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(),
+ Diags);
+
+ // Override the resources path.
+ CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+
+ CI.getFrontendOpts().DisableFree = UseBumpAllocator;
+ return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls);
+}
OpenPOWER on IntegriCloud