blob: 7f42fa949e5bb2a3ef7e5a1b168685f441fa39d2 [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 Gregor385103b2010-07-30 20:58:08 +000036#include "llvm/Support/Timer.h"
Douglas Gregor44c181a2010-07-23 00:33:23 +000037#include <cstdlib>
Zhongxing Xuad23ebe2010-07-23 02:15:08 +000038#include <cstdio>
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000039using namespace clang;
40
Douglas Gregor3687e9d2010-04-05 21:10:19 +000041ASTUnit::ASTUnit(bool _MainFileIsAST)
Douglas Gregorabc563f2010-07-19 21:46:24 +000042 : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
Douglas Gregor385103b2010-07-30 20:58:08 +000043 ConcurrencyCheckValue(CheckUnlocked), SavedMainFileBuffer(0) {
44}
Douglas Gregor3687e9d2010-04-05 21:10:19 +000045
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000046ASTUnit::~ASTUnit() {
Douglas Gregorbdf60622010-03-05 21:16:25 +000047 ConcurrencyCheckValue = CheckLocked;
Douglas Gregorabc563f2010-07-19 21:46:24 +000048 CleanTemporaryFiles();
Douglas Gregor175c4a92010-07-23 23:58:40 +000049 if (!PreambleFile.empty())
Douglas Gregor385103b2010-07-30 20:58:08 +000050 llvm::sys::Path(PreambleFile).eraseFromDisk();
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +000051
52 // Free the buffers associated with remapped files. We are required to
53 // perform this operation here because we explicitly request that the
54 // compiler instance *not* free these buffers for each invocation of the
55 // parser.
56 if (Invocation.get()) {
57 PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
58 for (PreprocessorOptions::remapped_file_buffer_iterator
59 FB = PPOpts.remapped_file_buffer_begin(),
60 FBEnd = PPOpts.remapped_file_buffer_end();
61 FB != FBEnd;
62 ++FB)
63 delete FB->second;
64 }
Douglas Gregor28233422010-07-27 14:52:07 +000065
66 delete SavedMainFileBuffer;
Douglas Gregor385103b2010-07-30 20:58:08 +000067
68 for (unsigned I = 0, N = Timers.size(); I != N; ++I)
69 delete Timers[I];
Douglas Gregorabc563f2010-07-19 21:46:24 +000070}
71
72void ASTUnit::CleanTemporaryFiles() {
Douglas Gregor313e26c2010-02-18 23:35:40 +000073 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
74 TemporaryFiles[I].eraseFromDisk();
Douglas Gregorabc563f2010-07-19 21:46:24 +000075 TemporaryFiles.clear();
Steve Naroffe19944c2009-10-15 22:23:48 +000076}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000077
78namespace {
79
80/// \brief Gathers information from PCHReader that will be used to initialize
81/// a Preprocessor.
Benjamin Kramerbd218282009-11-28 10:07:24 +000082class PCHInfoCollector : public PCHReaderListener {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000083 LangOptions &LangOpt;
84 HeaderSearch &HSI;
85 std::string &TargetTriple;
86 std::string &Predefines;
87 unsigned &Counter;
Mike Stump1eb44332009-09-09 15:08:12 +000088
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000089 unsigned NumHeaderInfos;
Mike Stump1eb44332009-09-09 15:08:12 +000090
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000091public:
92 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
93 std::string &TargetTriple, std::string &Predefines,
94 unsigned &Counter)
95 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
96 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000097
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000098 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
99 LangOpt = LangOpts;
100 return false;
101 }
Mike Stump1eb44332009-09-09 15:08:12 +0000102
Daniel Dunbardc3c0d22009-11-11 00:52:11 +0000103 virtual bool ReadTargetTriple(llvm::StringRef Triple) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000104 TargetTriple = Triple;
105 return false;
106 }
Mike Stump1eb44332009-09-09 15:08:12 +0000107
Sebastian Redlcb481aa2010-07-14 23:29:55 +0000108 virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
Daniel Dunbar7b5a1212009-11-11 05:29:04 +0000109 llvm::StringRef OriginalFileName,
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000110 std::string &SuggestedPredefines) {
Sebastian Redlcb481aa2010-07-14 23:29:55 +0000111 Predefines = Buffers[0].Data;
112 for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
113 Predefines += Buffers[I].Data;
114 }
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000115 return false;
116 }
Mike Stump1eb44332009-09-09 15:08:12 +0000117
Douglas Gregorec1afbf2010-03-16 19:09:18 +0000118 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000119 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
120 }
Mike Stump1eb44332009-09-09 15:08:12 +0000121
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000122 virtual void ReadCounter(unsigned Value) {
123 Counter = Value;
124 }
125};
126
Douglas Gregora88084b2010-02-18 18:08:43 +0000127class StoredDiagnosticClient : public DiagnosticClient {
128 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
129
130public:
131 explicit StoredDiagnosticClient(
132 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
133 : StoredDiags(StoredDiags) { }
134
135 virtual void HandleDiagnostic(Diagnostic::Level Level,
136 const DiagnosticInfo &Info);
137};
138
139/// \brief RAII object that optionally captures diagnostics, if
140/// there is no diagnostic client to capture them already.
141class CaptureDroppedDiagnostics {
142 Diagnostic &Diags;
143 StoredDiagnosticClient Client;
144 DiagnosticClient *PreviousClient;
145
146public:
147 CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
148 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
149 : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
150 {
151 if (RequestCapture || Diags.getClient() == 0)
152 Diags.setClient(&Client);
153 }
154
155 ~CaptureDroppedDiagnostics() {
156 Diags.setClient(PreviousClient);
157 }
158};
159
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000160} // anonymous namespace
161
Douglas Gregora88084b2010-02-18 18:08:43 +0000162void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
163 const DiagnosticInfo &Info) {
164 StoredDiags.push_back(StoredDiagnostic(Level, Info));
165}
166
Steve Naroff77accc12009-09-03 18:19:54 +0000167const std::string &ASTUnit::getOriginalSourceFileName() {
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000168 return OriginalSourceFile;
Steve Naroff77accc12009-09-03 18:19:54 +0000169}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000170
Steve Naroffe19944c2009-10-15 22:23:48 +0000171const std::string &ASTUnit::getPCHFileName() {
Daniel Dunbarc7822db2009-12-02 21:47:43 +0000172 assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
Benjamin Kramer7297c182010-01-30 16:23:25 +0000173 return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
Steve Naroffe19944c2009-10-15 22:23:48 +0000174}
175
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000176ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Douglas Gregor28019772010-04-05 23:52:57 +0000177 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Ted Kremenek5cf48762009-10-17 00:34:24 +0000178 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000179 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000180 unsigned NumRemappedFiles,
181 bool CaptureDiagnostics) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000182 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
183
Douglas Gregor28019772010-04-05 23:52:57 +0000184 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000185 // No diagnostics engine was provided, so create our own diagnostics object
186 // with the default options.
187 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000188 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000189 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000190
191 AST->CaptureDiagnostics = CaptureDiagnostics;
Douglas Gregor7d1d49d2009-10-16 20:01:17 +0000192 AST->OnlyLocalDecls = OnlyLocalDecls;
Douglas Gregor28019772010-04-05 23:52:57 +0000193 AST->Diagnostics = Diags;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000194 AST->FileMgr.reset(new FileManager);
195 AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
Steve Naroff36c44642009-10-19 14:34:22 +0000196 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000197
Douglas Gregora88084b2010-02-18 18:08:43 +0000198 // If requested, capture diagnostics in the ASTUnit.
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000199 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
Douglas Gregor405634b2010-04-05 18:10:21 +0000200 AST->StoredDiagnostics);
Douglas Gregora88084b2010-02-18 18:08:43 +0000201
Douglas Gregor4db64a42010-01-23 00:14:00 +0000202 for (unsigned I = 0; I != NumRemappedFiles; ++I) {
203 // Create the file entry for the file that we're mapping from.
204 const FileEntry *FromFile
205 = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
206 RemappedFiles[I].second->getBufferSize(),
207 0);
208 if (!FromFile) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000209 AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
Douglas Gregor4db64a42010-01-23 00:14:00 +0000210 << RemappedFiles[I].first;
Douglas Gregorc8dfe5e2010-02-27 01:32:48 +0000211 delete RemappedFiles[I].second;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000212 continue;
213 }
214
215 // Override the contents of the "from" file with the contents of
216 // the "to" file.
217 AST->getSourceManager().overrideFileContents(FromFile,
218 RemappedFiles[I].second);
219 }
220
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000221 // Gather Info for preprocessor construction later on.
Mike Stump1eb44332009-09-09 15:08:12 +0000222
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000223 LangOptions LangInfo;
224 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
225 std::string TargetTriple;
226 std::string Predefines;
227 unsigned Counter;
228
Daniel Dunbarbce6f622009-09-03 05:59:50 +0000229 llvm::OwningPtr<PCHReader> Reader;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000230 llvm::OwningPtr<ExternalASTSource> Source;
231
Ted Kremenekfc062212009-10-19 21:44:57 +0000232 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000233 AST->getDiagnostics()));
Daniel Dunbarcc318932009-09-03 05:59:35 +0000234 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
235 Predefines, Counter));
236
237 switch (Reader->ReadPCH(Filename)) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000238 case PCHReader::Success:
239 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000240
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000241 case PCHReader::Failure:
Argyrios Kyrtzidis106c9982009-06-25 18:22:30 +0000242 case PCHReader::IgnorePCH:
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000243 AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000244 return NULL;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000245 }
Mike Stump1eb44332009-09-09 15:08:12 +0000246
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000247 AST->OriginalSourceFile = Reader->getOriginalSourceFile();
248
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000249 // PCH loaded successfully. Now create the preprocessor.
Mike Stump1eb44332009-09-09 15:08:12 +0000250
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000251 // Get information about the target being compiled for.
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000252 //
253 // FIXME: This is broken, we should store the TargetOptions in the PCH.
254 TargetOptions TargetOpts;
255 TargetOpts.ABI = "";
Charles Davis98b7c5c2010-06-11 01:06:47 +0000256 TargetOpts.CXXABI = "itanium";
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000257 TargetOpts.CPU = "";
258 TargetOpts.Features.clear();
259 TargetOpts.Triple = TargetTriple;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000260 AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
261 TargetOpts));
262 AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
263 *AST->Target.get(),
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000264 AST->getSourceManager(), HeaderInfo));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000265 Preprocessor &PP = *AST->PP.get();
266
Daniel Dunbard5b61262009-09-21 03:03:47 +0000267 PP.setPredefines(Reader->getSuggestedPredefines());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000268 PP.setCounterValue(Counter);
Daniel Dunbarcc318932009-09-03 05:59:35 +0000269 Reader->setPreprocessor(PP);
Mike Stump1eb44332009-09-09 15:08:12 +0000270
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000271 // Create and initialize the ASTContext.
272
273 AST->Ctx.reset(new ASTContext(LangInfo,
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000274 AST->getSourceManager(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000275 *AST->Target.get(),
276 PP.getIdentifierTable(),
277 PP.getSelectorTable(),
278 PP.getBuiltinInfo(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000279 /* size_reserve = */0));
280 ASTContext &Context = *AST->Ctx.get();
Mike Stump1eb44332009-09-09 15:08:12 +0000281
Daniel Dunbarcc318932009-09-03 05:59:35 +0000282 Reader->InitializeContext(Context);
Mike Stump1eb44332009-09-09 15:08:12 +0000283
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000284 // Attach the PCH reader to the AST context as an external AST
285 // source, so that declarations will be deserialized from the
286 // PCH file as needed.
Daniel Dunbarcc318932009-09-03 05:59:35 +0000287 Source.reset(Reader.take());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000288 Context.setExternalSource(Source);
289
Mike Stump1eb44332009-09-09 15:08:12 +0000290 return AST.take();
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000291}
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000292
293namespace {
294
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000295class TopLevelDeclTrackerConsumer : public ASTConsumer {
296 ASTUnit &Unit;
297
298public:
299 TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
300
301 void HandleTopLevelDecl(DeclGroupRef D) {
Ted Kremenekda5a4282010-05-03 20:16:35 +0000302 for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
303 Decl *D = *it;
304 // FIXME: Currently ObjC method declarations are incorrectly being
305 // reported as top-level declarations, even though their DeclContext
306 // is the containing ObjC @interface/@implementation. This is a
307 // fundamental problem in the parser right now.
308 if (isa<ObjCMethodDecl>(D))
309 continue;
310 Unit.getTopLevelDecls().push_back(D);
311 }
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000312 }
313};
314
315class TopLevelDeclTrackerAction : public ASTFrontendAction {
316public:
317 ASTUnit &Unit;
318
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000319 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
320 llvm::StringRef InFile) {
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000321 return new TopLevelDeclTrackerConsumer(Unit);
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000322 }
323
324public:
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000325 TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
326
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000327 virtual bool hasCodeCompletionSupport() const { return false; }
328};
329
330}
331
Douglas Gregorabc563f2010-07-19 21:46:24 +0000332/// Parse the source file into a translation unit using the given compiler
333/// invocation, replacing the current translation unit.
334///
335/// \returns True if a failure occurred that causes the ASTUnit not to
336/// contain any translation-unit information, false otherwise.
Douglas Gregor754f3492010-07-24 00:38:13 +0000337bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Douglas Gregor28233422010-07-27 14:52:07 +0000338 delete SavedMainFileBuffer;
339 SavedMainFileBuffer = 0;
340
Douglas Gregorabc563f2010-07-19 21:46:24 +0000341 if (!Invocation.get())
342 return true;
343
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000344 // Create the compiler instance to use for building the AST.
Daniel Dunbarcb6dda12009-12-02 08:43:56 +0000345 CompilerInstance Clang;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000346 Clang.setInvocation(Invocation.take());
347 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
348
349 // Set up diagnostics.
350 Clang.setDiagnostics(&getDiagnostics());
351 Clang.setDiagnosticClient(getDiagnostics().getClient());
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000352
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000353 // Create the target instance.
354 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
355 Clang.getTargetOpts()));
Douglas Gregora88084b2010-02-18 18:08:43 +0000356 if (!Clang.hasTarget()) {
Douglas Gregora88084b2010-02-18 18:08:43 +0000357 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000358 return true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000359 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000360
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000361 // Inform the target of the language options.
362 //
363 // FIXME: We shouldn't need to do this, the target should be immutable once
364 // created. This complexity should be lifted elsewhere.
365 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
Douglas Gregorabc563f2010-07-19 21:46:24 +0000366
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000367 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
368 "Invocation must have exactly one source file!");
Daniel Dunbarc34ce3f2010-06-07 23:22:09 +0000369 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000370 "FIXME: AST inputs not yet supported here!");
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000371 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
372 "IR inputs not support here!");
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000373
Douglas Gregorabc563f2010-07-19 21:46:24 +0000374 // Configure the various subsystems.
375 // FIXME: Should we retain the previous file manager?
376 FileMgr.reset(new FileManager);
377 SourceMgr.reset(new SourceManager(getDiagnostics()));
378 Ctx.reset();
379 PP.reset();
380
381 // Clear out old caches and data.
382 TopLevelDecls.clear();
383 StoredDiagnostics.clear();
384 CleanTemporaryFiles();
385 PreprocessedEntitiesByFile.clear();
386
Douglas Gregora88084b2010-02-18 18:08:43 +0000387 // Capture any diagnostics that would otherwise be dropped.
388 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
389 Clang.getDiagnostics(),
Douglas Gregorabc563f2010-07-19 21:46:24 +0000390 StoredDiagnostics);
391
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000392 // Create a file manager object to provide access to and cache the filesystem.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000393 Clang.setFileManager(&getFileManager());
394
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000395 // Create the source manager.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000396 Clang.setSourceManager(&getSourceManager());
397
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000398 // If the main file has been overridden due to the use of a preamble,
399 // make that override happen and introduce the preamble.
400 PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts();
401 if (OverrideMainBuffer) {
402 PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
403 PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
404 PreprocessorOpts.PrecompiledPreambleBytes.second
405 = PreambleEndsAtStartOfLine;
Douglas Gregor385103b2010-07-30 20:58:08 +0000406 PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000407 PreprocessorOpts.DisablePCHValidation = true;
Douglas Gregor28233422010-07-27 14:52:07 +0000408
409 // Keep track of the override buffer;
410 SavedMainFileBuffer = OverrideMainBuffer;
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000411 }
412
Douglas Gregorabc563f2010-07-19 21:46:24 +0000413 llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
414 Act.reset(new TopLevelDeclTrackerAction(*this));
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000415 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
Daniel Dunbard3598a62010-06-07 23:23:06 +0000416 Clang.getFrontendOpts().Inputs[0].first))
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000417 goto error;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000418
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000419 Act->Execute();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000420
Daniel Dunbar64a32ba2009-12-01 21:57:33 +0000421 // Steal the created target, context, and preprocessor, and take back the
422 // source and file managers.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000423 Ctx.reset(Clang.takeASTContext());
424 PP.reset(Clang.takePreprocessor());
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000425 Clang.takeSourceManager();
426 Clang.takeFileManager();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000427 Target.reset(Clang.takeTarget());
428
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000429 Act->EndSourceFile();
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000430
431 // Remove the overridden buffer we used for the preamble.
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000432 if (OverrideMainBuffer) {
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000433 PreprocessorOpts.eraseRemappedFile(
434 PreprocessorOpts.remapped_file_buffer_end() - 1);
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000435 PreprocessorOpts.DisablePCHValidation = true;
436 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000437
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000438 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000439
440 Invocation.reset(Clang.takeInvocation());
441 return false;
442
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000443error:
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000444 // Remove the overridden buffer we used for the preamble.
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000445 if (OverrideMainBuffer) {
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000446 PreprocessorOpts.eraseRemappedFile(
447 PreprocessorOpts.remapped_file_buffer_end() - 1);
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000448 PreprocessorOpts.DisablePCHValidation = true;
449 }
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000450
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000451 Clang.takeSourceManager();
452 Clang.takeFileManager();
453 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000454 Invocation.reset(Clang.takeInvocation());
455 return true;
456}
457
Douglas Gregor44c181a2010-07-23 00:33:23 +0000458/// \brief Simple function to retrieve a path for a preamble precompiled header.
459static std::string GetPreamblePCHPath() {
460 // FIXME: This is lame; sys::Path should provide this function (in particular,
461 // it should know how to find the temporary files dir).
462 // FIXME: This is really lame. I copied this code from the Driver!
463 std::string Error;
464 const char *TmpDir = ::getenv("TMPDIR");
465 if (!TmpDir)
466 TmpDir = ::getenv("TEMP");
467 if (!TmpDir)
468 TmpDir = ::getenv("TMP");
469 if (!TmpDir)
470 TmpDir = "/tmp";
471 llvm::sys::Path P(TmpDir);
472 P.appendComponent("preamble");
473 if (P.createTemporaryFileOnDisk())
474 return std::string();
475
476 P.appendSuffix("pch");
477 return P.str();
478}
479
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000480/// \brief Compute the preamble for the main file, providing the source buffer
481/// that corresponds to the main file along with a pair (bytes, start-of-line)
482/// that describes the preamble.
483std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
Douglas Gregor175c4a92010-07-23 23:58:40 +0000484ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
485 FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000486 PreprocessorOptions &PreprocessorOpts
Douglas Gregor175c4a92010-07-23 23:58:40 +0000487 = Invocation.getPreprocessorOpts();
488 CreatedBuffer = false;
489
Douglas Gregor44c181a2010-07-23 00:33:23 +0000490 // Try to determine if the main file has been remapped, either from the
491 // command line (to another file) or directly through the compiler invocation
492 // (to a memory buffer).
Douglas Gregor175c4a92010-07-23 23:58:40 +0000493 llvm::MemoryBuffer *Buffer = 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000494 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
495 if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
496 // Check whether there is a file-file remapping of the main file
497 for (PreprocessorOptions::remapped_file_iterator
Douglas Gregor175c4a92010-07-23 23:58:40 +0000498 M = PreprocessorOpts.remapped_file_begin(),
499 E = PreprocessorOpts.remapped_file_end();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000500 M != E;
501 ++M) {
502 llvm::sys::PathWithStatus MPath(M->first);
503 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
504 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
505 // We found a remapping. Try to load the resulting, remapped source.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000506 if (CreatedBuffer) {
Douglas Gregor44c181a2010-07-23 00:33:23 +0000507 delete Buffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000508 CreatedBuffer = false;
509 }
510
Douglas Gregor44c181a2010-07-23 00:33:23 +0000511 Buffer = llvm::MemoryBuffer::getFile(M->second);
512 if (!Buffer)
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000513 return std::make_pair((llvm::MemoryBuffer*)0,
514 std::make_pair(0, true));
Douglas Gregor175c4a92010-07-23 23:58:40 +0000515 CreatedBuffer = true;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000516
Douglas Gregor175c4a92010-07-23 23:58:40 +0000517 // Remove this remapping. We've captured the buffer already.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000518 M = PreprocessorOpts.eraseRemappedFile(M);
519 E = PreprocessorOpts.remapped_file_end();
520 }
521 }
522 }
523
524 // Check whether there is a file-buffer remapping. It supercedes the
525 // file-file remapping.
526 for (PreprocessorOptions::remapped_file_buffer_iterator
527 M = PreprocessorOpts.remapped_file_buffer_begin(),
528 E = PreprocessorOpts.remapped_file_buffer_end();
529 M != E;
530 ++M) {
531 llvm::sys::PathWithStatus MPath(M->first);
532 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
533 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
534 // We found a remapping.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000535 if (CreatedBuffer) {
Douglas Gregor44c181a2010-07-23 00:33:23 +0000536 delete Buffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000537 CreatedBuffer = false;
538 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000539
Douglas Gregor175c4a92010-07-23 23:58:40 +0000540 Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
541
542 // Remove this remapping. We've captured the buffer already.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000543 M = PreprocessorOpts.eraseRemappedFile(M);
544 E = PreprocessorOpts.remapped_file_buffer_end();
545 }
546 }
Douglas Gregor175c4a92010-07-23 23:58:40 +0000547 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000548 }
549
550 // If the main source file was not remapped, load it now.
551 if (!Buffer) {
552 Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
553 if (!Buffer)
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000554 return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
Douglas Gregor175c4a92010-07-23 23:58:40 +0000555
556 CreatedBuffer = true;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000557 }
558
Douglas Gregor175c4a92010-07-23 23:58:40 +0000559 return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer));
560}
561
Douglas Gregor754f3492010-07-24 00:38:13 +0000562static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
563 bool DeleteOld,
564 unsigned NewSize,
565 llvm::StringRef NewName) {
566 llvm::MemoryBuffer *Result
567 = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
568 memcpy(const_cast<char*>(Result->getBufferStart()),
569 Old->getBufferStart(), Old->getBufferSize());
570 memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000571 ' ', NewSize - Old->getBufferSize() - 1);
572 const_cast<char*>(Result->getBufferEnd())[-1] = '\n';
Douglas Gregor754f3492010-07-24 00:38:13 +0000573
574 if (DeleteOld)
575 delete Old;
576
577 return Result;
578}
579
Douglas Gregor175c4a92010-07-23 23:58:40 +0000580/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
581/// the source file.
582///
583/// This routine will compute the preamble of the main source file. If a
584/// non-trivial preamble is found, it will precompile that preamble into a
585/// precompiled header so that the precompiled preamble can be used to reduce
586/// reparsing time. If a precompiled preamble has already been constructed,
587/// this routine will determine if it is still valid and, if so, avoid
588/// rebuilding the precompiled preamble.
589///
Douglas Gregor754f3492010-07-24 00:38:13 +0000590/// \returns If the precompiled preamble can be used, returns a newly-allocated
591/// buffer that should be used in place of the main file when doing so.
592/// Otherwise, returns a NULL pointer.
593llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000594 CompilerInvocation PreambleInvocation(*Invocation);
595 FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
596 PreprocessorOptions &PreprocessorOpts
597 = PreambleInvocation.getPreprocessorOpts();
598
599 bool CreatedPreambleBuffer = false;
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000600 std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
Douglas Gregor175c4a92010-07-23 23:58:40 +0000601 = ComputePreamble(PreambleInvocation, CreatedPreambleBuffer);
602
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000603 if (!NewPreamble.second.first) {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000604 // We couldn't find a preamble in the main source. Clear out the current
605 // preamble, if we have one. It's obviously no good any more.
606 Preamble.clear();
607 if (!PreambleFile.empty()) {
Douglas Gregor385103b2010-07-30 20:58:08 +0000608 llvm::sys::Path(PreambleFile).eraseFromDisk();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000609 PreambleFile.clear();
610 }
611 if (CreatedPreambleBuffer)
612 delete NewPreamble.first;
613
Douglas Gregor754f3492010-07-24 00:38:13 +0000614 return 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000615 }
616
617 if (!Preamble.empty()) {
618 // We've previously computed a preamble. Check whether we have the same
619 // preamble now that we did before, and that there's enough space in
620 // the main-file buffer within the precompiled preamble to fit the
621 // new main file.
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000622 if (Preamble.size() == NewPreamble.second.first &&
623 PreambleEndsAtStartOfLine == NewPreamble.second.second &&
Douglas Gregor592508e2010-07-24 00:42:07 +0000624 NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
Douglas Gregor175c4a92010-07-23 23:58:40 +0000625 memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000626 NewPreamble.second.first) == 0) {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000627 // The preamble has not changed. We may be able to re-use the precompiled
628 // preamble.
629 // FIXME: Check that none of the files used by the preamble have changed.
630
Douglas Gregor754f3492010-07-24 00:38:13 +0000631
Douglas Gregor175c4a92010-07-23 23:58:40 +0000632 // Okay! Re-use the precompiled preamble.
Douglas Gregor754f3492010-07-24 00:38:13 +0000633 return CreatePaddedMainFileBuffer(NewPreamble.first,
634 CreatedPreambleBuffer,
635 PreambleReservedSize,
636 FrontendOpts.Inputs[0].second);
Douglas Gregor175c4a92010-07-23 23:58:40 +0000637 }
638
639 // We can't reuse the previously-computed preamble. Build a new one.
640 Preamble.clear();
Douglas Gregor385103b2010-07-30 20:58:08 +0000641 llvm::sys::Path(PreambleFile).eraseFromDisk();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000642 }
643
644 // We did not previously compute a preamble, or it can't be reused anyway.
Douglas Gregor385103b2010-07-30 20:58:08 +0000645 llvm::Timer *PreambleTimer = 0;
646 if (TimerGroup.get()) {
647 PreambleTimer = new llvm::Timer("Precompiling preamble", *TimerGroup);
648 PreambleTimer->startTimer();
649 Timers.push_back(PreambleTimer);
650 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000651
652 // Create a new buffer that stores the preamble. The buffer also contains
653 // extra space for the original contents of the file (which will be present
654 // when we actually parse the file) along with more room in case the file
Douglas Gregor175c4a92010-07-23 23:58:40 +0000655 // grows.
656 PreambleReservedSize = NewPreamble.first->getBufferSize();
657 if (PreambleReservedSize < 4096)
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000658 PreambleReservedSize = 8191;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000659 else
Douglas Gregor175c4a92010-07-23 23:58:40 +0000660 PreambleReservedSize *= 2;
661
Douglas Gregor44c181a2010-07-23 00:33:23 +0000662 llvm::MemoryBuffer *PreambleBuffer
Douglas Gregor175c4a92010-07-23 23:58:40 +0000663 = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000664 FrontendOpts.Inputs[0].second);
665 memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
Douglas Gregor175c4a92010-07-23 23:58:40 +0000666 NewPreamble.first->getBufferStart(), Preamble.size());
667 memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000668 ' ', PreambleReservedSize - Preamble.size() - 1);
669 const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
Douglas Gregor592508e2010-07-24 00:42:07 +0000670
Douglas Gregor175c4a92010-07-23 23:58:40 +0000671 // Save the preamble text for later; we'll need to compare against it for
672 // subsequent reparses.
673 Preamble.assign(NewPreamble.first->getBufferStart(),
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000674 NewPreamble.first->getBufferStart()
675 + NewPreamble.second.first);
676 PreambleEndsAtStartOfLine = NewPreamble.second.second;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000677
678 // Remap the main source file to the preamble buffer.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000679 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000680 PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
681
682 // Tell the compiler invocation to generate a temporary precompiled header.
683 FrontendOpts.ProgramAction = frontend::GeneratePCH;
684 // FIXME: Set ChainedPCH, once it is ready.
685 // FIXME: Generate the precompiled header into memory?
Douglas Gregor385103b2010-07-30 20:58:08 +0000686 FrontendOpts.OutputFile = GetPreamblePCHPath();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000687
688 // Create the compiler instance to use for building the precompiled preamble.
689 CompilerInstance Clang;
690 Clang.setInvocation(&PreambleInvocation);
691 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
692
693 // Set up diagnostics.
694 Clang.setDiagnostics(&getDiagnostics());
695 Clang.setDiagnosticClient(getDiagnostics().getClient());
696
697 // Create the target instance.
698 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
699 Clang.getTargetOpts()));
700 if (!Clang.hasTarget()) {
701 Clang.takeDiagnosticClient();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000702 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
703 Preamble.clear();
704 if (CreatedPreambleBuffer)
705 delete NewPreamble.first;
Douglas Gregor385103b2010-07-30 20:58:08 +0000706 if (PreambleTimer)
707 PreambleTimer->stopTimer();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000708
Douglas Gregor754f3492010-07-24 00:38:13 +0000709 return 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000710 }
711
712 // Inform the target of the language options.
713 //
714 // FIXME: We shouldn't need to do this, the target should be immutable once
715 // created. This complexity should be lifted elsewhere.
716 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
717
718 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
719 "Invocation must have exactly one source file!");
720 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
721 "FIXME: AST inputs not yet supported here!");
722 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
723 "IR inputs not support here!");
724
725 // Clear out old caches and data.
726 StoredDiagnostics.clear();
727
728 // Capture any diagnostics that would otherwise be dropped.
729 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
730 Clang.getDiagnostics(),
731 StoredDiagnostics);
732
733 // Create a file manager object to provide access to and cache the filesystem.
734 Clang.setFileManager(new FileManager);
735
736 // Create the source manager.
737 Clang.setSourceManager(new SourceManager(getDiagnostics()));
738
739 // FIXME: Eventually, we'll have to track top-level declarations here, too.
740 llvm::OwningPtr<GeneratePCHAction> Act;
741 Act.reset(new GeneratePCHAction);
742 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
743 Clang.getFrontendOpts().Inputs[0].first)) {
744 Clang.takeDiagnosticClient();
745 Clang.takeInvocation();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000746 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
747 Preamble.clear();
748 if (CreatedPreambleBuffer)
749 delete NewPreamble.first;
Douglas Gregor385103b2010-07-30 20:58:08 +0000750 if (PreambleTimer)
751 PreambleTimer->stopTimer();
752
Douglas Gregor754f3492010-07-24 00:38:13 +0000753 return 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000754 }
755
756 Act->Execute();
757 Act->EndSourceFile();
758 Clang.takeDiagnosticClient();
759 Clang.takeInvocation();
760
Douglas Gregor175c4a92010-07-23 23:58:40 +0000761 if (Diagnostics->getNumErrors() > 0) {
762 // There were errors parsing the preamble, so no precompiled header was
763 // generated. Forget that we even tried.
764 // FIXME: Should we leave a note for ourselves to try again?
765 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
766 Preamble.clear();
767 if (CreatedPreambleBuffer)
768 delete NewPreamble.first;
Douglas Gregor385103b2010-07-30 20:58:08 +0000769 if (PreambleTimer)
770 PreambleTimer->stopTimer();
771 if (PreambleTimer)
772 PreambleTimer->stopTimer();
773
Douglas Gregor754f3492010-07-24 00:38:13 +0000774 return 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000775 }
776
777 // Keep track of the preamble we precompiled.
778 PreambleFile = FrontendOpts.OutputFile;
Douglas Gregor385103b2010-07-30 20:58:08 +0000779 if (PreambleTimer)
780 PreambleTimer->stopTimer();
781
Douglas Gregor754f3492010-07-24 00:38:13 +0000782 return CreatePaddedMainFileBuffer(NewPreamble.first,
783 CreatedPreambleBuffer,
784 PreambleReservedSize,
785 FrontendOpts.Inputs[0].second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000786}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000787
788ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
789 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
790 bool OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000791 bool CaptureDiagnostics,
792 bool PrecompilePreamble) {
Douglas Gregorabc563f2010-07-19 21:46:24 +0000793 if (!Diags.getPtr()) {
794 // No diagnostics engine was provided, so create our own diagnostics object
795 // with the default options.
796 DiagnosticOptions DiagOpts;
797 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
798 }
799
800 // Create the AST unit.
801 llvm::OwningPtr<ASTUnit> AST;
802 AST.reset(new ASTUnit(false));
803 AST->Diagnostics = Diags;
804 AST->CaptureDiagnostics = CaptureDiagnostics;
805 AST->OnlyLocalDecls = OnlyLocalDecls;
806 AST->Invocation.reset(CI);
Douglas Gregorf4f6c9d2010-07-26 21:36:20 +0000807 CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000808
Douglas Gregor385103b2010-07-30 20:58:08 +0000809 if (getenv("LIBCLANG_TIMING"))
810 AST->TimerGroup.reset(
811 new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second));
812
813
Douglas Gregor754f3492010-07-24 00:38:13 +0000814 llvm::MemoryBuffer *OverrideMainBuffer = 0;
Douglas Gregorfd0b8702010-07-28 22:12:37 +0000815 // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
816 if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus)
Douglas Gregor754f3492010-07-24 00:38:13 +0000817 OverrideMainBuffer = AST->BuildPrecompiledPreamble();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000818
Douglas Gregor385103b2010-07-30 20:58:08 +0000819 llvm::Timer *ParsingTimer = 0;
820 if (AST->TimerGroup.get()) {
821 ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup);
822 ParsingTimer->startTimer();
823 AST->Timers.push_back(ParsingTimer);
824 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000825
Douglas Gregor385103b2010-07-30 20:58:08 +0000826 bool Failed = AST->Parse(OverrideMainBuffer);
827 if (ParsingTimer)
828 ParsingTimer->stopTimer();
829
830 return Failed? 0 : AST.take();
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000831}
Daniel Dunbar7b556682009-12-02 03:23:45 +0000832
833ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
834 const char **ArgEnd,
Douglas Gregor28019772010-04-05 23:52:57 +0000835 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Daniel Dunbar869824e2009-12-13 03:46:13 +0000836 llvm::StringRef ResourceFilesPath,
Daniel Dunbar7b556682009-12-02 03:23:45 +0000837 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000838 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000839 unsigned NumRemappedFiles,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000840 bool CaptureDiagnostics,
841 bool PrecompilePreamble) {
Douglas Gregor28019772010-04-05 23:52:57 +0000842 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000843 // No diagnostics engine was provided, so create our own diagnostics object
844 // with the default options.
845 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000846 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000847 }
848
Daniel Dunbar7b556682009-12-02 03:23:45 +0000849 llvm::SmallVector<const char *, 16> Args;
850 Args.push_back("<clang>"); // FIXME: Remove dummy argument.
851 Args.insert(Args.end(), ArgBegin, ArgEnd);
852
853 // FIXME: Find a cleaner way to force the driver into restricted modes. We
854 // also want to force it to use clang.
855 Args.push_back("-fsyntax-only");
856
Daniel Dunbar869824e2009-12-13 03:46:13 +0000857 // FIXME: We shouldn't have to pass in the path info.
Daniel Dunbar0bbad512010-07-19 00:44:04 +0000858 driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000859 "a.out", false, false, *Diags);
Daniel Dunbar3bd54cc2010-01-25 00:44:02 +0000860
861 // Don't check that inputs exist, they have been remapped.
862 TheDriver.setCheckInputsExist(false);
863
Daniel Dunbar7b556682009-12-02 03:23:45 +0000864 llvm::OwningPtr<driver::Compilation> C(
865 TheDriver.BuildCompilation(Args.size(), Args.data()));
866
867 // We expect to get back exactly one command job, if we didn't something
868 // failed.
869 const driver::JobList &Jobs = C->getJobs();
870 if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
871 llvm::SmallString<256> Msg;
872 llvm::raw_svector_ostream OS(Msg);
873 C->PrintJob(OS, C->getJobs(), "; ", true);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000874 Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
Daniel Dunbar7b556682009-12-02 03:23:45 +0000875 return 0;
876 }
877
878 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
879 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000880 Diags->Report(diag::err_fe_expected_clang_command);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000881 return 0;
882 }
883
884 const driver::ArgStringList &CCArgs = Cmd->getArguments();
Daniel Dunbar807b0612010-01-30 21:47:16 +0000885 llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
Dan Gohmancb421fa2010-04-19 16:39:44 +0000886 CompilerInvocation::CreateFromArgs(*CI,
887 const_cast<const char **>(CCArgs.data()),
888 const_cast<const char **>(CCArgs.data()) +
Douglas Gregor44c181a2010-07-23 00:33:23 +0000889 CCArgs.size(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000890 *Diags);
Daniel Dunbar1e69fe32009-12-13 03:45:58 +0000891
Douglas Gregor4db64a42010-01-23 00:14:00 +0000892 // Override any files that need remapping
893 for (unsigned I = 0; I != NumRemappedFiles; ++I)
Daniel Dunbar807b0612010-01-30 21:47:16 +0000894 CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000895 RemappedFiles[I].second);
Douglas Gregor4db64a42010-01-23 00:14:00 +0000896
Daniel Dunbar8b9adfe2009-12-15 00:06:45 +0000897 // Override the resources path.
Daniel Dunbar807b0612010-01-30 21:47:16 +0000898 CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
Daniel Dunbar7b556682009-12-02 03:23:45 +0000899
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000900 CI->getFrontendOpts().DisableFree = true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000901 return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000902 CaptureDiagnostics, PrecompilePreamble);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000903}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000904
905bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
906 if (!Invocation.get())
907 return true;
908
Douglas Gregor385103b2010-07-30 20:58:08 +0000909 llvm::Timer *ReparsingTimer = 0;
910 if (TimerGroup.get()) {
911 ReparsingTimer = new llvm::Timer("Reparse", *TimerGroup);
912 ReparsingTimer->startTimer();
913 Timers.push_back(ReparsingTimer);
914 }
915
Douglas Gregor175c4a92010-07-23 23:58:40 +0000916 // If we have a preamble file lying around, build or reuse the precompiled
917 // preamble.
Douglas Gregor754f3492010-07-24 00:38:13 +0000918 llvm::MemoryBuffer *OverrideMainBuffer = 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000919 if (!PreambleFile.empty())
Douglas Gregor754f3492010-07-24 00:38:13 +0000920 OverrideMainBuffer = BuildPrecompiledPreamble();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000921
Douglas Gregorabc563f2010-07-19 21:46:24 +0000922 // Clear out the diagnostics state.
923 getDiagnostics().Reset();
924
925 // Remap files.
926 Invocation->getPreprocessorOpts().clearRemappedFiles();
927 for (unsigned I = 0; I != NumRemappedFiles; ++I)
928 Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Douglas Gregor175c4a92010-07-23 23:58:40 +0000929 RemappedFiles[I].second);
930
931 // Parse the sources
Douglas Gregor754f3492010-07-24 00:38:13 +0000932 bool Result = Parse(OverrideMainBuffer);
Douglas Gregor385103b2010-07-30 20:58:08 +0000933 if (ReparsingTimer)
934 ReparsingTimer->stopTimer();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000935 return Result;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000936}