2009-06-20 16:27:14 +08: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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Frontend/ASTUnit.h"
|
|
|
|
#include "clang/Frontend/PCHReader.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/AST/DeclVisitor.h"
|
|
|
|
#include "clang/AST/StmtVisitor.h"
|
2009-12-02 11:23:45 +08:00
|
|
|
#include "clang/Driver/Compilation.h"
|
|
|
|
#include "clang/Driver/Driver.h"
|
|
|
|
#include "clang/Driver/Job.h"
|
|
|
|
#include "clang/Driver/Tool.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
|
|
#include "clang/Frontend/FrontendActions.h"
|
2009-12-02 11:23:45 +08:00
|
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/Frontend/FrontendOptions.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2009-11-15 14:48:46 +08:00
|
|
|
#include "clang/Basic/TargetOptions.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2010-01-23 08:14:00 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2009-12-02 11:23:45 +08:00
|
|
|
#include "llvm/System/Host.h"
|
2009-10-18 19:34:14 +08:00
|
|
|
#include "llvm/System/Path.h"
|
2010-07-23 08:33:23 +08:00
|
|
|
#include <cstdlib>
|
2010-07-23 10:15:08 +08:00
|
|
|
#include <cstdio>
|
2009-06-20 16:08:23 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2010-04-06 05:10:19 +08:00
|
|
|
ASTUnit::ASTUnit(bool _MainFileIsAST)
|
2010-07-20 05:46:24 +08:00
|
|
|
: CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
|
|
|
|
ConcurrencyCheckValue(CheckUnlocked) { }
|
2010-04-06 05:10:19 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
ASTUnit::~ASTUnit() {
|
2010-03-06 05:16:25 +08:00
|
|
|
ConcurrencyCheckValue = CheckLocked;
|
2010-07-20 05:46:24 +08:00
|
|
|
CleanTemporaryFiles();
|
2010-07-24 07:58:40 +08:00
|
|
|
if (!PreambleFile.empty())
|
|
|
|
PreambleFile.eraseFromDisk();
|
2010-07-20 05:46:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::CleanTemporaryFiles() {
|
2010-02-19 07:35:40 +08:00
|
|
|
for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
|
|
|
|
TemporaryFiles[I].eraseFromDisk();
|
2010-07-20 05:46:24 +08:00
|
|
|
TemporaryFiles.clear();
|
2009-10-16 06:23:48 +08:00
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
/// \brief Gathers information from PCHReader that will be used to initialize
|
|
|
|
/// a Preprocessor.
|
2009-11-28 18:07:24 +08:00
|
|
|
class PCHInfoCollector : public PCHReaderListener {
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOptions &LangOpt;
|
|
|
|
HeaderSearch &HSI;
|
|
|
|
std::string &TargetTriple;
|
|
|
|
std::string &Predefines;
|
|
|
|
unsigned &Counter;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
unsigned NumHeaderInfos;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08: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-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
|
|
|
|
LangOpt = LangOpts;
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 08:52:11 +08:00
|
|
|
virtual bool ReadTargetTriple(llvm::StringRef Triple) {
|
2009-06-20 16:08:23 +08:00
|
|
|
TargetTriple = Triple;
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-15 07:29:55 +08:00
|
|
|
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
2009-11-11 13:29:04 +08:00
|
|
|
llvm::StringRef OriginalFileName,
|
2009-06-20 16:08:23 +08:00
|
|
|
std::string &SuggestedPredefines) {
|
2010-07-15 07:29:55 +08:00
|
|
|
Predefines = Buffers[0].Data;
|
|
|
|
for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
|
|
|
|
Predefines += Buffers[I].Data;
|
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-17 03:09:18 +08:00
|
|
|
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
|
2009-06-20 16:08:23 +08:00
|
|
|
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
virtual void ReadCounter(unsigned Value) {
|
|
|
|
Counter = Value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
class StoredDiagnosticClient : public DiagnosticClient {
|
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit StoredDiagnosticClient(
|
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
|
|
|
: StoredDiags(StoredDiags) { }
|
|
|
|
|
|
|
|
virtual void HandleDiagnostic(Diagnostic::Level Level,
|
|
|
|
const DiagnosticInfo &Info);
|
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief RAII object that optionally captures diagnostics, if
|
|
|
|
/// there is no diagnostic client to capture them already.
|
|
|
|
class CaptureDroppedDiagnostics {
|
|
|
|
Diagnostic &Diags;
|
|
|
|
StoredDiagnosticClient Client;
|
|
|
|
DiagnosticClient *PreviousClient;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
|
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
|
|
|
: Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
|
|
|
|
{
|
|
|
|
if (RequestCapture || Diags.getClient() == 0)
|
|
|
|
Diags.setClient(&Client);
|
|
|
|
}
|
|
|
|
|
|
|
|
~CaptureDroppedDiagnostics() {
|
|
|
|
Diags.setClient(PreviousClient);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
|
|
|
|
const DiagnosticInfo &Info) {
|
|
|
|
StoredDiags.push_back(StoredDiagnostic(Level, Info));
|
|
|
|
}
|
|
|
|
|
2009-09-04 02:19:54 +08:00
|
|
|
const std::string &ASTUnit::getOriginalSourceFileName() {
|
2009-12-02 16:44:16 +08:00
|
|
|
return OriginalSourceFile;
|
2009-09-04 02:19:54 +08:00
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
|
2009-10-16 06:23:48 +08:00
|
|
|
const std::string &ASTUnit::getPCHFileName() {
|
2009-12-03 05:47:43 +08:00
|
|
|
assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
|
2010-01-31 00:23:25 +08:00
|
|
|
return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
|
2009-10-16 06:23:48 +08:00
|
|
|
}
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
|
2010-04-06 07:52:57 +08:00
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
2009-10-17 08:34:24 +08:00
|
|
|
bool OnlyLocalDecls,
|
2010-01-23 08:14:00 +08:00
|
|
|
RemappedFile *RemappedFiles,
|
2010-02-19 02:08:43 +08:00
|
|
|
unsigned NumRemappedFiles,
|
|
|
|
bool CaptureDiagnostics) {
|
2010-04-06 05:10:19 +08:00
|
|
|
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
|
|
|
|
|
2010-04-06 07:52:57 +08:00
|
|
|
if (!Diags.getPtr()) {
|
2010-04-06 05:10:19 +08:00
|
|
|
// No diagnostics engine was provided, so create our own diagnostics object
|
|
|
|
// with the default options.
|
|
|
|
DiagnosticOptions DiagOpts;
|
2010-04-06 07:52:57 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
2010-04-06 05:10:19 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2009-10-17 04:01:17 +08:00
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-04-06 07:52:57 +08:00
|
|
|
AST->Diagnostics = Diags;
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->FileMgr.reset(new FileManager);
|
|
|
|
AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
|
2009-10-19 22:34:22 +08:00
|
|
|
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
|
2009-06-20 16:08:23 +08:00
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
// If requested, capture diagnostics in the ASTUnit.
|
2010-04-06 05:10:19 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
|
2010-04-06 02:10:21 +08:00
|
|
|
AST->StoredDiagnostics);
|
2010-02-19 02:08:43 +08:00
|
|
|
|
2010-01-23 08:14:00 +08: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) {
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
|
2010-01-23 08:14:00 +08:00
|
|
|
<< RemappedFiles[I].first;
|
2010-02-27 09:32:48 +08:00
|
|
|
delete RemappedFiles[I].second;
|
2010-01-23 08:14:00 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override the contents of the "from" file with the contents of
|
|
|
|
// the "to" file.
|
|
|
|
AST->getSourceManager().overrideFileContents(FromFile,
|
|
|
|
RemappedFiles[I].second);
|
|
|
|
}
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Gather Info for preprocessor construction later on.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOptions LangInfo;
|
|
|
|
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
|
|
|
|
std::string TargetTriple;
|
|
|
|
std::string Predefines;
|
|
|
|
unsigned Counter;
|
|
|
|
|
2009-09-03 13:59:50 +08:00
|
|
|
llvm::OwningPtr<PCHReader> Reader;
|
2009-06-20 16:08:23 +08:00
|
|
|
llvm::OwningPtr<ExternalASTSource> Source;
|
|
|
|
|
2009-10-20 05:44:57 +08:00
|
|
|
Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->getDiagnostics()));
|
2009-09-03 13:59:35 +08:00
|
|
|
Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
|
|
|
|
Predefines, Counter));
|
|
|
|
|
|
|
|
switch (Reader->ReadPCH(Filename)) {
|
2009-06-20 16:08:23 +08:00
|
|
|
case PCHReader::Success:
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
case PCHReader::Failure:
|
2009-06-26 02:22:30 +08:00
|
|
|
case PCHReader::IgnorePCH:
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
|
2009-06-20 16:08:23 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-02 16:44:16 +08:00
|
|
|
AST->OriginalSourceFile = Reader->getOriginalSourceFile();
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// PCH loaded successfully. Now create the preprocessor.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Get information about the target being compiled for.
|
2009-11-15 14:48:46 +08:00
|
|
|
//
|
|
|
|
// FIXME: This is broken, we should store the TargetOptions in the PCH.
|
|
|
|
TargetOptions TargetOpts;
|
|
|
|
TargetOpts.ABI = "";
|
2010-06-11 09:06:47 +08:00
|
|
|
TargetOpts.CXXABI = "itanium";
|
2009-11-15 14:48:46 +08:00
|
|
|
TargetOpts.CPU = "";
|
|
|
|
TargetOpts.Features.clear();
|
|
|
|
TargetOpts.Triple = TargetTriple;
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
|
|
|
|
TargetOpts));
|
|
|
|
AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
|
|
|
|
*AST->Target.get(),
|
2009-09-21 11:03:39 +08:00
|
|
|
AST->getSourceManager(), HeaderInfo));
|
2009-06-20 16:08:23 +08:00
|
|
|
Preprocessor &PP = *AST->PP.get();
|
|
|
|
|
2009-09-21 11:03:47 +08:00
|
|
|
PP.setPredefines(Reader->getSuggestedPredefines());
|
2009-06-20 16:08:23 +08:00
|
|
|
PP.setCounterValue(Counter);
|
2009-09-03 13:59:35 +08:00
|
|
|
Reader->setPreprocessor(PP);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Create and initialize the ASTContext.
|
|
|
|
|
|
|
|
AST->Ctx.reset(new ASTContext(LangInfo,
|
2009-09-21 11:03:39 +08:00
|
|
|
AST->getSourceManager(),
|
2009-06-20 16:08:23 +08:00
|
|
|
*AST->Target.get(),
|
|
|
|
PP.getIdentifierTable(),
|
|
|
|
PP.getSelectorTable(),
|
|
|
|
PP.getBuiltinInfo(),
|
2010-02-16 09:55:04 +08:00
|
|
|
/* FreeMemory = */ false,
|
2009-06-20 16:08:23 +08:00
|
|
|
/* size_reserve = */0));
|
|
|
|
ASTContext &Context = *AST->Ctx.get();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-03 13:59:35 +08:00
|
|
|
Reader->InitializeContext(Context);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08: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.
|
2009-09-03 13:59:35 +08:00
|
|
|
Source.reset(Reader.take());
|
2009-06-20 16:08:23 +08:00
|
|
|
Context.setExternalSource(Source);
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
return AST.take();
|
2009-06-20 16:08:23 +08:00
|
|
|
}
|
2009-12-01 17:51:01 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
class TopLevelDeclTrackerConsumer : public ASTConsumer {
|
|
|
|
ASTUnit &Unit;
|
|
|
|
|
|
|
|
public:
|
|
|
|
TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
|
|
|
|
|
|
|
|
void HandleTopLevelDecl(DeclGroupRef D) {
|
2010-05-04 04:16:35 +08:00
|
|
|
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
|
|
|
|
Decl *D = *it;
|
|
|
|
// FIXME: Currently ObjC method declarations are incorrectly being
|
|
|
|
// reported as top-level declarations, even though their DeclContext
|
|
|
|
// is the containing ObjC @interface/@implementation. This is a
|
|
|
|
// fundamental problem in the parser right now.
|
|
|
|
if (isa<ObjCMethodDecl>(D))
|
|
|
|
continue;
|
|
|
|
Unit.getTopLevelDecls().push_back(D);
|
|
|
|
}
|
2009-12-04 16:17:33 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class TopLevelDeclTrackerAction : public ASTFrontendAction {
|
|
|
|
public:
|
|
|
|
ASTUnit &Unit;
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
|
|
|
llvm::StringRef InFile) {
|
2009-12-04 16:17:33 +08:00
|
|
|
return new TopLevelDeclTrackerConsumer(Unit);
|
2009-12-01 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2009-12-04 16:17:33 +08:00
|
|
|
TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
virtual bool hasCodeCompletionSupport() const { return false; }
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
/// Parse the source file into a translation unit using the given compiler
|
|
|
|
/// invocation, replacing the current translation unit.
|
|
|
|
///
|
|
|
|
/// \returns True if a failure occurred that causes the ASTUnit not to
|
|
|
|
/// contain any translation-unit information, false otherwise.
|
2010-07-24 08:38:13 +08:00
|
|
|
bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
|
2010-07-20 05:46:24 +08:00
|
|
|
if (!Invocation.get())
|
|
|
|
return true;
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the compiler instance to use for building the AST.
|
2009-12-02 16:43:56 +08:00
|
|
|
CompilerInstance Clang;
|
2010-07-20 05:46:24 +08:00
|
|
|
Clang.setInvocation(Invocation.take());
|
|
|
|
OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
|
|
|
|
|
|
|
|
// Set up diagnostics.
|
|
|
|
Clang.setDiagnostics(&getDiagnostics());
|
|
|
|
Clang.setDiagnosticClient(getDiagnostics().getClient());
|
2010-04-06 05:10:19 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the target instance.
|
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
2010-02-19 02:08:43 +08:00
|
|
|
if (!Clang.hasTarget()) {
|
|
|
|
Clang.takeDiagnosticClient();
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
2010-02-19 02:08:43 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// 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());
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
|
|
|
|
"Invocation must have exactly one source file!");
|
2010-06-08 07:22:09 +08:00
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
|
2009-12-01 17:51:01 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2010-06-08 07:26:47 +08:00
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
|
|
|
|
"IR inputs not support here!");
|
2009-12-01 17:51:01 +08:00
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
// Configure the various subsystems.
|
|
|
|
// FIXME: Should we retain the previous file manager?
|
|
|
|
FileMgr.reset(new FileManager);
|
|
|
|
SourceMgr.reset(new SourceManager(getDiagnostics()));
|
|
|
|
Ctx.reset();
|
|
|
|
PP.reset();
|
|
|
|
|
|
|
|
// Clear out old caches and data.
|
|
|
|
TopLevelDecls.clear();
|
|
|
|
StoredDiagnostics.clear();
|
|
|
|
CleanTemporaryFiles();
|
|
|
|
PreprocessedEntitiesByFile.clear();
|
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
// Capture any diagnostics that would otherwise be dropped.
|
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
|
|
|
Clang.getDiagnostics(),
|
2010-07-20 05:46:24 +08:00
|
|
|
StoredDiagnostics);
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
2010-07-20 05:46:24 +08:00
|
|
|
Clang.setFileManager(&getFileManager());
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the source manager.
|
2010-07-20 05:46:24 +08:00
|
|
|
Clang.setSourceManager(&getSourceManager());
|
|
|
|
|
|
|
|
llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
|
|
|
|
Act.reset(new TopLevelDeclTrackerAction(*this));
|
2009-12-04 16:17:33 +08:00
|
|
|
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
|
2010-06-08 07:23:06 +08:00
|
|
|
Clang.getFrontendOpts().Inputs[0].first))
|
2009-12-01 17:51:01 +08:00
|
|
|
goto error;
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
Act->Execute();
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-02 05:57:33 +08:00
|
|
|
// Steal the created target, context, and preprocessor, and take back the
|
|
|
|
// source and file managers.
|
2010-07-20 05:46:24 +08:00
|
|
|
Ctx.reset(Clang.takeASTContext());
|
|
|
|
PP.reset(Clang.takePreprocessor());
|
2009-12-01 17:51:01 +08:00
|
|
|
Clang.takeSourceManager();
|
|
|
|
Clang.takeFileManager();
|
2010-07-20 05:46:24 +08:00
|
|
|
Target.reset(Clang.takeTarget());
|
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
Act->EndSourceFile();
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
Clang.takeDiagnosticClient();
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
Invocation.reset(Clang.takeInvocation());
|
|
|
|
return false;
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
error:
|
|
|
|
Clang.takeSourceManager();
|
|
|
|
Clang.takeFileManager();
|
|
|
|
Clang.takeDiagnosticClient();
|
2010-07-20 05:46:24 +08:00
|
|
|
Invocation.reset(Clang.takeInvocation());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-23 08:33:23 +08:00
|
|
|
/// \brief Simple function to retrieve a path for a preamble precompiled header.
|
|
|
|
static std::string GetPreamblePCHPath() {
|
|
|
|
// FIXME: This is lame; sys::Path should provide this function (in particular,
|
|
|
|
// it should know how to find the temporary files dir).
|
|
|
|
// FIXME: This is really lame. I copied this code from the Driver!
|
|
|
|
std::string Error;
|
|
|
|
const char *TmpDir = ::getenv("TMPDIR");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("TEMP");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("TMP");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = "/tmp";
|
|
|
|
llvm::sys::Path P(TmpDir);
|
|
|
|
P.appendComponent("preamble");
|
|
|
|
if (P.createTemporaryFileOnDisk())
|
|
|
|
return std::string();
|
|
|
|
|
|
|
|
P.appendSuffix("pch");
|
|
|
|
return P.str();
|
|
|
|
}
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
/// \brief Compute the preamble for the main file, providing
|
|
|
|
std::pair<llvm::MemoryBuffer *, unsigned>
|
|
|
|
ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
|
|
|
|
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
|
2010-07-23 08:33:23 +08:00
|
|
|
PreprocessorOptions &PreprocessorOpts
|
2010-07-24 07:58:40 +08:00
|
|
|
= Invocation.getPreprocessorOpts();
|
|
|
|
CreatedBuffer = false;
|
|
|
|
|
2010-07-23 08:33:23 +08:00
|
|
|
// Try to determine if the main file has been remapped, either from the
|
|
|
|
// command line (to another file) or directly through the compiler invocation
|
|
|
|
// (to a memory buffer).
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::MemoryBuffer *Buffer = 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
|
|
|
|
if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
|
|
|
|
// Check whether there is a file-file remapping of the main file
|
|
|
|
for (PreprocessorOptions::remapped_file_iterator
|
2010-07-24 07:58:40 +08:00
|
|
|
M = PreprocessorOpts.remapped_file_begin(),
|
|
|
|
E = PreprocessorOpts.remapped_file_end();
|
2010-07-23 08:33:23 +08:00
|
|
|
M != E;
|
|
|
|
++M) {
|
|
|
|
llvm::sys::PathWithStatus MPath(M->first);
|
|
|
|
if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
|
|
|
|
if (MainFileStatus->uniqueID == MStatus->uniqueID) {
|
|
|
|
// We found a remapping. Try to load the resulting, remapped source.
|
2010-07-24 07:58:40 +08:00
|
|
|
if (CreatedBuffer) {
|
2010-07-23 08:33:23 +08:00
|
|
|
delete Buffer;
|
2010-07-24 07:58:40 +08:00
|
|
|
CreatedBuffer = false;
|
|
|
|
}
|
|
|
|
|
2010-07-23 08:33:23 +08:00
|
|
|
Buffer = llvm::MemoryBuffer::getFile(M->second);
|
|
|
|
if (!Buffer)
|
2010-07-24 07:58:40 +08:00
|
|
|
return std::make_pair((llvm::MemoryBuffer*)0, 0);
|
|
|
|
CreatedBuffer = true;
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// Remove this remapping. We've captured the buffer already.
|
2010-07-23 08:33:23 +08:00
|
|
|
M = PreprocessorOpts.eraseRemappedFile(M);
|
|
|
|
E = PreprocessorOpts.remapped_file_end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether there is a file-buffer remapping. It supercedes the
|
|
|
|
// file-file remapping.
|
|
|
|
for (PreprocessorOptions::remapped_file_buffer_iterator
|
|
|
|
M = PreprocessorOpts.remapped_file_buffer_begin(),
|
|
|
|
E = PreprocessorOpts.remapped_file_buffer_end();
|
|
|
|
M != E;
|
|
|
|
++M) {
|
|
|
|
llvm::sys::PathWithStatus MPath(M->first);
|
|
|
|
if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
|
|
|
|
if (MainFileStatus->uniqueID == MStatus->uniqueID) {
|
|
|
|
// We found a remapping.
|
2010-07-24 07:58:40 +08:00
|
|
|
if (CreatedBuffer) {
|
2010-07-23 08:33:23 +08:00
|
|
|
delete Buffer;
|
2010-07-24 07:58:40 +08:00
|
|
|
CreatedBuffer = false;
|
|
|
|
}
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
|
|
|
|
|
|
|
|
// Remove this remapping. We've captured the buffer already.
|
2010-07-23 08:33:23 +08:00
|
|
|
M = PreprocessorOpts.eraseRemappedFile(M);
|
|
|
|
E = PreprocessorOpts.remapped_file_buffer_end();
|
|
|
|
}
|
|
|
|
}
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the main source file was not remapped, load it now.
|
|
|
|
if (!Buffer) {
|
|
|
|
Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
|
|
|
|
if (!Buffer)
|
2010-07-24 07:58:40 +08:00
|
|
|
return std::make_pair((llvm::MemoryBuffer*)0, 0);
|
|
|
|
|
|
|
|
CreatedBuffer = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer));
|
|
|
|
}
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
|
|
|
|
bool DeleteOld,
|
|
|
|
unsigned NewSize,
|
|
|
|
llvm::StringRef NewName) {
|
|
|
|
llvm::MemoryBuffer *Result
|
|
|
|
= llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
|
|
|
|
memcpy(const_cast<char*>(Result->getBufferStart()),
|
|
|
|
Old->getBufferStart(), Old->getBufferSize());
|
|
|
|
memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
|
|
|
|
' ', NewSize - Old->getBufferSize() - 1);
|
|
|
|
const_cast<char*>(Result->getBufferEnd())[-1] = 0;
|
|
|
|
|
|
|
|
if (DeleteOld)
|
|
|
|
delete Old;
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
|
|
|
|
/// the source file.
|
|
|
|
///
|
|
|
|
/// This routine will compute the preamble of the main source file. If a
|
|
|
|
/// non-trivial preamble is found, it will precompile that preamble into a
|
|
|
|
/// precompiled header so that the precompiled preamble can be used to reduce
|
|
|
|
/// reparsing time. If a precompiled preamble has already been constructed,
|
|
|
|
/// this routine will determine if it is still valid and, if so, avoid
|
|
|
|
/// rebuilding the precompiled preamble.
|
|
|
|
///
|
2010-07-24 08:38:13 +08:00
|
|
|
/// \returns If the precompiled preamble can be used, returns a newly-allocated
|
|
|
|
/// buffer that should be used in place of the main file when doing so.
|
|
|
|
/// Otherwise, returns a NULL pointer.
|
|
|
|
llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
|
2010-07-24 07:58:40 +08:00
|
|
|
CompilerInvocation PreambleInvocation(*Invocation);
|
|
|
|
FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
|
|
|
|
PreprocessorOptions &PreprocessorOpts
|
|
|
|
= PreambleInvocation.getPreprocessorOpts();
|
|
|
|
|
|
|
|
bool CreatedPreambleBuffer = false;
|
|
|
|
std::pair<llvm::MemoryBuffer *, unsigned> NewPreamble
|
|
|
|
= ComputePreamble(PreambleInvocation, CreatedPreambleBuffer);
|
|
|
|
|
|
|
|
if (!NewPreamble.second) {
|
|
|
|
// We couldn't find a preamble in the main source. Clear out the current
|
|
|
|
// preamble, if we have one. It's obviously no good any more.
|
|
|
|
Preamble.clear();
|
|
|
|
if (!PreambleFile.empty()) {
|
|
|
|
PreambleFile.eraseFromDisk();
|
|
|
|
PreambleFile.clear();
|
|
|
|
}
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
if (!Preamble.empty()) {
|
|
|
|
// We've previously computed a preamble. Check whether we have the same
|
|
|
|
// preamble now that we did before, and that there's enough space in
|
|
|
|
// the main-file buffer within the precompiled preamble to fit the
|
|
|
|
// new main file.
|
|
|
|
if (Preamble.size() == NewPreamble.second &&
|
|
|
|
NewPreamble.first->getBufferSize() < PreambleReservedSize &&
|
|
|
|
memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
|
|
|
|
NewPreamble.second) == 0) {
|
|
|
|
// The preamble has not changed. We may be able to re-use the precompiled
|
|
|
|
// preamble.
|
|
|
|
// FIXME: Check that none of the files used by the preamble have changed.
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// Okay! Re-use the precompiled preamble.
|
2010-07-24 08:38:13 +08:00
|
|
|
return CreatePaddedMainFileBuffer(NewPreamble.first,
|
|
|
|
CreatedPreambleBuffer,
|
|
|
|
PreambleReservedSize,
|
|
|
|
FrontendOpts.Inputs[0].second);
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We can't reuse the previously-computed preamble. Build a new one.
|
|
|
|
Preamble.clear();
|
|
|
|
PreambleFile.eraseFromDisk();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We did not previously compute a preamble, or it can't be reused anyway.
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create a new buffer that stores the preamble. The buffer also contains
|
|
|
|
// extra space for the original contents of the file (which will be present
|
|
|
|
// when we actually parse the file) along with more room in case the file
|
2010-07-24 07:58:40 +08:00
|
|
|
// grows.
|
|
|
|
PreambleReservedSize = NewPreamble.first->getBufferSize();
|
|
|
|
if (PreambleReservedSize < 4096)
|
|
|
|
PreambleReservedSize = 8192;
|
2010-07-23 08:33:23 +08:00
|
|
|
else
|
2010-07-24 07:58:40 +08:00
|
|
|
PreambleReservedSize *= 2;
|
|
|
|
|
2010-07-23 08:33:23 +08:00
|
|
|
llvm::MemoryBuffer *PreambleBuffer
|
2010-07-24 07:58:40 +08:00
|
|
|
= llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
|
2010-07-23 08:33:23 +08:00
|
|
|
FrontendOpts.Inputs[0].second);
|
|
|
|
memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
|
2010-07-24 07:58:40 +08:00
|
|
|
NewPreamble.first->getBufferStart(), Preamble.size());
|
|
|
|
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
|
|
|
|
' ', PreambleReservedSize - Preamble.size() - 1);
|
2010-07-23 08:33:23 +08:00
|
|
|
const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = 0;
|
2010-07-24 07:58:40 +08:00
|
|
|
|
|
|
|
// Save the preamble text for later; we'll need to compare against it for
|
|
|
|
// subsequent reparses.
|
|
|
|
Preamble.assign(NewPreamble.first->getBufferStart(),
|
2010-07-24 08:38:13 +08:00
|
|
|
NewPreamble.first->getBufferStart() + NewPreamble.second);
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Remap the main source file to the preamble buffer.
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
|
2010-07-23 08:33:23 +08:00
|
|
|
PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
|
|
|
|
|
|
|
|
// Tell the compiler invocation to generate a temporary precompiled header.
|
|
|
|
FrontendOpts.ProgramAction = frontend::GeneratePCH;
|
|
|
|
// FIXME: Set ChainedPCH, once it is ready.
|
|
|
|
// FIXME: Generate the precompiled header into memory?
|
2010-07-24 07:58:40 +08:00
|
|
|
if (PreambleFile.isEmpty())
|
|
|
|
FrontendOpts.OutputFile = GetPreamblePCHPath();
|
|
|
|
else
|
|
|
|
FrontendOpts.OutputFile = PreambleFile.str();
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create the compiler instance to use for building the precompiled preamble.
|
|
|
|
CompilerInstance Clang;
|
|
|
|
Clang.setInvocation(&PreambleInvocation);
|
|
|
|
OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
|
|
|
|
|
|
|
|
// Set up diagnostics.
|
|
|
|
Clang.setDiagnostics(&getDiagnostics());
|
|
|
|
Clang.setDiagnosticClient(getDiagnostics().getClient());
|
|
|
|
|
|
|
|
// Create the target instance.
|
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
|
|
|
if (!Clang.hasTarget()) {
|
|
|
|
Clang.takeDiagnosticClient();
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 != IK_AST &&
|
|
|
|
"FIXME: AST inputs not yet supported here!");
|
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
|
|
|
|
"IR inputs not support here!");
|
|
|
|
|
|
|
|
// Clear out old caches and data.
|
|
|
|
StoredDiagnostics.clear();
|
|
|
|
|
|
|
|
// Capture any diagnostics that would otherwise be dropped.
|
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
|
|
|
Clang.getDiagnostics(),
|
|
|
|
StoredDiagnostics);
|
|
|
|
|
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
|
|
|
Clang.setFileManager(new FileManager);
|
|
|
|
|
|
|
|
// Create the source manager.
|
|
|
|
Clang.setSourceManager(new SourceManager(getDiagnostics()));
|
|
|
|
|
|
|
|
// FIXME: Eventually, we'll have to track top-level declarations here, too.
|
|
|
|
llvm::OwningPtr<GeneratePCHAction> Act;
|
|
|
|
Act.reset(new GeneratePCHAction);
|
|
|
|
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
|
|
|
|
Clang.getFrontendOpts().Inputs[0].first)) {
|
|
|
|
Clang.takeDiagnosticClient();
|
|
|
|
Clang.takeInvocation();
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Act->Execute();
|
|
|
|
Act->EndSourceFile();
|
|
|
|
Clang.takeDiagnosticClient();
|
|
|
|
Clang.takeInvocation();
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
if (Diagnostics->getNumErrors() > 0) {
|
|
|
|
// There were errors parsing the preamble, so no precompiled header was
|
|
|
|
// generated. Forget that we even tried.
|
|
|
|
// FIXME: Should we leave a note for ourselves to try again?
|
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Keep track of the preamble we precompiled.
|
|
|
|
PreambleFile = FrontendOpts.OutputFile;
|
2010-07-23 08:33:23 +08:00
|
|
|
fprintf(stderr, "Preamble PCH: %s\n", FrontendOpts.OutputFile.c_str());
|
2010-07-24 08:38:13 +08:00
|
|
|
return CreatePaddedMainFileBuffer(NewPreamble.first,
|
|
|
|
CreatedPreambleBuffer,
|
|
|
|
PreambleReservedSize,
|
|
|
|
FrontendOpts.Inputs[0].second);
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
|
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
|
|
|
bool OnlyLocalDecls,
|
2010-07-23 08:33:23 +08:00
|
|
|
bool CaptureDiagnostics,
|
|
|
|
bool PrecompilePreamble) {
|
2010-07-20 05:46:24 +08:00
|
|
|
if (!Diags.getPtr()) {
|
|
|
|
// No diagnostics engine was provided, so create our own diagnostics object
|
|
|
|
// with the default options.
|
|
|
|
DiagnosticOptions DiagOpts;
|
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the AST unit.
|
|
|
|
llvm::OwningPtr<ASTUnit> AST;
|
|
|
|
AST.reset(new ASTUnit(false));
|
|
|
|
AST->Diagnostics = Diags;
|
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
|
|
|
AST->Invocation.reset(CI);
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
if (PrecompilePreamble)
|
2010-07-24 08:38:13 +08:00
|
|
|
OverrideMainBuffer = AST->BuildPrecompiledPreamble();
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
if (!AST->Parse(OverrideMainBuffer))
|
2010-07-20 05:46:24 +08:00
|
|
|
return AST.take();
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
delete OverrideMainBuffer;
|
2009-12-01 17:51:01 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-12-02 11:23:45 +08:00
|
|
|
|
|
|
|
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
|
|
|
|
const char **ArgEnd,
|
2010-04-06 07:52:57 +08:00
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
2009-12-13 11:46:13 +08:00
|
|
|
llvm::StringRef ResourceFilesPath,
|
2009-12-02 11:23:45 +08:00
|
|
|
bool OnlyLocalDecls,
|
2010-01-23 08:14:00 +08:00
|
|
|
RemappedFile *RemappedFiles,
|
2010-02-19 02:08:43 +08:00
|
|
|
unsigned NumRemappedFiles,
|
2010-07-23 08:33:23 +08:00
|
|
|
bool CaptureDiagnostics,
|
|
|
|
bool PrecompilePreamble) {
|
2010-04-06 07:52:57 +08:00
|
|
|
if (!Diags.getPtr()) {
|
2010-04-06 05:10:19 +08:00
|
|
|
// No diagnostics engine was provided, so create our own diagnostics object
|
|
|
|
// with the default options.
|
|
|
|
DiagnosticOptions DiagOpts;
|
2010-04-06 07:52:57 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
2010-04-06 05:10:19 +08:00
|
|
|
}
|
|
|
|
|
2009-12-02 11:23:45 +08: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");
|
|
|
|
|
2009-12-13 11:46:13 +08:00
|
|
|
// FIXME: We shouldn't have to pass in the path info.
|
2010-07-19 08:44:04 +08:00
|
|
|
driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
|
2010-04-06 05:10:19 +08:00
|
|
|
"a.out", false, false, *Diags);
|
2010-01-25 08:44:02 +08:00
|
|
|
|
|
|
|
// Don't check that inputs exist, they have been remapped.
|
|
|
|
TheDriver.setCheckInputsExist(false);
|
|
|
|
|
2009-12-02 11:23:45 +08: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);
|
2010-04-06 05:10:19 +08:00
|
|
|
Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
|
2009-12-02 11:23:45 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
|
|
|
|
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
|
2010-04-06 05:10:19 +08:00
|
|
|
Diags->Report(diag::err_fe_expected_clang_command);
|
2009-12-02 11:23:45 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
2010-01-31 05:47:16 +08:00
|
|
|
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
2010-04-20 00:39:44 +08:00
|
|
|
CompilerInvocation::CreateFromArgs(*CI,
|
|
|
|
const_cast<const char **>(CCArgs.data()),
|
|
|
|
const_cast<const char **>(CCArgs.data()) +
|
2010-07-23 08:33:23 +08:00
|
|
|
CCArgs.size(),
|
2010-04-06 05:10:19 +08:00
|
|
|
*Diags);
|
2009-12-13 11:45:58 +08:00
|
|
|
|
2010-01-23 08:14:00 +08:00
|
|
|
// Override any files that need remapping
|
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I)
|
2010-01-31 05:47:16 +08:00
|
|
|
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
2010-02-16 09:55:04 +08:00
|
|
|
RemappedFiles[I].second);
|
2010-01-23 08:14:00 +08:00
|
|
|
|
2009-12-15 08:06:45 +08:00
|
|
|
// Override the resources path.
|
2010-01-31 05:47:16 +08:00
|
|
|
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2010-02-16 09:55:04 +08:00
|
|
|
CI->getFrontendOpts().DisableFree = true;
|
2010-02-19 02:08:43 +08:00
|
|
|
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
|
2010-07-23 08:33:23 +08:00
|
|
|
CaptureDiagnostics, PrecompilePreamble);
|
2009-12-02 11:23:45 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
|
|
|
|
if (!Invocation.get())
|
|
|
|
return true;
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// If we have a preamble file lying around, build or reuse the precompiled
|
|
|
|
// preamble.
|
2010-07-24 08:38:13 +08:00
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
2010-07-24 07:58:40 +08:00
|
|
|
if (!PreambleFile.empty())
|
2010-07-24 08:38:13 +08:00
|
|
|
OverrideMainBuffer = BuildPrecompiledPreamble();
|
2010-07-24 07:58:40 +08:00
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
// Clear out the diagnostics state.
|
|
|
|
getDiagnostics().Reset();
|
|
|
|
|
|
|
|
// Remap files.
|
|
|
|
Invocation->getPreprocessorOpts().clearRemappedFiles();
|
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I)
|
|
|
|
Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
2010-07-24 07:58:40 +08:00
|
|
|
RemappedFiles[I].second);
|
|
|
|
|
|
|
|
// Parse the sources
|
2010-07-24 08:38:13 +08:00
|
|
|
bool Result = Parse(OverrideMainBuffer);
|
|
|
|
delete OverrideMainBuffer;
|
2010-07-24 07:58:40 +08:00
|
|
|
return Result;
|
2010-07-20 05:46:24 +08:00
|
|
|
}
|