opnsense-src/lib/Frontend/ASTUnit.cpp

368 lines
12 KiB
C++
Raw Normal View History

2009-06-22 04:08:35 -04:00
//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// ASTUnit Implementation.
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/AST/ASTContext.h"
2009-12-01 06:08:04 -05:00
#include "clang/AST/ASTConsumer.h"
2009-06-22 04:08:35 -04:00
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
2009-12-15 13:49:47 -05:00
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
2009-12-01 06:08:04 -05:00
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
2009-12-15 13:49:47 -05:00
#include "clang/Frontend/FrontendDiagnostic.h"
2009-12-01 06:08:04 -05:00
#include "clang/Frontend/FrontendOptions.h"
2009-06-22 04:08:35 -04:00
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
2009-11-18 09:59:57 -05:00
#include "clang/Basic/TargetOptions.h"
2009-06-22 04:08:35 -04:00
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
2010-01-23 06:10:26 -05:00
#include "llvm/Support/MemoryBuffer.h"
2009-12-15 13:49:47 -05:00
#include "llvm/System/Host.h"
2009-10-23 10:22:18 -04:00
#include "llvm/System/Path.h"
2009-06-22 04:08:35 -04:00
using namespace clang;
2009-12-15 13:49:47 -05:00
ASTUnit::ASTUnit(bool _MainFileIsAST)
: tempFile(false), MainFileIsAST(_MainFileIsAST) {
2009-10-23 10:22:18 -04:00
}
2009-12-01 06:08:04 -05:00
ASTUnit::~ASTUnit() {
2009-10-23 10:22:18 -04:00
if (tempFile)
llvm::sys::Path(getPCHFileName()).eraseFromDisk();
}
2009-06-22 04:08:35 -04:00
namespace {
/// \brief Gathers information from PCHReader that will be used to initialize
/// a Preprocessor.
2009-12-01 06:08:04 -05:00
class PCHInfoCollector : public PCHReaderListener {
2009-06-22 04:08:35 -04:00
LangOptions &LangOpt;
HeaderSearch &HSI;
std::string &TargetTriple;
std::string &Predefines;
unsigned &Counter;
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
unsigned NumHeaderInfos;
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
public:
PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
std::string &TargetTriple, std::string &Predefines,
unsigned &Counter)
: LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
LangOpt = LangOpts;
return false;
}
2009-10-14 14:03:49 -04:00
2009-11-18 09:59:57 -05:00
virtual bool ReadTargetTriple(llvm::StringRef Triple) {
2009-06-22 04:08:35 -04:00
TargetTriple = Triple;
return false;
}
2009-10-14 14:03:49 -04:00
2009-11-18 09:59:57 -05:00
virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
2009-06-22 04:08:35 -04:00
FileID PCHBufferID,
2009-11-18 09:59:57 -05:00
llvm::StringRef OriginalFileName,
2009-06-22 04:08:35 -04:00
std::string &SuggestedPredefines) {
Predefines = PCHPredef;
return false;
}
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
}
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
virtual void ReadCounter(unsigned Value) {
Counter = Value;
}
};
} // anonymous namespace
2009-10-14 14:03:49 -04:00
const std::string &ASTUnit::getOriginalSourceFileName() {
2009-12-15 13:49:47 -05:00
return OriginalSourceFile;
2009-10-14 14:03:49 -04:00
}
2009-10-23 10:22:18 -04:00
const std::string &ASTUnit::getPCHFileName() {
2009-12-15 13:49:47 -05:00
assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
2010-02-16 04:31:36 -05:00
return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
2009-10-14 14:03:49 -04:00
}
2009-06-22 04:08:35 -04:00
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
2009-12-15 13:49:47 -05:00
Diagnostic &Diags,
2009-10-23 10:22:18 -04:00
bool OnlyLocalDecls,
2010-01-23 06:10:26 -05:00
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles) {
2009-12-15 13:49:47 -05:00
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
2009-10-23 10:22:18 -04:00
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
2009-06-22 04:08:35 -04:00
2010-01-23 06:10:26 -05:00
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
// Create the file entry for the file that we're mapping from.
const FileEntry *FromFile
= AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
RemappedFiles[I].second->getBufferSize(),
0);
if (!FromFile) {
Diags.Report(diag::err_fe_remap_missing_from_file)
<< RemappedFiles[I].first;
continue;
}
// Override the contents of the "from" file with the contents of
// the "to" file.
AST->getSourceManager().overrideFileContents(FromFile,
RemappedFiles[I].second);
}
2009-06-22 04:08:35 -04:00
// Gather Info for preprocessor construction later on.
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
LangOptions LangInfo;
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
std::string TargetTriple;
std::string Predefines;
unsigned Counter;
llvm::OwningPtr<PCHReader> Reader;
llvm::OwningPtr<ExternalASTSource> Source;
2009-10-23 10:22:18 -04:00
Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
2009-12-15 13:49:47 -05:00
Diags));
2009-06-22 04:08:35 -04:00
Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
switch (Reader->ReadPCH(Filename)) {
case PCHReader::Success:
break;
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
case PCHReader::Failure:
2009-06-27 06:45:02 -04:00
case PCHReader::IgnorePCH:
2009-12-15 13:49:47 -05:00
Diags.Report(diag::err_fe_unable_to_load_pch);
2009-06-22 04:08:35 -04:00
return NULL;
}
2009-10-14 14:03:49 -04:00
2009-12-15 13:49:47 -05:00
AST->OriginalSourceFile = Reader->getOriginalSourceFile();
2009-06-22 04:08:35 -04:00
// PCH loaded successfully. Now create the preprocessor.
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
// Get information about the target being compiled for.
2009-11-18 09:59:57 -05:00
//
// FIXME: This is broken, we should store the TargetOptions in the PCH.
TargetOptions TargetOpts;
TargetOpts.ABI = "";
TargetOpts.CPU = "";
TargetOpts.Features.clear();
TargetOpts.Triple = TargetTriple;
2009-12-15 13:49:47 -05:00
AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
2009-10-14 14:03:49 -04:00
AST->getSourceManager(), HeaderInfo));
2009-06-22 04:08:35 -04:00
Preprocessor &PP = *AST->PP.get();
2009-10-14 14:03:49 -04:00
PP.setPredefines(Reader->getSuggestedPredefines());
2009-06-22 04:08:35 -04:00
PP.setCounterValue(Counter);
Reader->setPreprocessor(PP);
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
// Create and initialize the ASTContext.
AST->Ctx.reset(new ASTContext(LangInfo,
2009-10-14 14:03:49 -04:00
AST->getSourceManager(),
2009-06-22 04:08:35 -04:00
*AST->Target.get(),
PP.getIdentifierTable(),
PP.getSelectorTable(),
PP.getBuiltinInfo(),
2010-02-16 04:31:36 -05:00
/* FreeMemory = */ false,
2009-06-22 04:08:35 -04:00
/* size_reserve = */0));
ASTContext &Context = *AST->Ctx.get();
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
Reader->InitializeContext(Context);
2009-10-14 14:03:49 -04:00
2009-06-22 04:08:35 -04:00
// Attach the PCH reader to the AST context as an external AST
// source, so that declarations will be deserialized from the
// PCH file as needed.
Source.reset(Reader.take());
Context.setExternalSource(Source);
2009-10-14 14:03:49 -04:00
return AST.take();
2009-06-22 04:08:35 -04:00
}
2009-12-01 06:08:04 -05:00
namespace {
2009-12-15 13:49:47 -05:00
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;
2009-12-01 06:08:04 -05:00
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
2009-12-15 13:49:47 -05:00
return new TopLevelDeclTrackerConsumer(Unit);
2009-12-01 06:08:04 -05:00
}
public:
2009-12-15 13:49:47 -05:00
TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
2009-12-01 06:08:04 -05:00
virtual bool hasCodeCompletionSupport() const { return false; }
};
}
2010-02-16 04:31:36 -05:00
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
2009-12-01 06:08:04 -05:00
Diagnostic &Diags,
2009-12-15 13:49:47 -05:00
bool OnlyLocalDecls) {
2009-12-01 06:08:04 -05:00
// Create the compiler instance to use for building the AST.
2009-12-15 13:49:47 -05:00
CompilerInstance Clang;
2009-12-01 06:08:04 -05:00
llvm::OwningPtr<ASTUnit> AST;
2009-12-15 13:49:47 -05:00
llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
2009-12-01 06:08:04 -05:00
2010-02-16 04:31:36 -05:00
Clang.setInvocation(CI);
2009-12-01 06:08:04 -05:00
Clang.setDiagnostics(&Diags);
Clang.setDiagnosticClient(Diags.getClient());
// Create the target instance.
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
Clang.getTargetOpts()));
if (!Clang.hasTarget())
goto error;
// Inform the target of the language options.
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
"FIXME: AST inputs not yet supported here!");
// Create the AST unit.
2009-12-15 13:49:47 -05:00
AST.reset(new ASTUnit(false));
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
2009-12-01 06:08:04 -05:00
// Create a file manager object to provide access to and cache the filesystem.
Clang.setFileManager(&AST->getFileManager());
// Create the source manager.
Clang.setSourceManager(&AST->getSourceManager());
// Create the preprocessor.
Clang.createPreprocessor();
2009-12-15 13:49:47 -05:00
Act.reset(new TopLevelDeclTrackerAction(*AST));
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
2009-12-01 06:08:04 -05:00
/*IsAST=*/false))
goto error;
2009-12-15 13:49:47 -05:00
Act->Execute();
2009-12-01 06:08:04 -05:00
2009-12-15 13:49:47 -05:00
// Steal the created target, context, and preprocessor, and take back the
// source and file managers.
2009-12-01 06:08:04 -05:00
AST->Ctx.reset(Clang.takeASTContext());
AST->PP.reset(Clang.takePreprocessor());
Clang.takeSourceManager();
Clang.takeFileManager();
2009-12-15 13:49:47 -05:00
AST->Target.reset(Clang.takeTarget());
2009-12-01 06:08:04 -05:00
2009-12-15 13:49:47 -05:00
Act->EndSourceFile();
2009-12-01 06:08:04 -05:00
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
2010-02-16 04:31:36 -05:00
Clang.takeInvocation();
2009-12-01 06:08:04 -05:00
2010-02-16 04:31:36 -05:00
AST->Invocation.reset(Clang.takeInvocation());
2009-12-01 06:08:04 -05:00
return AST.take();
error:
Clang.takeSourceManager();
Clang.takeFileManager();
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
return 0;
}
2009-12-15 13:49:47 -05:00
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
Diagnostic &Diags,
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls,
2010-01-23 06:10:26 -05:00
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles) {
2009-12-15 13:49:47 -05:00
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);
2010-02-16 04:31:36 -05:00
// Don't check that inputs exist, they have been remapped.
TheDriver.setCheckInputsExist(false);
2009-12-15 13:49:47 -05:00
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();
2010-02-16 04:31:36 -05:00
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
2009-12-15 13:49:47 -05:00
(const char**) CCArgs.data()+CCArgs.size(),
Diags);
2010-01-23 06:10:26 -05:00
// Override any files that need remapping
for (unsigned I = 0; I != NumRemappedFiles; ++I)
2010-02-16 04:31:36 -05:00
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
RemappedFiles[I].second);
2010-01-23 06:10:26 -05:00
2009-12-15 13:49:47 -05:00
// Override the resources path.
2010-02-16 04:31:36 -05:00
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
2009-12-15 13:49:47 -05:00
2010-02-16 04:31:36 -05:00
CI->getFrontendOpts().DisableFree = true;
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls);
2009-12-15 13:49:47 -05:00
}