blob: 77a414772af0b8103b3a527a4c2f9676e70767ed [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),
42 ConcurrencyCheckValue(CheckUnlocked) { }
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 Gregorabc563f2010-07-19 21:46:24 +000049}
50
51void ASTUnit::CleanTemporaryFiles() {
Douglas Gregor313e26c2010-02-18 23:35:40 +000052 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
53 TemporaryFiles[I].eraseFromDisk();
Douglas Gregorabc563f2010-07-19 21:46:24 +000054 TemporaryFiles.clear();
Steve Naroffe19944c2009-10-15 22:23:48 +000055}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000056
57namespace {
58
59/// \brief Gathers information from PCHReader that will be used to initialize
60/// a Preprocessor.
Benjamin Kramerbd218282009-11-28 10:07:24 +000061class PCHInfoCollector : public PCHReaderListener {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000062 LangOptions &LangOpt;
63 HeaderSearch &HSI;
64 std::string &TargetTriple;
65 std::string &Predefines;
66 unsigned &Counter;
Mike Stump1eb44332009-09-09 15:08:12 +000067
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000068 unsigned NumHeaderInfos;
Mike Stump1eb44332009-09-09 15:08:12 +000069
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000070public:
71 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
72 std::string &TargetTriple, std::string &Predefines,
73 unsigned &Counter)
74 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
75 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000076
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000077 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
78 LangOpt = LangOpts;
79 return false;
80 }
Mike Stump1eb44332009-09-09 15:08:12 +000081
Daniel Dunbardc3c0d22009-11-11 00:52:11 +000082 virtual bool ReadTargetTriple(llvm::StringRef Triple) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000083 TargetTriple = Triple;
84 return false;
85 }
Mike Stump1eb44332009-09-09 15:08:12 +000086
Sebastian Redlcb481aa2010-07-14 23:29:55 +000087 virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
Daniel Dunbar7b5a1212009-11-11 05:29:04 +000088 llvm::StringRef OriginalFileName,
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000089 std::string &SuggestedPredefines) {
Sebastian Redlcb481aa2010-07-14 23:29:55 +000090 Predefines = Buffers[0].Data;
91 for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
92 Predefines += Buffers[I].Data;
93 }
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000094 return false;
95 }
Mike Stump1eb44332009-09-09 15:08:12 +000096
Douglas Gregorec1afbf2010-03-16 19:09:18 +000097 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000098 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
99 }
Mike Stump1eb44332009-09-09 15:08:12 +0000100
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000101 virtual void ReadCounter(unsigned Value) {
102 Counter = Value;
103 }
104};
105
Douglas Gregora88084b2010-02-18 18:08:43 +0000106class StoredDiagnosticClient : public DiagnosticClient {
107 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
108
109public:
110 explicit StoredDiagnosticClient(
111 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
112 : StoredDiags(StoredDiags) { }
113
114 virtual void HandleDiagnostic(Diagnostic::Level Level,
115 const DiagnosticInfo &Info);
116};
117
118/// \brief RAII object that optionally captures diagnostics, if
119/// there is no diagnostic client to capture them already.
120class CaptureDroppedDiagnostics {
121 Diagnostic &Diags;
122 StoredDiagnosticClient Client;
123 DiagnosticClient *PreviousClient;
124
125public:
126 CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
127 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
128 : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
129 {
130 if (RequestCapture || Diags.getClient() == 0)
131 Diags.setClient(&Client);
132 }
133
134 ~CaptureDroppedDiagnostics() {
135 Diags.setClient(PreviousClient);
136 }
137};
138
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000139} // anonymous namespace
140
Douglas Gregora88084b2010-02-18 18:08:43 +0000141void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
142 const DiagnosticInfo &Info) {
143 StoredDiags.push_back(StoredDiagnostic(Level, Info));
144}
145
Steve Naroff77accc12009-09-03 18:19:54 +0000146const std::string &ASTUnit::getOriginalSourceFileName() {
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000147 return OriginalSourceFile;
Steve Naroff77accc12009-09-03 18:19:54 +0000148}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000149
Steve Naroffe19944c2009-10-15 22:23:48 +0000150const std::string &ASTUnit::getPCHFileName() {
Daniel Dunbarc7822db2009-12-02 21:47:43 +0000151 assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
Benjamin Kramer7297c182010-01-30 16:23:25 +0000152 return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
Steve Naroffe19944c2009-10-15 22:23:48 +0000153}
154
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000155ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Douglas Gregor28019772010-04-05 23:52:57 +0000156 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Ted Kremenek5cf48762009-10-17 00:34:24 +0000157 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000158 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000159 unsigned NumRemappedFiles,
160 bool CaptureDiagnostics) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000161 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
162
Douglas Gregor28019772010-04-05 23:52:57 +0000163 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000164 // No diagnostics engine was provided, so create our own diagnostics object
165 // with the default options.
166 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000167 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000168 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000169
170 AST->CaptureDiagnostics = CaptureDiagnostics;
Douglas Gregor7d1d49d2009-10-16 20:01:17 +0000171 AST->OnlyLocalDecls = OnlyLocalDecls;
Douglas Gregor28019772010-04-05 23:52:57 +0000172 AST->Diagnostics = Diags;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000173 AST->FileMgr.reset(new FileManager);
174 AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
Steve Naroff36c44642009-10-19 14:34:22 +0000175 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000176
Douglas Gregora88084b2010-02-18 18:08:43 +0000177 // If requested, capture diagnostics in the ASTUnit.
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000178 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
Douglas Gregor405634b2010-04-05 18:10:21 +0000179 AST->StoredDiagnostics);
Douglas Gregora88084b2010-02-18 18:08:43 +0000180
Douglas Gregor4db64a42010-01-23 00:14:00 +0000181 for (unsigned I = 0; I != NumRemappedFiles; ++I) {
182 // Create the file entry for the file that we're mapping from.
183 const FileEntry *FromFile
184 = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
185 RemappedFiles[I].second->getBufferSize(),
186 0);
187 if (!FromFile) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000188 AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
Douglas Gregor4db64a42010-01-23 00:14:00 +0000189 << RemappedFiles[I].first;
Douglas Gregorc8dfe5e2010-02-27 01:32:48 +0000190 delete RemappedFiles[I].second;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000191 continue;
192 }
193
194 // Override the contents of the "from" file with the contents of
195 // the "to" file.
196 AST->getSourceManager().overrideFileContents(FromFile,
197 RemappedFiles[I].second);
198 }
199
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000200 // Gather Info for preprocessor construction later on.
Mike Stump1eb44332009-09-09 15:08:12 +0000201
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000202 LangOptions LangInfo;
203 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
204 std::string TargetTriple;
205 std::string Predefines;
206 unsigned Counter;
207
Daniel Dunbarbce6f622009-09-03 05:59:50 +0000208 llvm::OwningPtr<PCHReader> Reader;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000209 llvm::OwningPtr<ExternalASTSource> Source;
210
Ted Kremenekfc062212009-10-19 21:44:57 +0000211 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000212 AST->getDiagnostics()));
Daniel Dunbarcc318932009-09-03 05:59:35 +0000213 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
214 Predefines, Counter));
215
216 switch (Reader->ReadPCH(Filename)) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000217 case PCHReader::Success:
218 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000219
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000220 case PCHReader::Failure:
Argyrios Kyrtzidis106c9982009-06-25 18:22:30 +0000221 case PCHReader::IgnorePCH:
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000222 AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000223 return NULL;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000224 }
Mike Stump1eb44332009-09-09 15:08:12 +0000225
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000226 AST->OriginalSourceFile = Reader->getOriginalSourceFile();
227
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000228 // PCH loaded successfully. Now create the preprocessor.
Mike Stump1eb44332009-09-09 15:08:12 +0000229
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000230 // Get information about the target being compiled for.
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000231 //
232 // FIXME: This is broken, we should store the TargetOptions in the PCH.
233 TargetOptions TargetOpts;
234 TargetOpts.ABI = "";
Charles Davis98b7c5c2010-06-11 01:06:47 +0000235 TargetOpts.CXXABI = "itanium";
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000236 TargetOpts.CPU = "";
237 TargetOpts.Features.clear();
238 TargetOpts.Triple = TargetTriple;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000239 AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
240 TargetOpts));
241 AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
242 *AST->Target.get(),
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000243 AST->getSourceManager(), HeaderInfo));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000244 Preprocessor &PP = *AST->PP.get();
245
Daniel Dunbard5b61262009-09-21 03:03:47 +0000246 PP.setPredefines(Reader->getSuggestedPredefines());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000247 PP.setCounterValue(Counter);
Daniel Dunbarcc318932009-09-03 05:59:35 +0000248 Reader->setPreprocessor(PP);
Mike Stump1eb44332009-09-09 15:08:12 +0000249
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000250 // Create and initialize the ASTContext.
251
252 AST->Ctx.reset(new ASTContext(LangInfo,
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000253 AST->getSourceManager(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000254 *AST->Target.get(),
255 PP.getIdentifierTable(),
256 PP.getSelectorTable(),
257 PP.getBuiltinInfo(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000258 /* size_reserve = */0));
259 ASTContext &Context = *AST->Ctx.get();
Mike Stump1eb44332009-09-09 15:08:12 +0000260
Daniel Dunbarcc318932009-09-03 05:59:35 +0000261 Reader->InitializeContext(Context);
Mike Stump1eb44332009-09-09 15:08:12 +0000262
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000263 // Attach the PCH reader to the AST context as an external AST
264 // source, so that declarations will be deserialized from the
265 // PCH file as needed.
Daniel Dunbarcc318932009-09-03 05:59:35 +0000266 Source.reset(Reader.take());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000267 Context.setExternalSource(Source);
268
Mike Stump1eb44332009-09-09 15:08:12 +0000269 return AST.take();
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000270}
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000271
272namespace {
273
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000274class TopLevelDeclTrackerConsumer : public ASTConsumer {
275 ASTUnit &Unit;
276
277public:
278 TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
279
280 void HandleTopLevelDecl(DeclGroupRef D) {
Ted Kremenekda5a4282010-05-03 20:16:35 +0000281 for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
282 Decl *D = *it;
283 // FIXME: Currently ObjC method declarations are incorrectly being
284 // reported as top-level declarations, even though their DeclContext
285 // is the containing ObjC @interface/@implementation. This is a
286 // fundamental problem in the parser right now.
287 if (isa<ObjCMethodDecl>(D))
288 continue;
289 Unit.getTopLevelDecls().push_back(D);
290 }
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000291 }
292};
293
294class TopLevelDeclTrackerAction : public ASTFrontendAction {
295public:
296 ASTUnit &Unit;
297
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000298 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
299 llvm::StringRef InFile) {
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000300 return new TopLevelDeclTrackerConsumer(Unit);
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000301 }
302
303public:
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000304 TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
305
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000306 virtual bool hasCodeCompletionSupport() const { return false; }
307};
308
309}
310
Douglas Gregorabc563f2010-07-19 21:46:24 +0000311/// Parse the source file into a translation unit using the given compiler
312/// invocation, replacing the current translation unit.
313///
314/// \returns True if a failure occurred that causes the ASTUnit not to
315/// contain any translation-unit information, false otherwise.
Douglas Gregor754f3492010-07-24 00:38:13 +0000316bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Douglas Gregorabc563f2010-07-19 21:46:24 +0000317 if (!Invocation.get())
318 return true;
319
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000320 // Create the compiler instance to use for building the AST.
Daniel Dunbarcb6dda12009-12-02 08:43:56 +0000321 CompilerInstance Clang;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000322 Clang.setInvocation(Invocation.take());
323 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
324
325 // Set up diagnostics.
326 Clang.setDiagnostics(&getDiagnostics());
327 Clang.setDiagnosticClient(getDiagnostics().getClient());
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000328
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000329 // Create the target instance.
330 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
331 Clang.getTargetOpts()));
Douglas Gregora88084b2010-02-18 18:08:43 +0000332 if (!Clang.hasTarget()) {
Douglas Gregora88084b2010-02-18 18:08:43 +0000333 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000334 return true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000335 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000336
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000337 // Inform the target of the language options.
338 //
339 // FIXME: We shouldn't need to do this, the target should be immutable once
340 // created. This complexity should be lifted elsewhere.
341 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
Douglas Gregorabc563f2010-07-19 21:46:24 +0000342
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000343 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
344 "Invocation must have exactly one source file!");
Daniel Dunbarc34ce3f2010-06-07 23:22:09 +0000345 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000346 "FIXME: AST inputs not yet supported here!");
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000347 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
348 "IR inputs not support here!");
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000349
Douglas Gregorabc563f2010-07-19 21:46:24 +0000350 // Configure the various subsystems.
351 // FIXME: Should we retain the previous file manager?
352 FileMgr.reset(new FileManager);
353 SourceMgr.reset(new SourceManager(getDiagnostics()));
354 Ctx.reset();
355 PP.reset();
356
357 // Clear out old caches and data.
358 TopLevelDecls.clear();
359 StoredDiagnostics.clear();
360 CleanTemporaryFiles();
361 PreprocessedEntitiesByFile.clear();
362
Douglas Gregora88084b2010-02-18 18:08:43 +0000363 // Capture any diagnostics that would otherwise be dropped.
364 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
365 Clang.getDiagnostics(),
Douglas Gregorabc563f2010-07-19 21:46:24 +0000366 StoredDiagnostics);
367
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000368 // Create a file manager object to provide access to and cache the filesystem.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000369 Clang.setFileManager(&getFileManager());
370
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000371 // Create the source manager.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000372 Clang.setSourceManager(&getSourceManager());
373
374 llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
375 Act.reset(new TopLevelDeclTrackerAction(*this));
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000376 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
Daniel Dunbard3598a62010-06-07 23:23:06 +0000377 Clang.getFrontendOpts().Inputs[0].first))
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000378 goto error;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000379
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000380 Act->Execute();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000381
Daniel Dunbar64a32ba2009-12-01 21:57:33 +0000382 // Steal the created target, context, and preprocessor, and take back the
383 // source and file managers.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000384 Ctx.reset(Clang.takeASTContext());
385 PP.reset(Clang.takePreprocessor());
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000386 Clang.takeSourceManager();
387 Clang.takeFileManager();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000388 Target.reset(Clang.takeTarget());
389
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000390 Act->EndSourceFile();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000391
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000392 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000393
394 Invocation.reset(Clang.takeInvocation());
395 return false;
396
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000397error:
398 Clang.takeSourceManager();
399 Clang.takeFileManager();
400 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000401 Invocation.reset(Clang.takeInvocation());
402 return true;
403}
404
Douglas Gregor44c181a2010-07-23 00:33:23 +0000405/// \brief Simple function to retrieve a path for a preamble precompiled header.
406static std::string GetPreamblePCHPath() {
407 // FIXME: This is lame; sys::Path should provide this function (in particular,
408 // it should know how to find the temporary files dir).
409 // FIXME: This is really lame. I copied this code from the Driver!
410 std::string Error;
411 const char *TmpDir = ::getenv("TMPDIR");
412 if (!TmpDir)
413 TmpDir = ::getenv("TEMP");
414 if (!TmpDir)
415 TmpDir = ::getenv("TMP");
416 if (!TmpDir)
417 TmpDir = "/tmp";
418 llvm::sys::Path P(TmpDir);
419 P.appendComponent("preamble");
420 if (P.createTemporaryFileOnDisk())
421 return std::string();
422
423 P.appendSuffix("pch");
424 return P.str();
425}
426
Douglas Gregor175c4a92010-07-23 23:58:40 +0000427/// \brief Compute the preamble for the main file, providing
428std::pair<llvm::MemoryBuffer *, unsigned>
429ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
430 FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000431 PreprocessorOptions &PreprocessorOpts
Douglas Gregor175c4a92010-07-23 23:58:40 +0000432 = Invocation.getPreprocessorOpts();
433 CreatedBuffer = false;
434
Douglas Gregor44c181a2010-07-23 00:33:23 +0000435 // Try to determine if the main file has been remapped, either from the
436 // command line (to another file) or directly through the compiler invocation
437 // (to a memory buffer).
Douglas Gregor175c4a92010-07-23 23:58:40 +0000438 llvm::MemoryBuffer *Buffer = 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000439 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
440 if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
441 // Check whether there is a file-file remapping of the main file
442 for (PreprocessorOptions::remapped_file_iterator
Douglas Gregor175c4a92010-07-23 23:58:40 +0000443 M = PreprocessorOpts.remapped_file_begin(),
444 E = PreprocessorOpts.remapped_file_end();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000445 M != E;
446 ++M) {
447 llvm::sys::PathWithStatus MPath(M->first);
448 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
449 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
450 // We found a remapping. Try to load the resulting, remapped source.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000451 if (CreatedBuffer) {
Douglas Gregor44c181a2010-07-23 00:33:23 +0000452 delete Buffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000453 CreatedBuffer = false;
454 }
455
Douglas Gregor44c181a2010-07-23 00:33:23 +0000456 Buffer = llvm::MemoryBuffer::getFile(M->second);
457 if (!Buffer)
Douglas Gregor175c4a92010-07-23 23:58:40 +0000458 return std::make_pair((llvm::MemoryBuffer*)0, 0);
459 CreatedBuffer = true;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000460
Douglas Gregor175c4a92010-07-23 23:58:40 +0000461 // Remove this remapping. We've captured the buffer already.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000462 M = PreprocessorOpts.eraseRemappedFile(M);
463 E = PreprocessorOpts.remapped_file_end();
464 }
465 }
466 }
467
468 // Check whether there is a file-buffer remapping. It supercedes the
469 // file-file remapping.
470 for (PreprocessorOptions::remapped_file_buffer_iterator
471 M = PreprocessorOpts.remapped_file_buffer_begin(),
472 E = PreprocessorOpts.remapped_file_buffer_end();
473 M != E;
474 ++M) {
475 llvm::sys::PathWithStatus MPath(M->first);
476 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
477 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
478 // We found a remapping.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000479 if (CreatedBuffer) {
Douglas Gregor44c181a2010-07-23 00:33:23 +0000480 delete Buffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000481 CreatedBuffer = false;
482 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000483
Douglas Gregor175c4a92010-07-23 23:58:40 +0000484 Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
485
486 // Remove this remapping. We've captured the buffer already.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000487 M = PreprocessorOpts.eraseRemappedFile(M);
488 E = PreprocessorOpts.remapped_file_buffer_end();
489 }
490 }
Douglas Gregor175c4a92010-07-23 23:58:40 +0000491 }
Douglas Gregor44c181a2010-07-23 00:33:23 +0000492 }
493
494 // If the main source file was not remapped, load it now.
495 if (!Buffer) {
496 Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
497 if (!Buffer)
Douglas Gregor175c4a92010-07-23 23:58:40 +0000498 return std::make_pair((llvm::MemoryBuffer*)0, 0);
499
500 CreatedBuffer = true;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000501 }
502
Douglas Gregor175c4a92010-07-23 23:58:40 +0000503 return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer));
504}
505
Douglas Gregor754f3492010-07-24 00:38:13 +0000506static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
507 bool DeleteOld,
508 unsigned NewSize,
509 llvm::StringRef NewName) {
510 llvm::MemoryBuffer *Result
511 = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
512 memcpy(const_cast<char*>(Result->getBufferStart()),
513 Old->getBufferStart(), Old->getBufferSize());
514 memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
Douglas Gregor592508e2010-07-24 00:42:07 +0000515 ' ', NewSize - Old->getBufferSize() - 2);
516 const_cast<char*>(Result->getBufferEnd())[-2] = '\n';
Douglas Gregor754f3492010-07-24 00:38:13 +0000517 const_cast<char*>(Result->getBufferEnd())[-1] = 0;
518
519 if (DeleteOld)
520 delete Old;
521
522 return Result;
523}
524
Douglas Gregor175c4a92010-07-23 23:58:40 +0000525/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
526/// the source file.
527///
528/// This routine will compute the preamble of the main source file. If a
529/// non-trivial preamble is found, it will precompile that preamble into a
530/// precompiled header so that the precompiled preamble can be used to reduce
531/// reparsing time. If a precompiled preamble has already been constructed,
532/// this routine will determine if it is still valid and, if so, avoid
533/// rebuilding the precompiled preamble.
534///
Douglas Gregor754f3492010-07-24 00:38:13 +0000535/// \returns If the precompiled preamble can be used, returns a newly-allocated
536/// buffer that should be used in place of the main file when doing so.
537/// Otherwise, returns a NULL pointer.
538llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
Douglas Gregor175c4a92010-07-23 23:58:40 +0000539 CompilerInvocation PreambleInvocation(*Invocation);
540 FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
541 PreprocessorOptions &PreprocessorOpts
542 = PreambleInvocation.getPreprocessorOpts();
543
544 bool CreatedPreambleBuffer = false;
545 std::pair<llvm::MemoryBuffer *, unsigned> NewPreamble
546 = ComputePreamble(PreambleInvocation, CreatedPreambleBuffer);
547
548 if (!NewPreamble.second) {
549 // We couldn't find a preamble in the main source. Clear out the current
550 // preamble, if we have one. It's obviously no good any more.
551 Preamble.clear();
552 if (!PreambleFile.empty()) {
553 PreambleFile.eraseFromDisk();
554 PreambleFile.clear();
555 }
556 if (CreatedPreambleBuffer)
557 delete NewPreamble.first;
558
Douglas Gregor754f3492010-07-24 00:38:13 +0000559 return 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000560 }
561
562 if (!Preamble.empty()) {
563 // We've previously computed a preamble. Check whether we have the same
564 // preamble now that we did before, and that there's enough space in
565 // the main-file buffer within the precompiled preamble to fit the
566 // new main file.
567 if (Preamble.size() == NewPreamble.second &&
Douglas Gregor592508e2010-07-24 00:42:07 +0000568 NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
Douglas Gregor175c4a92010-07-23 23:58:40 +0000569 memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
570 NewPreamble.second) == 0) {
571 // The preamble has not changed. We may be able to re-use the precompiled
572 // preamble.
573 // FIXME: Check that none of the files used by the preamble have changed.
574
Douglas Gregor754f3492010-07-24 00:38:13 +0000575
Douglas Gregor175c4a92010-07-23 23:58:40 +0000576 // Okay! Re-use the precompiled preamble.
Douglas Gregor754f3492010-07-24 00:38:13 +0000577 return CreatePaddedMainFileBuffer(NewPreamble.first,
578 CreatedPreambleBuffer,
579 PreambleReservedSize,
580 FrontendOpts.Inputs[0].second);
Douglas Gregor175c4a92010-07-23 23:58:40 +0000581 }
582
583 // We can't reuse the previously-computed preamble. Build a new one.
584 Preamble.clear();
585 PreambleFile.eraseFromDisk();
586 }
587
588 // We did not previously compute a preamble, or it can't be reused anyway.
Douglas Gregor44c181a2010-07-23 00:33:23 +0000589
590 // Create a new buffer that stores the preamble. The buffer also contains
591 // extra space for the original contents of the file (which will be present
592 // when we actually parse the file) along with more room in case the file
Douglas Gregor175c4a92010-07-23 23:58:40 +0000593 // grows.
594 PreambleReservedSize = NewPreamble.first->getBufferSize();
595 if (PreambleReservedSize < 4096)
596 PreambleReservedSize = 8192;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000597 else
Douglas Gregor175c4a92010-07-23 23:58:40 +0000598 PreambleReservedSize *= 2;
599
Douglas Gregor44c181a2010-07-23 00:33:23 +0000600 llvm::MemoryBuffer *PreambleBuffer
Douglas Gregor175c4a92010-07-23 23:58:40 +0000601 = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000602 FrontendOpts.Inputs[0].second);
603 memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
Douglas Gregor175c4a92010-07-23 23:58:40 +0000604 NewPreamble.first->getBufferStart(), Preamble.size());
605 memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
Douglas Gregor592508e2010-07-24 00:42:07 +0000606 ' ', PreambleReservedSize - Preamble.size() - 2);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000607 const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = 0;
Douglas Gregor592508e2010-07-24 00:42:07 +0000608 const_cast<char*>(PreambleBuffer->getBufferEnd())[-2] = '\n';
609
Douglas Gregor175c4a92010-07-23 23:58:40 +0000610 // Save the preamble text for later; we'll need to compare against it for
611 // subsequent reparses.
612 Preamble.assign(NewPreamble.first->getBufferStart(),
Douglas Gregor754f3492010-07-24 00:38:13 +0000613 NewPreamble.first->getBufferStart() + NewPreamble.second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000614
615 // Remap the main source file to the preamble buffer.
Douglas Gregor175c4a92010-07-23 23:58:40 +0000616 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000617 PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
618
619 // Tell the compiler invocation to generate a temporary precompiled header.
620 FrontendOpts.ProgramAction = frontend::GeneratePCH;
621 // FIXME: Set ChainedPCH, once it is ready.
622 // FIXME: Generate the precompiled header into memory?
Douglas Gregor175c4a92010-07-23 23:58:40 +0000623 if (PreambleFile.isEmpty())
624 FrontendOpts.OutputFile = GetPreamblePCHPath();
625 else
626 FrontendOpts.OutputFile = PreambleFile.str();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000627
628 // Create the compiler instance to use for building the precompiled preamble.
629 CompilerInstance Clang;
630 Clang.setInvocation(&PreambleInvocation);
631 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
632
633 // Set up diagnostics.
634 Clang.setDiagnostics(&getDiagnostics());
635 Clang.setDiagnosticClient(getDiagnostics().getClient());
636
637 // Create the target instance.
638 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
639 Clang.getTargetOpts()));
640 if (!Clang.hasTarget()) {
641 Clang.takeDiagnosticClient();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000642 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
643 Preamble.clear();
644 if (CreatedPreambleBuffer)
645 delete NewPreamble.first;
646
Douglas Gregor754f3492010-07-24 00:38:13 +0000647 return 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000648 }
649
650 // Inform the target of the language options.
651 //
652 // FIXME: We shouldn't need to do this, the target should be immutable once
653 // created. This complexity should be lifted elsewhere.
654 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
655
656 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
657 "Invocation must have exactly one source file!");
658 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
659 "FIXME: AST inputs not yet supported here!");
660 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
661 "IR inputs not support here!");
662
663 // Clear out old caches and data.
664 StoredDiagnostics.clear();
665
666 // Capture any diagnostics that would otherwise be dropped.
667 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
668 Clang.getDiagnostics(),
669 StoredDiagnostics);
670
671 // Create a file manager object to provide access to and cache the filesystem.
672 Clang.setFileManager(new FileManager);
673
674 // Create the source manager.
675 Clang.setSourceManager(new SourceManager(getDiagnostics()));
676
677 // FIXME: Eventually, we'll have to track top-level declarations here, too.
678 llvm::OwningPtr<GeneratePCHAction> Act;
679 Act.reset(new GeneratePCHAction);
680 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
681 Clang.getFrontendOpts().Inputs[0].first)) {
682 Clang.takeDiagnosticClient();
683 Clang.takeInvocation();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000684 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
685 Preamble.clear();
686 if (CreatedPreambleBuffer)
687 delete NewPreamble.first;
688
Douglas Gregor754f3492010-07-24 00:38:13 +0000689 return 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000690 }
691
692 Act->Execute();
693 Act->EndSourceFile();
694 Clang.takeDiagnosticClient();
695 Clang.takeInvocation();
696
Douglas Gregor175c4a92010-07-23 23:58:40 +0000697 if (Diagnostics->getNumErrors() > 0) {
698 // There were errors parsing the preamble, so no precompiled header was
699 // generated. Forget that we even tried.
700 // FIXME: Should we leave a note for ourselves to try again?
701 llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
702 Preamble.clear();
703 if (CreatedPreambleBuffer)
704 delete NewPreamble.first;
705
Douglas Gregor754f3492010-07-24 00:38:13 +0000706 return 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000707 }
708
709 // Keep track of the preamble we precompiled.
710 PreambleFile = FrontendOpts.OutputFile;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000711 fprintf(stderr, "Preamble PCH: %s\n", FrontendOpts.OutputFile.c_str());
Douglas Gregor754f3492010-07-24 00:38:13 +0000712 return CreatePaddedMainFileBuffer(NewPreamble.first,
713 CreatedPreambleBuffer,
714 PreambleReservedSize,
715 FrontendOpts.Inputs[0].second);
Douglas Gregor44c181a2010-07-23 00:33:23 +0000716}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000717
718ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
719 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
720 bool OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000721 bool CaptureDiagnostics,
722 bool PrecompilePreamble) {
Douglas Gregorabc563f2010-07-19 21:46:24 +0000723 if (!Diags.getPtr()) {
724 // No diagnostics engine was provided, so create our own diagnostics object
725 // with the default options.
726 DiagnosticOptions DiagOpts;
727 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
728 }
729
730 // Create the AST unit.
731 llvm::OwningPtr<ASTUnit> AST;
732 AST.reset(new ASTUnit(false));
733 AST->Diagnostics = Diags;
734 AST->CaptureDiagnostics = CaptureDiagnostics;
735 AST->OnlyLocalDecls = OnlyLocalDecls;
736 AST->Invocation.reset(CI);
737
Douglas Gregor754f3492010-07-24 00:38:13 +0000738 llvm::MemoryBuffer *OverrideMainBuffer = 0;
Douglas Gregor44c181a2010-07-23 00:33:23 +0000739 if (PrecompilePreamble)
Douglas Gregor754f3492010-07-24 00:38:13 +0000740 OverrideMainBuffer = AST->BuildPrecompiledPreamble();
Douglas Gregor44c181a2010-07-23 00:33:23 +0000741
Douglas Gregor754f3492010-07-24 00:38:13 +0000742 if (!AST->Parse(OverrideMainBuffer))
Douglas Gregorabc563f2010-07-19 21:46:24 +0000743 return AST.take();
744
Douglas Gregor754f3492010-07-24 00:38:13 +0000745 delete OverrideMainBuffer;
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000746 return 0;
747}
Daniel Dunbar7b556682009-12-02 03:23:45 +0000748
749ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
750 const char **ArgEnd,
Douglas Gregor28019772010-04-05 23:52:57 +0000751 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Daniel Dunbar869824e2009-12-13 03:46:13 +0000752 llvm::StringRef ResourceFilesPath,
Daniel Dunbar7b556682009-12-02 03:23:45 +0000753 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000754 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000755 unsigned NumRemappedFiles,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000756 bool CaptureDiagnostics,
757 bool PrecompilePreamble) {
Douglas Gregor28019772010-04-05 23:52:57 +0000758 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000759 // No diagnostics engine was provided, so create our own diagnostics object
760 // with the default options.
761 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000762 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000763 }
764
Daniel Dunbar7b556682009-12-02 03:23:45 +0000765 llvm::SmallVector<const char *, 16> Args;
766 Args.push_back("<clang>"); // FIXME: Remove dummy argument.
767 Args.insert(Args.end(), ArgBegin, ArgEnd);
768
769 // FIXME: Find a cleaner way to force the driver into restricted modes. We
770 // also want to force it to use clang.
771 Args.push_back("-fsyntax-only");
772
Daniel Dunbar869824e2009-12-13 03:46:13 +0000773 // FIXME: We shouldn't have to pass in the path info.
Daniel Dunbar0bbad512010-07-19 00:44:04 +0000774 driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000775 "a.out", false, false, *Diags);
Daniel Dunbar3bd54cc2010-01-25 00:44:02 +0000776
777 // Don't check that inputs exist, they have been remapped.
778 TheDriver.setCheckInputsExist(false);
779
Daniel Dunbar7b556682009-12-02 03:23:45 +0000780 llvm::OwningPtr<driver::Compilation> C(
781 TheDriver.BuildCompilation(Args.size(), Args.data()));
782
783 // We expect to get back exactly one command job, if we didn't something
784 // failed.
785 const driver::JobList &Jobs = C->getJobs();
786 if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
787 llvm::SmallString<256> Msg;
788 llvm::raw_svector_ostream OS(Msg);
789 C->PrintJob(OS, C->getJobs(), "; ", true);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000790 Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
Daniel Dunbar7b556682009-12-02 03:23:45 +0000791 return 0;
792 }
793
794 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
795 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000796 Diags->Report(diag::err_fe_expected_clang_command);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000797 return 0;
798 }
799
800 const driver::ArgStringList &CCArgs = Cmd->getArguments();
Daniel Dunbar807b0612010-01-30 21:47:16 +0000801 llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
Dan Gohmancb421fa2010-04-19 16:39:44 +0000802 CompilerInvocation::CreateFromArgs(*CI,
803 const_cast<const char **>(CCArgs.data()),
804 const_cast<const char **>(CCArgs.data()) +
Douglas Gregor44c181a2010-07-23 00:33:23 +0000805 CCArgs.size(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000806 *Diags);
Daniel Dunbar1e69fe32009-12-13 03:45:58 +0000807
Douglas Gregor4db64a42010-01-23 00:14:00 +0000808 // Override any files that need remapping
809 for (unsigned I = 0; I != NumRemappedFiles; ++I)
Daniel Dunbar807b0612010-01-30 21:47:16 +0000810 CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000811 RemappedFiles[I].second);
Douglas Gregor4db64a42010-01-23 00:14:00 +0000812
Daniel Dunbar8b9adfe2009-12-15 00:06:45 +0000813 // Override the resources path.
Daniel Dunbar807b0612010-01-30 21:47:16 +0000814 CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
Daniel Dunbar7b556682009-12-02 03:23:45 +0000815
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000816 CI->getFrontendOpts().DisableFree = true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000817 return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000818 CaptureDiagnostics, PrecompilePreamble);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000819}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000820
821bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
822 if (!Invocation.get())
823 return true;
824
Douglas Gregor175c4a92010-07-23 23:58:40 +0000825 // If we have a preamble file lying around, build or reuse the precompiled
826 // preamble.
Douglas Gregor754f3492010-07-24 00:38:13 +0000827 llvm::MemoryBuffer *OverrideMainBuffer = 0;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000828 if (!PreambleFile.empty())
Douglas Gregor754f3492010-07-24 00:38:13 +0000829 OverrideMainBuffer = BuildPrecompiledPreamble();
Douglas Gregor175c4a92010-07-23 23:58:40 +0000830
Douglas Gregorabc563f2010-07-19 21:46:24 +0000831 // Clear out the diagnostics state.
832 getDiagnostics().Reset();
833
834 // Remap files.
835 Invocation->getPreprocessorOpts().clearRemappedFiles();
836 for (unsigned I = 0; I != NumRemappedFiles; ++I)
837 Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Douglas Gregor175c4a92010-07-23 23:58:40 +0000838 RemappedFiles[I].second);
839
840 // Parse the sources
Douglas Gregor754f3492010-07-24 00:38:13 +0000841 bool Result = Parse(OverrideMainBuffer);
842 delete OverrideMainBuffer;
Douglas Gregor175c4a92010-07-23 23:58:40 +0000843 return Result;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000844}