blob: a035cd89f60b15b720f73bd7ba146cc68daf7bb7 [file] [log] [blame]
Argyrios Kyrtzidis4b562cf2009-06-20 08:27:14 +00001//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// ASTUnit Implementation.
11//
12//===----------------------------------------------------------------------===//
13
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000014#include "clang/Frontend/ASTUnit.h"
15#include "clang/Frontend/PCHReader.h"
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000016#include "clang/AST/ASTContext.h"
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000017#include "clang/AST/ASTConsumer.h"
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000018#include "clang/AST/DeclVisitor.h"
19#include "clang/AST/StmtVisitor.h"
Daniel Dunbar7b556682009-12-02 03:23:45 +000020#include "clang/Driver/Compilation.h"
21#include "clang/Driver/Driver.h"
22#include "clang/Driver/Job.h"
23#include "clang/Driver/Tool.h"
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000024#include "clang/Frontend/CompilerInstance.h"
25#include "clang/Frontend/FrontendActions.h"
Daniel Dunbar7b556682009-12-02 03:23:45 +000026#include "clang/Frontend/FrontendDiagnostic.h"
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000027#include "clang/Frontend/FrontendOptions.h"
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000028#include "clang/Lex/HeaderSearch.h"
29#include "clang/Lex/Preprocessor.h"
Daniel Dunbard58c03f2009-11-15 06:48:46 +000030#include "clang/Basic/TargetOptions.h"
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000031#include "clang/Basic/TargetInfo.h"
32#include "clang/Basic/Diagnostic.h"
Douglas Gregor4db64a42010-01-23 00:14:00 +000033#include "llvm/Support/MemoryBuffer.h"
Daniel Dunbar7b556682009-12-02 03:23:45 +000034#include "llvm/System/Host.h"
Benjamin Kramer4a630d32009-10-18 11:34:14 +000035#include "llvm/System/Path.h"
Douglas Gregor44c181a2010-07-23 00:33:23 +000036#include <cstdlib>
Zhongxing Xuad23ebe2010-07-23 02:15:08 +000037#include <cstdio>
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000038using namespace clang;
39
Douglas Gregor3687e9d2010-04-05 21:10:19 +000040ASTUnit::ASTUnit(bool _MainFileIsAST)
Douglas Gregorabc563f2010-07-19 21:46:24 +000041 : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
Douglas Gregor28233422010-07-27 14:52:07 +000042 ConcurrencyCheckValue(CheckUnlocked), SavedMainFileBuffer(0) { }
Douglas Gregor3687e9d2010-04-05 21:10:19 +000043
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000044ASTUnit::~ASTUnit() {
Douglas Gregorbdf60622010-03-05 21:16:25 +000045 ConcurrencyCheckValue = CheckLocked;
Douglas Gregorabc563f2010-07-19 21:46:24 +000046 CleanTemporaryFiles();
Douglas Gregor175c4a92010-07-23 23:58:40 +000047 if (!PreambleFile.empty())
48 PreambleFile.eraseFromDisk();
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +000049
50 // Free the buffers associated with remapped files. We are required to
51 // perform this operation here because we explicitly request that the
52 // compiler instance *not* free these buffers for each invocation of the
53 // parser.
54 if (Invocation.get()) {
55 PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
56 for (PreprocessorOptions::remapped_file_buffer_iterator
57 FB = PPOpts.remapped_file_buffer_begin(),
58 FBEnd = PPOpts.remapped_file_buffer_end();
59 FB != FBEnd;
60 ++FB)
61 delete FB->second;
62 }
Douglas Gregor28233422010-07-27 14:52:07 +000063
64 delete SavedMainFileBuffer;
Douglas Gregorabc563f2010-07-19 21:46:24 +000065}
66
67void ASTUnit::CleanTemporaryFiles() {
Douglas Gregor313e26c2010-02-18 23:35:40 +000068 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
69 TemporaryFiles[I].eraseFromDisk();
Douglas Gregorabc563f2010-07-19 21:46:24 +000070 TemporaryFiles.clear();
Steve Naroffe19944c2009-10-15 22:23:48 +000071}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000072
73namespace {
74
75/// \brief Gathers information from PCHReader that will be used to initialize
76/// a Preprocessor.
Benjamin Kramerbd218282009-11-28 10:07:24 +000077class PCHInfoCollector : public PCHReaderListener {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000078 LangOptions &LangOpt;
79 HeaderSearch &HSI;
80 std::string &TargetTriple;
81 std::string &Predefines;
82 unsigned &Counter;
Mike Stump1eb44332009-09-09 15:08:12 +000083
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000084 unsigned NumHeaderInfos;
Mike Stump1eb44332009-09-09 15:08:12 +000085
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000086public:
87 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
88 std::string &TargetTriple, std::string &Predefines,
89 unsigned &Counter)
90 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
91 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000092
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000093 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
94 LangOpt = LangOpts;
95 return false;
96 }
Mike Stump1eb44332009-09-09 15:08:12 +000097
Daniel Dunbardc3c0d22009-11-11 00:52:11 +000098 virtual bool ReadTargetTriple(llvm::StringRef Triple) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000099 TargetTriple = Triple;
100 return false;
101 }
Mike Stump1eb44332009-09-09 15:08:12 +0000102
Sebastian Redlcb481aa2010-07-14 23:29:55 +0000103 virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
Daniel Dunbar7b5a1212009-11-11 05:29:04 +0000104 llvm::StringRef OriginalFileName,
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000105 std::string &SuggestedPredefines) {
Sebastian Redlcb481aa2010-07-14 23:29:55 +0000106 Predefines = Buffers[0].Data;
107 for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
108 Predefines += Buffers[I].Data;
109 }
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000110 return false;
111 }
Mike Stump1eb44332009-09-09 15:08:12 +0000112
Douglas Gregorec1afbf2010-03-16 19:09:18 +0000113 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000114 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
115 }
Mike Stump1eb44332009-09-09 15:08:12 +0000116
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000117 virtual void ReadCounter(unsigned Value) {
118 Counter = Value;
119 }
120};
121
Douglas Gregora88084b2010-02-18 18:08:43 +0000122class StoredDiagnosticClient : public DiagnosticClient {
123 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
124
125public:
126 explicit StoredDiagnosticClient(
127 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
128 : StoredDiags(StoredDiags) { }
129
130 virtual void HandleDiagnostic(Diagnostic::Level Level,
131 const DiagnosticInfo &Info);
132};
133
134/// \brief RAII object that optionally captures diagnostics, if
135/// there is no diagnostic client to capture them already.
136class CaptureDroppedDiagnostics {
137 Diagnostic &Diags;
138 StoredDiagnosticClient Client;
139 DiagnosticClient *PreviousClient;
140
141public:
142 CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
143 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
144 : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
145 {
146 if (RequestCapture || Diags.getClient() == 0)
147 Diags.setClient(&Client);
148 }
149
150 ~CaptureDroppedDiagnostics() {
151 Diags.setClient(PreviousClient);
152 }
153};
154
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000155} // anonymous namespace
156
Douglas Gregora88084b2010-02-18 18:08:43 +0000157void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
158 const DiagnosticInfo &Info) {
159 StoredDiags.push_back(StoredDiagnostic(Level, Info));
160}
161
Steve Naroff77accc12009-09-03 18:19:54 +0000162const std::string &ASTUnit::getOriginalSourceFileName() {
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000163 return OriginalSourceFile;
Steve Naroff77accc12009-09-03 18:19:54 +0000164}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000165
Steve Naroffe19944c2009-10-15 22:23:48 +0000166const std::string &ASTUnit::getPCHFileName() {
Daniel Dunbarc7822db2009-12-02 21:47:43 +0000167 assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
Benjamin Kramer7297c182010-01-30 16:23:25 +0000168 return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
Steve Naroffe19944c2009-10-15 22:23:48 +0000169}
170
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000171ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Douglas Gregor28019772010-04-05 23:52:57 +0000172 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Ted Kremenek5cf48762009-10-17 00:34:24 +0000173 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000174 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000175 unsigned NumRemappedFiles,
176 bool CaptureDiagnostics) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000177 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
178
Douglas Gregor28019772010-04-05 23:52:57 +0000179 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000180 // No diagnostics engine was provided, so create our own diagnostics object
181 // with the default options.
182 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000183 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000184 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000185
186 AST->CaptureDiagnostics = CaptureDiagnostics;
Douglas Gregor7d1d49d2009-10-16 20:01:17 +0000187 AST->OnlyLocalDecls = OnlyLocalDecls;
Douglas Gregor28019772010-04-05 23:52:57 +0000188 AST->Diagnostics = Diags;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000189 AST->FileMgr.reset(new FileManager);
190 AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
Steve Naroff36c44642009-10-19 14:34:22 +0000191 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000192
Douglas Gregora88084b2010-02-18 18:08:43 +0000193 // If requested, capture diagnostics in the ASTUnit.
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000194 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
Douglas Gregor405634b2010-04-05 18:10:21 +0000195 AST->StoredDiagnostics);
Douglas Gregora88084b2010-02-18 18:08:43 +0000196
Douglas Gregor4db64a42010-01-23 00:14:00 +0000197 for (unsigned I = 0; I != NumRemappedFiles; ++I) {
198 // Create the file entry for the file that we're mapping from.
199 const FileEntry *FromFile
200 = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
201 RemappedFiles[I].second->getBufferSize(),
202 0);
203 if (!FromFile) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000204 AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
Douglas Gregor4db64a42010-01-23 00:14:00 +0000205 << RemappedFiles[I].first;
Douglas Gregorc8dfe5e2010-02-27 01:32:48 +0000206 delete RemappedFiles[I].second;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000207 continue;
208 }
209
210 // Override the contents of the "from" file with the contents of
211 // the "to" file.
212 AST->getSourceManager().overrideFileContents(FromFile,
213 RemappedFiles[I].second);
214 }
215
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000216 // Gather Info for preprocessor construction later on.
Mike Stump1eb44332009-09-09 15:08:12 +0000217
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000218 LangOptions LangInfo;
219 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
220 std::string TargetTriple;
221 std::string Predefines;
222 unsigned Counter;
223
Daniel Dunbarbce6f622009-09-03 05:59:50 +0000224 llvm::OwningPtr<PCHReader> Reader;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000225 llvm::OwningPtr<ExternalASTSource> Source;
226
Ted Kremenekfc062212009-10-19 21:44:57 +0000227 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000228 AST->getDiagnostics()));
Daniel Dunbarcc318932009-09-03 05:59:35 +0000229 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
230 Predefines, Counter));
231
232 switch (Reader->ReadPCH(Filename)) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000233 case PCHReader::Success:
234 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000235
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000236 case PCHReader::Failure:
Argyrios Kyrtzidis106c9982009-06-25 18:22:30 +0000237 case PCHReader::IgnorePCH:
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000238 AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000239 return NULL;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000240 }
Mike Stump1eb44332009-09-09 15:08:12 +0000241
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000242 AST->OriginalSourceFile = Reader->getOriginalSourceFile();
243
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000244 // PCH loaded successfully. Now create the preprocessor.
Mike Stump1eb44332009-09-09 15:08:12 +0000245
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000246 // Get information about the target being compiled for.
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000247 //
248 // FIXME: This is broken, we should store the TargetOptions in the PCH.
249 TargetOptions TargetOpts;
250 TargetOpts.ABI = "";
Charles Davis98b7c5c2010-06-11 01:06:47 +0000251 TargetOpts.CXXABI = "itanium";
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000252 TargetOpts.CPU = "";
253 TargetOpts.Features.clear();
254 TargetOpts.Triple = TargetTriple;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000255 AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
256 TargetOpts));
257 AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
258 *AST->Target.get(),
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000259 AST->getSourceManager(), HeaderInfo));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000260 Preprocessor &PP = *AST->PP.get();
261
Daniel Dunbard5b61262009-09-21 03:03:47 +0000262 PP.setPredefines(Reader->getSuggestedPredefines());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000263 PP.setCounterValue(Counter);
Daniel Dunbarcc318932009-09-03 05:59:35 +0000264 Reader->setPreprocessor(PP);
Mike Stump1eb44332009-09-09 15:08:12 +0000265
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000266 // Create and initialize the ASTContext.
267
268 AST->Ctx.reset(new ASTContext(LangInfo,
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000269 AST->getSourceManager(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000270 *AST->Target.get(),
271 PP.getIdentifierTable(),
272 PP.getSelectorTable(),
273 PP.getBuiltinInfo(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000274 /* size_reserve = */0));
275 ASTContext &Context = *AST->Ctx.get();
Mike Stump1eb44332009-09-09 15:08:12 +0000276
Daniel Dunbarcc318932009-09-03 05:59:35 +0000277 Reader->InitializeContext(Context);
Mike Stump1eb44332009-09-09 15:08:12 +0000278
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000279 // Attach the PCH reader to the AST context as an external AST
280 // source, so that declarations will be deserialized from the
281 // PCH file as needed.
Daniel Dunbarcc318932009-09-03 05:59:35 +0000282 Source.reset(Reader.take());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000283 Context.setExternalSource(Source);
284
Mike Stump1eb44332009-09-09 15:08:12 +0000285 return AST.take();
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000286}
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000287
288namespace {
289
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000290class TopLevelDeclTrackerConsumer : public ASTConsumer {
291 ASTUnit &Unit;
292
293public:
294 TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
295
296 void HandleTopLevelDecl(DeclGroupRef D) {
Ted Kremenekda5a4282010-05-03 20:16:35 +0000297 for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
298 Decl *D = *it;
299 // FIXME: Currently ObjC method declarations are incorrectly being
300 // reported as top-level declarations, even though their DeclContext
301 // is the containing ObjC @interface/@implementation. This is a
302 // fundamental problem in the parser right now.
303 if (isa<ObjCMethodDecl>(D))
304 continue;
305 Unit.getTopLevelDecls().push_back(D);
306 }
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000307 }
308};
309
310class TopLevelDeclTrackerAction : public ASTFrontendAction {
311public:
312 ASTUnit &Unit;
313
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000314 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
315 llvm::StringRef InFile) {
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000316 return new TopLevelDeclTrackerConsumer(Unit);
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000317 }
318
319public:
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000320 TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
321
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000322 virtual bool hasCodeCompletionSupport() const { return false; }
323};
324
325}
326
Douglas Gregorabc563f2010-07-19 21:46:24 +0000327/// Parse the source file into a translation unit using the given compiler
328/// invocation, replacing the current translation unit.
329///
330/// \returns True if a failure occurred that causes the ASTUnit not to
331/// contain any translation-unit information, false otherwise.
Douglas Gregor754f3492010-07-24 00:38:13 +0000332bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Douglas Gregor28233422010-07-27 14:52:07 +0000333 delete SavedMainFileBuffer;
334 SavedMainFileBuffer = 0;
335
Douglas Gregorabc563f2010-07-19 21:46:24 +0000336 if (!Invocation.get())
337 return true;
338
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000339 // Create the compiler instance to use for building the AST.
Daniel Dunbarcb6dda12009-12-02 08:43:56 +0000340 CompilerInstance Clang;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000341 Clang.setInvocation(Invocation.take());
342 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
343
344 // Set up diagnostics.
345 Clang.setDiagnostics(&getDiagnostics());
346 Clang.setDiagnosticClient(getDiagnostics().getClient());
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000347
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000348 // Create the target instance.
349 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
350 Clang.getTargetOpts()));
Douglas Gregora88084b2010-02-18 18:08:43 +0000351 if (!Clang.hasTarget()) {
Douglas Gregora88084b2010-02-18 18:08:43 +0000352 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000353 return true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000354 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000355
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000356 // Inform the target of the language options.
357 //
358 // FIXME: We shouldn't need to do this, the target should be immutable once
359 // created. This complexity should be lifted elsewhere.
360 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
Douglas Gregorabc563f2010-07-19 21:46:24 +0000361
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000362 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
363 "Invocation must have exactly one source file!");
Daniel Dunbarc34ce3f2010-06-07 23:22:09 +0000364 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000365 "FIXME: AST inputs not yet supported here!");
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000366 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
367 "IR inputs not support here!");
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000368
Douglas Gregorabc563f2010-07-19 21:46:24 +0000369 // Configure the various subsystems.
370 // FIXME: Should we retain the previous file manager?
371 FileMgr.reset(new FileManager);
372 SourceMgr.reset(new SourceManager(getDiagnostics()));
373 Ctx.reset();
374 PP.reset();
375
376 // Clear out old caches and data.
377 TopLevelDecls.clear();
378 StoredDiagnostics.clear();
379 CleanTemporaryFiles();
380 PreprocessedEntitiesByFile.clear();
381
Douglas Gregora88084b2010-02-18 18:08:43 +0000382 // Capture any diagnostics that would otherwise be dropped.
383 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
384 Clang.getDiagnostics(),
Douglas Gregorabc563f2010-07-19 21:46:24 +0000385 StoredDiagnostics);
386
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000387 // Create a file manager object to provide access to and cache the filesystem.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000388 Clang.setFileManager(&getFileManager());
389
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000390 // Create the source manager.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000391 Clang.setSourceManager(&getSourceManager());
392
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000393 // If the main file has been overridden due to the use of a preamble,
394 // make that override happen and introduce the preamble.
395 PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts();
396 if (OverrideMainBuffer) {
397 PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
398 PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
399 PreprocessorOpts.PrecompiledPreambleBytes.second
400 = PreambleEndsAtStartOfLine;
401 PreprocessorOpts.ImplicitPCHInclude = PreambleFile.str();
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000402 PreprocessorOpts.DisablePCHValidation = true;
Douglas Gregor28233422010-07-27 14:52:07 +0000403
404 // Keep track of the override buffer;
405 SavedMainFileBuffer = OverrideMainBuffer;
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000406 }
407
Douglas Gregorabc563f2010-07-19 21:46:24 +0000408 llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
409 Act.reset(new TopLevelDeclTrackerAction(*this));
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000410 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
Daniel Dunbard3598a62010-06-07 23:23:06 +0000411 Clang.getFrontendOpts().Inputs[0].first))
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000412 goto error;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000413
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000414 Act->Execute();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000415
Daniel Dunbar64a32ba2009-12-01 21:57:33 +0000416 // Steal the created target, context, and preprocessor, and take back the
417 // source and file managers.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000418 Ctx.reset(Clang.takeASTContext());
419 PP.reset(Clang.takePreprocessor());
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000420 Clang.takeSourceManager();
421 Clang.takeFileManager();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000422 Target.reset(Clang.takeTarget());
423
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000424 Act->EndSourceFile();
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000425
426 // Remove the overridden buffer we used for the preamble.
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000427 if (OverrideMainBuffer) {
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000428 PreprocessorOpts.eraseRemappedFile(
429 PreprocessorOpts.remapped_file_buffer_end() - 1);
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000430 PreprocessorOpts.DisablePCHValidation = true;
431 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000432
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000433 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000434
435 Invocation.reset(Clang.takeInvocation());
436 return false;
437
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000438error:
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000439 // Remove the overridden buffer we used for the preamble.
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000440 if (OverrideMainBuffer) {
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000441 PreprocessorOpts.eraseRemappedFile(
442 PreprocessorOpts.remapped_file_buffer_end() - 1);
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000443 PreprocessorOpts.DisablePCHValidation = true;
444 }
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000445
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000446 Clang.takeSourceManager();
447 Clang.takeFileManager();
448 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000449 Invocation.reset(Clang.takeInvocation());
450 return true;
451}
452
Douglas Gregor44c181a2010-07-23 00:33:23 +0000453/// \brief Simple function to retrieve a path for a preamble precompiled header.
454static std::string GetPreamblePCHPath() {
455 // FIXME: This is lame; sys::Path should provide this function (in particular,
456 // it should know how to find the temporary files dir).
457 // FIXME: This is really lame. I copied this code from the Driver!
458 std::string Error;
459 const char *TmpDir = ::getenv("TMPDIR");
460 if (!TmpDir)
461 TmpDir = ::getenv("TEMP");
462 if (!TmpDir)
463 TmpDir = ::getenv("TMP");
464 if (!TmpDir)
465 TmpDir = "/tmp";
466 llvm::sys::Path P(TmpDir);
467 P.appendComponent("preamble");
468 if (P.createTemporaryFileOnDisk())
469 return std::string();
470
471 P.appendSuffix("pch");
472 return P.str();
473}
474
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000475/// \brief Compute the preamble for the main file, providing the source buffer
476/// that corresponds to the main file along with a pair (bytes, start-of-line)
477/// that describes the preamble.
478std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
Douglas Gregor175c4a92010-07-23 23:58:40 +0000479ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
480 FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000481 PreprocessorOptions &PreprocessorOpts
Douglas Gregor175c4a92010-07-23 23:58:40 +0000482 = Invocation.getPreprocessorOpts();
483 CreatedBuffer = false;
484
Douglas Gregor44c181a2010-07-23 00:33:23 +0000485 // Try to determine if the main file has been remapped, either from the
486 // command line (to another file) or directly through the compiler invocation
487 // (to a memory buffer).
Douglas Gregor175c4a92010-07-23 23:58:40 +0000488 llvm::MemoryBuffer *Buffer = 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000489 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
490 if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
491 // Check whether there is a file-file remapping of the main file
492 for (PreprocessorOptions::remapped_file_iterator
Douglas Gregor175c4a92010-07-23 23:58:40 +0000493 M = PreprocessorOpts.remapped_file_begin(),
494 E = PreprocessorOpts.remapped_file_end();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000495 M != E;
496 ++M) {
497 llvm::sys::PathWithStatus MPath(M->first);
498 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
499 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
500 // We found a remapping. Try to load the resulting, remapped source.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000501 if (CreatedBuffer) {
Douglas Gregor44c181a2010-07-23 00:33:23 +0000502 delete Buffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000503 CreatedBuffer = false;
504 }
505
Douglas Gregor44c181a2010-07-23 00:33:23 +0000506 Buffer = llvm::MemoryBuffer::getFile(M->second);
507 if (!Buffer)
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000508 return std::make_pair((llvm::MemoryBuffer*)0,
509 std::make_pair(0, true));
Douglas Gregor175c4a92010-07-23 23:58:40 +0000510 CreatedBuffer = true;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000511
Douglas Gregor175c4a92010-07-23 23:58:40 +0000512 // Remove this remapping. We've captured the buffer already.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000513 M = PreprocessorOpts.eraseRemappedFile(M);
514 E = PreprocessorOpts.remapped_file_end();
515 }
516 }
517 }
518
519 // Check whether there is a file-buffer remapping. It supercedes the
520 // file-file remapping.
521 for (PreprocessorOptions::remapped_file_buffer_iterator
522 M = PreprocessorOpts.remapped_file_buffer_begin(),
523 E = PreprocessorOpts.remapped_file_buffer_end();
524 M != E;
525 ++M) {
526 llvm::sys::PathWithStatus MPath(M->first);
527 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
528 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
529 // We found a remapping.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000530 if (CreatedBuffer) {
Douglas Gregor44c181a2010-07-23 00:33:23 +0000531 delete Buffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000532 CreatedBuffer = false;
533 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000534
Douglas Gregor175c4a92010-07-23 23:58:40 +0000535 Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
536
537 // Remove this remapping. We've captured the buffer already.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000538 M = PreprocessorOpts.eraseRemappedFile(M);
539 E = PreprocessorOpts.remapped_file_buffer_end();
540 }
541 }
Douglas Gregor175c4a92010-07-23 23:58:40 +0000542 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000543 }
544
545 // If the main source file was not remapped, load it now.
546 if (!Buffer) {
547 Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
548 if (!Buffer)
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000549 return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
Douglas Gregor175c4a92010-07-23 23:58:40 +0000550
551 CreatedBuffer = true;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000552 }
553
Douglas Gregor175c4a92010-07-23 23:58:40 +0000554 return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer));
555}
556
Douglas Gregor754f3492010-07-24 00:38:13 +0000557static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
558 bool DeleteOld,
559 unsigned NewSize,
560 llvm::StringRef NewName) {
561 llvm::MemoryBuffer *Result
562 = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
563 memcpy(const_cast<char*>(Result->getBufferStart()),
564 Old->getBufferStart(), Old->getBufferSize());
565 memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000566 ' ', NewSize - Old->getBufferSize() - 1);
567 const_cast<char*>(Result->getBufferEnd())[-1] = '\n';
Douglas Gregor754f3492010-07-24 00:38:13 +0000568
569 if (DeleteOld)
570 delete Old;
571
572 return Result;
573}
574
Douglas Gregor175c4a92010-07-23 23:58:40 +0000575/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
576/// the source file.
577///
578/// This routine will compute the preamble of the main source file. If a
579/// non-trivial preamble is found, it will precompile that preamble into a
580/// precompiled header so that the precompiled preamble can be used to reduce
581/// reparsing time. If a precompiled preamble has already been constructed,
582/// this routine will determine if it is still valid and, if so, avoid
583/// rebuilding the precompiled preamble.
584///
Douglas Gregor754f3492010-07-24 00:38:13 +0000585/// \returns If the precompiled preamble can be used, returns a newly-allocated
586/// buffer that should be used in place of the main file when doing so.
587/// Otherwise, returns a NULL pointer.
588llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000589 CompilerInvocation PreambleInvocation(*Invocation);
590 FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
591 PreprocessorOptions &PreprocessorOpts
592 = PreambleInvocation.getPreprocessorOpts();
593
594 bool CreatedPreambleBuffer = false;
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000595 std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
Douglas Gregor175c4a92010-07-23 23:58:40 +0000596 = ComputePreamble(PreambleInvocation, CreatedPreambleBuffer);
597
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000598 if (!NewPreamble.second.first) {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000599 // We couldn't find a preamble in the main source. Clear out the current
600 // preamble, if we have one. It's obviously no good any more.
601 Preamble.clear();
602 if (!PreambleFile.empty()) {
603 PreambleFile.eraseFromDisk();
604 PreambleFile.clear();
605 }
606 if (CreatedPreambleBuffer)
607 delete NewPreamble.first;
608
Douglas Gregor754f3492010-07-24 00:38:13 +0000609 return 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000610 }
611
612 if (!Preamble.empty()) {
613 // We've previously computed a preamble. Check whether we have the same
614 // preamble now that we did before, and that there's enough space in
615 // the main-file buffer within the precompiled preamble to fit the
616 // new main file.
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000617 if (Preamble.size() == NewPreamble.second.first &&
618 PreambleEndsAtStartOfLine == NewPreamble.second.second &&
Douglas Gregor592508e2010-07-24 00:42:07 +0000619 NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
Douglas Gregor175c4a92010-07-23 23:58:40 +0000620 memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000621 NewPreamble.second.first) == 0) {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000622 // The preamble has not changed. We may be able to re-use the precompiled
623 // preamble.
624 // FIXME: Check that none of the files used by the preamble have changed.
625
Douglas Gregor754f3492010-07-24 00:38:13 +0000626
Douglas Gregor175c4a92010-07-23 23:58:40 +0000627 // Okay! Re-use the precompiled preamble.
Douglas Gregor754f3492010-07-24 00:38:13 +0000628 return CreatePaddedMainFileBuffer(NewPreamble.first,
629 CreatedPreambleBuffer,
630 PreambleReservedSize,
631 FrontendOpts.Inputs[0].second);
Douglas Gregor175c4a92010-07-23 23:58:40 +0000632 }
633
634 // We can't reuse the previously-computed preamble. Build a new one.
635 Preamble.clear();
636 PreambleFile.eraseFromDisk();
637 }
638
639 // We did not previously compute a preamble, or it can't be reused anyway.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000640
641 // Create a new buffer that stores the preamble. The buffer also contains
642 // extra space for the original contents of the file (which will be present
643 // when we actually parse the file) along with more room in case the file
Douglas Gregor175c4a92010-07-23 23:58:40 +0000644 // grows.
645 PreambleReservedSize = NewPreamble.first->getBufferSize();
646 if (PreambleReservedSize < 4096)
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000647 PreambleReservedSize = 8191;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000648 else
Douglas Gregor175c4a92010-07-23 23:58:40 +0000649 PreambleReservedSize *= 2;
650
Douglas Gregor44c181a2010-07-23 00:33:23 +0000651 llvm::MemoryBuffer *PreambleBuffer
Douglas Gregor175c4a92010-07-23 23:58:40 +0000652 = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000653 FrontendOpts.Inputs[0].second);
654 memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
Douglas Gregor175c4a92010-07-23 23:58:40 +0000655 NewPreamble.first->getBufferStart(), Preamble.size());
656 memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000657 ' ', PreambleReservedSize - Preamble.size() - 1);
658 const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
Douglas Gregor592508e2010-07-24 00:42:07 +0000659
Douglas Gregor175c4a92010-07-23 23:58:40 +0000660 // Save the preamble text for later; we'll need to compare against it for
661 // subsequent reparses.
662 Preamble.assign(NewPreamble.first->getBufferStart(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000663 NewPreamble.first->getBufferStart()
664 + NewPreamble.second.first);
665 PreambleEndsAtStartOfLine = NewPreamble.second.second;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000666
667 // Remap the main source file to the preamble buffer.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000668 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000669 PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
670
671 // Tell the compiler invocation to generate a temporary precompiled header.
672 FrontendOpts.ProgramAction = frontend::GeneratePCH;
673 // FIXME: Set ChainedPCH, once it is ready.
674 // FIXME: Generate the precompiled header into memory?
Douglas Gregor175c4a92010-07-23 23:58:40 +0000675 if (PreambleFile.isEmpty())
676 FrontendOpts.OutputFile = GetPreamblePCHPath();
677 else
678 FrontendOpts.OutputFile = PreambleFile.str();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000679
680 // Create the compiler instance to use for building the precompiled preamble.
681 CompilerInstance Clang;
682 Clang.setInvocation(&PreambleInvocation);
683 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
684
685 // Set up diagnostics.
686 Clang.setDiagnostics(&getDiagnostics());
687 Clang.setDiagnosticClient(getDiagnostics().getClient());
688
689 // Create the target instance.
690 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
691 Clang.getTargetOpts()));
692 if (!Clang.hasTarget()) {
693 Clang.takeDiagnosticClient();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000694 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
695 Preamble.clear();
696 if (CreatedPreambleBuffer)
697 delete NewPreamble.first;
698
Douglas Gregor754f3492010-07-24 00:38:13 +0000699 return 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000700 }
701
702 // Inform the target of the language options.
703 //
704 // FIXME: We shouldn't need to do this, the target should be immutable once
705 // created. This complexity should be lifted elsewhere.
706 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
707
708 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
709 "Invocation must have exactly one source file!");
710 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
711 "FIXME: AST inputs not yet supported here!");
712 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
713 "IR inputs not support here!");
714
715 // Clear out old caches and data.
716 StoredDiagnostics.clear();
717
718 // Capture any diagnostics that would otherwise be dropped.
719 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
720 Clang.getDiagnostics(),
721 StoredDiagnostics);
722
723 // Create a file manager object to provide access to and cache the filesystem.
724 Clang.setFileManager(new FileManager);
725
726 // Create the source manager.
727 Clang.setSourceManager(new SourceManager(getDiagnostics()));
728
729 // FIXME: Eventually, we'll have to track top-level declarations here, too.
730 llvm::OwningPtr<GeneratePCHAction> Act;
731 Act.reset(new GeneratePCHAction);
732 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
733 Clang.getFrontendOpts().Inputs[0].first)) {
734 Clang.takeDiagnosticClient();
735 Clang.takeInvocation();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000736 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
737 Preamble.clear();
738 if (CreatedPreambleBuffer)
739 delete NewPreamble.first;
740
Douglas Gregor754f3492010-07-24 00:38:13 +0000741 return 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000742 }
743
744 Act->Execute();
745 Act->EndSourceFile();
746 Clang.takeDiagnosticClient();
747 Clang.takeInvocation();
748
Douglas Gregor175c4a92010-07-23 23:58:40 +0000749 if (Diagnostics->getNumErrors() > 0) {
750 // There were errors parsing the preamble, so no precompiled header was
751 // generated. Forget that we even tried.
752 // FIXME: Should we leave a note for ourselves to try again?
753 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
754 Preamble.clear();
755 if (CreatedPreambleBuffer)
756 delete NewPreamble.first;
757
Douglas Gregor754f3492010-07-24 00:38:13 +0000758 return 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000759 }
760
761 // Keep track of the preamble we precompiled.
762 PreambleFile = FrontendOpts.OutputFile;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000763 fprintf(stderr, "Preamble PCH: %s\n", FrontendOpts.OutputFile.c_str());
Douglas Gregor754f3492010-07-24 00:38:13 +0000764 return CreatePaddedMainFileBuffer(NewPreamble.first,
765 CreatedPreambleBuffer,
766 PreambleReservedSize,
767 FrontendOpts.Inputs[0].second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000768}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000769
770ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
771 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
772 bool OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000773 bool CaptureDiagnostics,
774 bool PrecompilePreamble) {
Douglas Gregorabc563f2010-07-19 21:46:24 +0000775 if (!Diags.getPtr()) {
776 // No diagnostics engine was provided, so create our own diagnostics object
777 // with the default options.
778 DiagnosticOptions DiagOpts;
779 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
780 }
781
782 // Create the AST unit.
783 llvm::OwningPtr<ASTUnit> AST;
784 AST.reset(new ASTUnit(false));
785 AST->Diagnostics = Diags;
786 AST->CaptureDiagnostics = CaptureDiagnostics;
787 AST->OnlyLocalDecls = OnlyLocalDecls;
788 AST->Invocation.reset(CI);
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000789 CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000790
Douglas Gregor754f3492010-07-24 00:38:13 +0000791 llvm::MemoryBuffer *OverrideMainBuffer = 0;
Douglas Gregorfd0b8702010-07-28 22:12:37 +0000792 // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
793 if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus)
Douglas Gregor754f3492010-07-24 00:38:13 +0000794 OverrideMainBuffer = AST->BuildPrecompiledPreamble();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000795
Douglas Gregor754f3492010-07-24 00:38:13 +0000796 if (!AST->Parse(OverrideMainBuffer))
Douglas Gregorabc563f2010-07-19 21:46:24 +0000797 return AST.take();
798
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000799 return 0;
800}
Daniel Dunbar7b556682009-12-02 03:23:45 +0000801
802ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
803 const char **ArgEnd,
Douglas Gregor28019772010-04-05 23:52:57 +0000804 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Daniel Dunbar869824e2009-12-13 03:46:13 +0000805 llvm::StringRef ResourceFilesPath,
Daniel Dunbar7b556682009-12-02 03:23:45 +0000806 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000807 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000808 unsigned NumRemappedFiles,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000809 bool CaptureDiagnostics,
810 bool PrecompilePreamble) {
Douglas Gregor28019772010-04-05 23:52:57 +0000811 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000812 // No diagnostics engine was provided, so create our own diagnostics object
813 // with the default options.
814 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000815 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000816 }
817
Daniel Dunbar7b556682009-12-02 03:23:45 +0000818 llvm::SmallVector<const char *, 16> Args;
819 Args.push_back("<clang>"); // FIXME: Remove dummy argument.
820 Args.insert(Args.end(), ArgBegin, ArgEnd);
821
822 // FIXME: Find a cleaner way to force the driver into restricted modes. We
823 // also want to force it to use clang.
824 Args.push_back("-fsyntax-only");
825
Daniel Dunbar869824e2009-12-13 03:46:13 +0000826 // FIXME: We shouldn't have to pass in the path info.
Daniel Dunbar0bbad512010-07-19 00:44:04 +0000827 driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000828 "a.out", false, false, *Diags);
Daniel Dunbar3bd54cc2010-01-25 00:44:02 +0000829
830 // Don't check that inputs exist, they have been remapped.
831 TheDriver.setCheckInputsExist(false);
832
Daniel Dunbar7b556682009-12-02 03:23:45 +0000833 llvm::OwningPtr<driver::Compilation> C(
834 TheDriver.BuildCompilation(Args.size(), Args.data()));
835
836 // We expect to get back exactly one command job, if we didn't something
837 // failed.
838 const driver::JobList &Jobs = C->getJobs();
839 if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
840 llvm::SmallString<256> Msg;
841 llvm::raw_svector_ostream OS(Msg);
842 C->PrintJob(OS, C->getJobs(), "; ", true);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000843 Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
Daniel Dunbar7b556682009-12-02 03:23:45 +0000844 return 0;
845 }
846
847 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
848 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000849 Diags->Report(diag::err_fe_expected_clang_command);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000850 return 0;
851 }
852
853 const driver::ArgStringList &CCArgs = Cmd->getArguments();
Daniel Dunbar807b0612010-01-30 21:47:16 +0000854 llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
Dan Gohmancb421fa2010-04-19 16:39:44 +0000855 CompilerInvocation::CreateFromArgs(*CI,
856 const_cast<const char **>(CCArgs.data()),
857 const_cast<const char **>(CCArgs.data()) +
Douglas Gregor44c181a2010-07-23 00:33:23 +0000858 CCArgs.size(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000859 *Diags);
Daniel Dunbar1e69fe32009-12-13 03:45:58 +0000860
Douglas Gregor4db64a42010-01-23 00:14:00 +0000861 // Override any files that need remapping
862 for (unsigned I = 0; I != NumRemappedFiles; ++I)
Daniel Dunbar807b0612010-01-30 21:47:16 +0000863 CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000864 RemappedFiles[I].second);
Douglas Gregor4db64a42010-01-23 00:14:00 +0000865
Daniel Dunbar8b9adfe2009-12-15 00:06:45 +0000866 // Override the resources path.
Daniel Dunbar807b0612010-01-30 21:47:16 +0000867 CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
Daniel Dunbar7b556682009-12-02 03:23:45 +0000868
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000869 CI->getFrontendOpts().DisableFree = true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000870 return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000871 CaptureDiagnostics, PrecompilePreamble);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000872}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000873
874bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
875 if (!Invocation.get())
876 return true;
877
Douglas Gregor175c4a92010-07-23 23:58:40 +0000878 // If we have a preamble file lying around, build or reuse the precompiled
879 // preamble.
Douglas Gregor754f3492010-07-24 00:38:13 +0000880 llvm::MemoryBuffer *OverrideMainBuffer = 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000881 if (!PreambleFile.empty())
Douglas Gregor754f3492010-07-24 00:38:13 +0000882 OverrideMainBuffer = BuildPrecompiledPreamble();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000883
Douglas Gregorabc563f2010-07-19 21:46:24 +0000884 // Clear out the diagnostics state.
885 getDiagnostics().Reset();
886
887 // Remap files.
888 Invocation->getPreprocessorOpts().clearRemappedFiles();
889 for (unsigned I = 0; I != NumRemappedFiles; ++I)
890 Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Douglas Gregor175c4a92010-07-23 23:58:40 +0000891 RemappedFiles[I].second);
892
893 // Parse the sources
Douglas Gregor754f3492010-07-24 00:38:13 +0000894 bool Result = Parse(OverrideMainBuffer);
Douglas Gregor175c4a92010-07-23 23:58:40 +0000895 return Result;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000896}