blob: 41627a547457af693059a8cba50682a55ad6b18f [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 Gregor44c181a2010-07-23 00:33:23 +000040PrecompiledPreamble::~PrecompiledPreamble() {
41 PreambleFile.eraseFromDisk();
42}
43
Douglas Gregor3687e9d2010-04-05 21:10:19 +000044ASTUnit::ASTUnit(bool _MainFileIsAST)
Douglas Gregorabc563f2010-07-19 21:46:24 +000045 : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
46 ConcurrencyCheckValue(CheckUnlocked) { }
Douglas Gregor3687e9d2010-04-05 21:10:19 +000047
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000048ASTUnit::~ASTUnit() {
Douglas Gregorbdf60622010-03-05 21:16:25 +000049 ConcurrencyCheckValue = CheckLocked;
Douglas Gregorabc563f2010-07-19 21:46:24 +000050 CleanTemporaryFiles();
51}
52
53void ASTUnit::CleanTemporaryFiles() {
Douglas Gregor313e26c2010-02-18 23:35:40 +000054 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
55 TemporaryFiles[I].eraseFromDisk();
Douglas Gregorabc563f2010-07-19 21:46:24 +000056 TemporaryFiles.clear();
Steve Naroffe19944c2009-10-15 22:23:48 +000057}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000058
59namespace {
60
61/// \brief Gathers information from PCHReader that will be used to initialize
62/// a Preprocessor.
Benjamin Kramerbd218282009-11-28 10:07:24 +000063class PCHInfoCollector : public PCHReaderListener {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000064 LangOptions &LangOpt;
65 HeaderSearch &HSI;
66 std::string &TargetTriple;
67 std::string &Predefines;
68 unsigned &Counter;
Mike Stump1eb44332009-09-09 15:08:12 +000069
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000070 unsigned NumHeaderInfos;
Mike Stump1eb44332009-09-09 15:08:12 +000071
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000072public:
73 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
74 std::string &TargetTriple, std::string &Predefines,
75 unsigned &Counter)
76 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
77 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000078
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000079 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
80 LangOpt = LangOpts;
81 return false;
82 }
Mike Stump1eb44332009-09-09 15:08:12 +000083
Daniel Dunbardc3c0d22009-11-11 00:52:11 +000084 virtual bool ReadTargetTriple(llvm::StringRef Triple) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000085 TargetTriple = Triple;
86 return false;
87 }
Mike Stump1eb44332009-09-09 15:08:12 +000088
Sebastian Redlcb481aa2010-07-14 23:29:55 +000089 virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
Daniel Dunbar7b5a1212009-11-11 05:29:04 +000090 llvm::StringRef OriginalFileName,
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000091 std::string &SuggestedPredefines) {
Sebastian Redlcb481aa2010-07-14 23:29:55 +000092 Predefines = Buffers[0].Data;
93 for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
94 Predefines += Buffers[I].Data;
95 }
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +000096 return false;
97 }
Mike Stump1eb44332009-09-09 15:08:12 +000098
Douglas Gregorec1afbf2010-03-16 19:09:18 +000099 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000100 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
101 }
Mike Stump1eb44332009-09-09 15:08:12 +0000102
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000103 virtual void ReadCounter(unsigned Value) {
104 Counter = Value;
105 }
106};
107
Douglas Gregora88084b2010-02-18 18:08:43 +0000108class StoredDiagnosticClient : public DiagnosticClient {
109 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
110
111public:
112 explicit StoredDiagnosticClient(
113 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
114 : StoredDiags(StoredDiags) { }
115
116 virtual void HandleDiagnostic(Diagnostic::Level Level,
117 const DiagnosticInfo &Info);
118};
119
120/// \brief RAII object that optionally captures diagnostics, if
121/// there is no diagnostic client to capture them already.
122class CaptureDroppedDiagnostics {
123 Diagnostic &Diags;
124 StoredDiagnosticClient Client;
125 DiagnosticClient *PreviousClient;
126
127public:
128 CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
129 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
130 : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
131 {
132 if (RequestCapture || Diags.getClient() == 0)
133 Diags.setClient(&Client);
134 }
135
136 ~CaptureDroppedDiagnostics() {
137 Diags.setClient(PreviousClient);
138 }
139};
140
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000141} // anonymous namespace
142
Douglas Gregora88084b2010-02-18 18:08:43 +0000143void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
144 const DiagnosticInfo &Info) {
145 StoredDiags.push_back(StoredDiagnostic(Level, Info));
146}
147
Steve Naroff77accc12009-09-03 18:19:54 +0000148const std::string &ASTUnit::getOriginalSourceFileName() {
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000149 return OriginalSourceFile;
Steve Naroff77accc12009-09-03 18:19:54 +0000150}
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000151
Steve Naroffe19944c2009-10-15 22:23:48 +0000152const std::string &ASTUnit::getPCHFileName() {
Daniel Dunbarc7822db2009-12-02 21:47:43 +0000153 assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
Benjamin Kramer7297c182010-01-30 16:23:25 +0000154 return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
Steve Naroffe19944c2009-10-15 22:23:48 +0000155}
156
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000157ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Douglas Gregor28019772010-04-05 23:52:57 +0000158 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Ted Kremenek5cf48762009-10-17 00:34:24 +0000159 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000160 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000161 unsigned NumRemappedFiles,
162 bool CaptureDiagnostics) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000163 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
164
Douglas Gregor28019772010-04-05 23:52:57 +0000165 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000166 // No diagnostics engine was provided, so create our own diagnostics object
167 // with the default options.
168 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000169 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000170 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000171
172 AST->CaptureDiagnostics = CaptureDiagnostics;
Douglas Gregor7d1d49d2009-10-16 20:01:17 +0000173 AST->OnlyLocalDecls = OnlyLocalDecls;
Douglas Gregor28019772010-04-05 23:52:57 +0000174 AST->Diagnostics = Diags;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000175 AST->FileMgr.reset(new FileManager);
176 AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
Steve Naroff36c44642009-10-19 14:34:22 +0000177 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000178
Douglas Gregora88084b2010-02-18 18:08:43 +0000179 // If requested, capture diagnostics in the ASTUnit.
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000180 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
Douglas Gregor405634b2010-04-05 18:10:21 +0000181 AST->StoredDiagnostics);
Douglas Gregora88084b2010-02-18 18:08:43 +0000182
Douglas Gregor4db64a42010-01-23 00:14:00 +0000183 for (unsigned I = 0; I != NumRemappedFiles; ++I) {
184 // Create the file entry for the file that we're mapping from.
185 const FileEntry *FromFile
186 = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
187 RemappedFiles[I].second->getBufferSize(),
188 0);
189 if (!FromFile) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000190 AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
Douglas Gregor4db64a42010-01-23 00:14:00 +0000191 << RemappedFiles[I].first;
Douglas Gregorc8dfe5e2010-02-27 01:32:48 +0000192 delete RemappedFiles[I].second;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000193 continue;
194 }
195
196 // Override the contents of the "from" file with the contents of
197 // the "to" file.
198 AST->getSourceManager().overrideFileContents(FromFile,
199 RemappedFiles[I].second);
200 }
201
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000202 // Gather Info for preprocessor construction later on.
Mike Stump1eb44332009-09-09 15:08:12 +0000203
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000204 LangOptions LangInfo;
205 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
206 std::string TargetTriple;
207 std::string Predefines;
208 unsigned Counter;
209
Daniel Dunbarbce6f622009-09-03 05:59:50 +0000210 llvm::OwningPtr<PCHReader> Reader;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000211 llvm::OwningPtr<ExternalASTSource> Source;
212
Ted Kremenekfc062212009-10-19 21:44:57 +0000213 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000214 AST->getDiagnostics()));
Daniel Dunbarcc318932009-09-03 05:59:35 +0000215 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
216 Predefines, Counter));
217
218 switch (Reader->ReadPCH(Filename)) {
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000219 case PCHReader::Success:
220 break;
Mike Stump1eb44332009-09-09 15:08:12 +0000221
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000222 case PCHReader::Failure:
Argyrios Kyrtzidis106c9982009-06-25 18:22:30 +0000223 case PCHReader::IgnorePCH:
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000224 AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000225 return NULL;
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000226 }
Mike Stump1eb44332009-09-09 15:08:12 +0000227
Daniel Dunbar68d40e22009-12-02 08:44:16 +0000228 AST->OriginalSourceFile = Reader->getOriginalSourceFile();
229
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000230 // PCH loaded successfully. Now create the preprocessor.
Mike Stump1eb44332009-09-09 15:08:12 +0000231
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000232 // Get information about the target being compiled for.
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000233 //
234 // FIXME: This is broken, we should store the TargetOptions in the PCH.
235 TargetOptions TargetOpts;
236 TargetOpts.ABI = "";
Charles Davis98b7c5c2010-06-11 01:06:47 +0000237 TargetOpts.CXXABI = "itanium";
Daniel Dunbard58c03f2009-11-15 06:48:46 +0000238 TargetOpts.CPU = "";
239 TargetOpts.Features.clear();
240 TargetOpts.Triple = TargetTriple;
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000241 AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
242 TargetOpts));
243 AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
244 *AST->Target.get(),
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000245 AST->getSourceManager(), HeaderInfo));
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000246 Preprocessor &PP = *AST->PP.get();
247
Daniel Dunbard5b61262009-09-21 03:03:47 +0000248 PP.setPredefines(Reader->getSuggestedPredefines());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000249 PP.setCounterValue(Counter);
Daniel Dunbarcc318932009-09-03 05:59:35 +0000250 Reader->setPreprocessor(PP);
Mike Stump1eb44332009-09-09 15:08:12 +0000251
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000252 // Create and initialize the ASTContext.
253
254 AST->Ctx.reset(new ASTContext(LangInfo,
Daniel Dunbar31b87d82009-09-21 03:03:39 +0000255 AST->getSourceManager(),
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000256 *AST->Target.get(),
257 PP.getIdentifierTable(),
258 PP.getSelectorTable(),
259 PP.getBuiltinInfo(),
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000260 /* FreeMemory = */ false,
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000261 /* size_reserve = */0));
262 ASTContext &Context = *AST->Ctx.get();
Mike Stump1eb44332009-09-09 15:08:12 +0000263
Daniel Dunbarcc318932009-09-03 05:59:35 +0000264 Reader->InitializeContext(Context);
Mike Stump1eb44332009-09-09 15:08:12 +0000265
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000266 // Attach the PCH reader to the AST context as an external AST
267 // source, so that declarations will be deserialized from the
268 // PCH file as needed.
Daniel Dunbarcc318932009-09-03 05:59:35 +0000269 Source.reset(Reader.take());
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000270 Context.setExternalSource(Source);
271
Mike Stump1eb44332009-09-09 15:08:12 +0000272 return AST.take();
Argyrios Kyrtzidis0853a022009-06-20 08:08:23 +0000273}
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000274
275namespace {
276
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000277class TopLevelDeclTrackerConsumer : public ASTConsumer {
278 ASTUnit &Unit;
279
280public:
281 TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
282
283 void HandleTopLevelDecl(DeclGroupRef D) {
Ted Kremenekda5a4282010-05-03 20:16:35 +0000284 for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
285 Decl *D = *it;
286 // FIXME: Currently ObjC method declarations are incorrectly being
287 // reported as top-level declarations, even though their DeclContext
288 // is the containing ObjC @interface/@implementation. This is a
289 // fundamental problem in the parser right now.
290 if (isa<ObjCMethodDecl>(D))
291 continue;
292 Unit.getTopLevelDecls().push_back(D);
293 }
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000294 }
295};
296
297class TopLevelDeclTrackerAction : public ASTFrontendAction {
298public:
299 ASTUnit &Unit;
300
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000301 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
302 llvm::StringRef InFile) {
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000303 return new TopLevelDeclTrackerConsumer(Unit);
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000304 }
305
306public:
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000307 TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
308
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000309 virtual bool hasCodeCompletionSupport() const { return false; }
310};
311
312}
313
Douglas Gregorabc563f2010-07-19 21:46:24 +0000314/// Parse the source file into a translation unit using the given compiler
315/// invocation, replacing the current translation unit.
316///
317/// \returns True if a failure occurred that causes the ASTUnit not to
318/// contain any translation-unit information, false otherwise.
319bool ASTUnit::Parse() {
320 if (!Invocation.get())
321 return true;
322
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000323 // Create the compiler instance to use for building the AST.
Daniel Dunbarcb6dda12009-12-02 08:43:56 +0000324 CompilerInstance Clang;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000325 Clang.setInvocation(Invocation.take());
326 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
327
328 // Set up diagnostics.
329 Clang.setDiagnostics(&getDiagnostics());
330 Clang.setDiagnosticClient(getDiagnostics().getClient());
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000331
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000332 // Create the target instance.
333 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
334 Clang.getTargetOpts()));
Douglas Gregora88084b2010-02-18 18:08:43 +0000335 if (!Clang.hasTarget()) {
Douglas Gregora88084b2010-02-18 18:08:43 +0000336 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000337 return true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000338 }
Douglas Gregorabc563f2010-07-19 21:46:24 +0000339
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000340 // Inform the target of the language options.
341 //
342 // FIXME: We shouldn't need to do this, the target should be immutable once
343 // created. This complexity should be lifted elsewhere.
344 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
Douglas Gregorabc563f2010-07-19 21:46:24 +0000345
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000346 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
347 "Invocation must have exactly one source file!");
Daniel Dunbarc34ce3f2010-06-07 23:22:09 +0000348 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000349 "FIXME: AST inputs not yet supported here!");
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000350 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
351 "IR inputs not support here!");
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000352
Douglas Gregorabc563f2010-07-19 21:46:24 +0000353 // Configure the various subsystems.
354 // FIXME: Should we retain the previous file manager?
355 FileMgr.reset(new FileManager);
356 SourceMgr.reset(new SourceManager(getDiagnostics()));
357 Ctx.reset();
358 PP.reset();
359
360 // Clear out old caches and data.
361 TopLevelDecls.clear();
362 StoredDiagnostics.clear();
363 CleanTemporaryFiles();
364 PreprocessedEntitiesByFile.clear();
365
Douglas Gregora88084b2010-02-18 18:08:43 +0000366 // Capture any diagnostics that would otherwise be dropped.
367 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
368 Clang.getDiagnostics(),
Douglas Gregorabc563f2010-07-19 21:46:24 +0000369 StoredDiagnostics);
370
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000371 // Create a file manager object to provide access to and cache the filesystem.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000372 Clang.setFileManager(&getFileManager());
373
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000374 // Create the source manager.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000375 Clang.setSourceManager(&getSourceManager());
376
377 llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
378 Act.reset(new TopLevelDeclTrackerAction(*this));
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000379 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
Daniel Dunbard3598a62010-06-07 23:23:06 +0000380 Clang.getFrontendOpts().Inputs[0].first))
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000381 goto error;
Douglas Gregorabc563f2010-07-19 21:46:24 +0000382
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000383 Act->Execute();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000384
Daniel Dunbar64a32ba2009-12-01 21:57:33 +0000385 // Steal the created target, context, and preprocessor, and take back the
386 // source and file managers.
Douglas Gregorabc563f2010-07-19 21:46:24 +0000387 Ctx.reset(Clang.takeASTContext());
388 PP.reset(Clang.takePreprocessor());
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000389 Clang.takeSourceManager();
390 Clang.takeFileManager();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000391 Target.reset(Clang.takeTarget());
392
Daniel Dunbarf772d1e2009-12-04 08:17:33 +0000393 Act->EndSourceFile();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000394
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000395 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000396
397 Invocation.reset(Clang.takeInvocation());
398 return false;
399
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000400error:
401 Clang.takeSourceManager();
402 Clang.takeFileManager();
403 Clang.takeDiagnosticClient();
Douglas Gregorabc563f2010-07-19 21:46:24 +0000404 Invocation.reset(Clang.takeInvocation());
405 return true;
406}
407
Douglas Gregor44c181a2010-07-23 00:33:23 +0000408/// \brief Simple function to retrieve a path for a preamble precompiled header.
409static std::string GetPreamblePCHPath() {
410 // FIXME: This is lame; sys::Path should provide this function (in particular,
411 // it should know how to find the temporary files dir).
412 // FIXME: This is really lame. I copied this code from the Driver!
413 std::string Error;
414 const char *TmpDir = ::getenv("TMPDIR");
415 if (!TmpDir)
416 TmpDir = ::getenv("TEMP");
417 if (!TmpDir)
418 TmpDir = ::getenv("TMP");
419 if (!TmpDir)
420 TmpDir = "/tmp";
421 llvm::sys::Path P(TmpDir);
422 P.appendComponent("preamble");
423 if (P.createTemporaryFileOnDisk())
424 return std::string();
425
426 P.appendSuffix("pch");
427 return P.str();
428}
429
430void ASTUnit::BuildPrecompiledPreamble() {
431 CompilerInvocation PreambleInvocation(*Invocation);
432 FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
433 PreprocessorOptions &PreprocessorOpts
434 = PreambleInvocation.getPreprocessorOpts();
435
436 // Try to determine if the main file has been remapped, either from the
437 // command line (to another file) or directly through the compiler invocation
438 // (to a memory buffer).
439 llvm::MemoryBuffer *Buffer = 0;
440 llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
441 if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
442 // Check whether there is a file-file remapping of the main file
443 for (PreprocessorOptions::remapped_file_iterator
444 M = PreprocessorOpts.remapped_file_begin(),
445 E = PreprocessorOpts.remapped_file_end();
446 M != E;
447 ++M) {
448 llvm::sys::PathWithStatus MPath(M->first);
449 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
450 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
451 // We found a remapping. Try to load the resulting, remapped source.
452 if (Buffer)
453 delete Buffer;
454 Buffer = llvm::MemoryBuffer::getFile(M->second);
455 if (!Buffer)
456 return;
457
458 // Remove the file-file remapping.
459 M = PreprocessorOpts.eraseRemappedFile(M);
460 E = PreprocessorOpts.remapped_file_end();
461 }
462 }
463 }
464
465 // Check whether there is a file-buffer remapping. It supercedes the
466 // file-file remapping.
467 for (PreprocessorOptions::remapped_file_buffer_iterator
468 M = PreprocessorOpts.remapped_file_buffer_begin(),
469 E = PreprocessorOpts.remapped_file_buffer_end();
470 M != E;
471 ++M) {
472 llvm::sys::PathWithStatus MPath(M->first);
473 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
474 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
475 // We found a remapping.
476 if (Buffer)
477 delete Buffer;
478 Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
479
480 // Remove the file-buffer remapping.
481 M = PreprocessorOpts.eraseRemappedFile(M);
482 E = PreprocessorOpts.remapped_file_buffer_end();
483 }
484 }
485 }
486 }
487
488 // If the main source file was not remapped, load it now.
489 if (!Buffer) {
490 Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
491 if (!Buffer)
492 return;
493 }
494
495 // Try to compute the preamble.
496 unsigned PreambleLength = Lexer::ComputePreamble(Buffer);
497 if (PreambleLength == 0)
498 return;
499
500 // Create a new buffer that stores the preamble. The buffer also contains
501 // extra space for the original contents of the file (which will be present
502 // when we actually parse the file) along with more room in case the file
503 // grows.
504 unsigned PreambleBufferSize = Buffer->getBufferSize();
505 if (PreambleBufferSize < 4096)
506 PreambleBufferSize = 8192;
507 else
508 PreambleBufferSize *= 2;
509
510 llvm::MemoryBuffer *PreambleBuffer
511 = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleBufferSize,
512 FrontendOpts.Inputs[0].second);
513 memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
514 Buffer->getBufferStart(), PreambleLength);
515 memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + PreambleLength,
516 ' ', PreambleBufferSize - PreambleLength - 1);
517 const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = 0;
518 delete Buffer;
519
520 // Remap the main source file to the preamble buffer.
521 PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
522
523 // Tell the compiler invocation to generate a temporary precompiled header.
524 FrontendOpts.ProgramAction = frontend::GeneratePCH;
525 // FIXME: Set ChainedPCH, once it is ready.
526 // FIXME: Generate the precompiled header into memory?
527 FrontendOpts.OutputFile = GetPreamblePCHPath();
528
529 // Create the compiler instance to use for building the precompiled preamble.
530 CompilerInstance Clang;
531 Clang.setInvocation(&PreambleInvocation);
532 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
533
534 // Set up diagnostics.
535 Clang.setDiagnostics(&getDiagnostics());
536 Clang.setDiagnosticClient(getDiagnostics().getClient());
537
538 // Create the target instance.
539 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
540 Clang.getTargetOpts()));
541 if (!Clang.hasTarget()) {
542 Clang.takeDiagnosticClient();
543 return;
544 }
545
546 // Inform the target of the language options.
547 //
548 // FIXME: We shouldn't need to do this, the target should be immutable once
549 // created. This complexity should be lifted elsewhere.
550 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
551
552 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
553 "Invocation must have exactly one source file!");
554 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
555 "FIXME: AST inputs not yet supported here!");
556 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
557 "IR inputs not support here!");
558
559 // Clear out old caches and data.
560 StoredDiagnostics.clear();
561
562 // Capture any diagnostics that would otherwise be dropped.
563 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
564 Clang.getDiagnostics(),
565 StoredDiagnostics);
566
567 // Create a file manager object to provide access to and cache the filesystem.
568 Clang.setFileManager(new FileManager);
569
570 // Create the source manager.
571 Clang.setSourceManager(new SourceManager(getDiagnostics()));
572
573 // FIXME: Eventually, we'll have to track top-level declarations here, too.
574 llvm::OwningPtr<GeneratePCHAction> Act;
575 Act.reset(new GeneratePCHAction);
576 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
577 Clang.getFrontendOpts().Inputs[0].first)) {
578 Clang.takeDiagnosticClient();
579 Clang.takeInvocation();
580 return;
581 }
582
583 Act->Execute();
584 Act->EndSourceFile();
585 Clang.takeDiagnosticClient();
586 Clang.takeInvocation();
587
588 // FIXME: Keep track of the actual preamble header we created!
589 fprintf(stderr, "Preamble PCH: %s\n", FrontendOpts.OutputFile.c_str());
590}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000591
592ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
593 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
594 bool OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000595 bool CaptureDiagnostics,
596 bool PrecompilePreamble) {
Douglas Gregorabc563f2010-07-19 21:46:24 +0000597 if (!Diags.getPtr()) {
598 // No diagnostics engine was provided, so create our own diagnostics object
599 // with the default options.
600 DiagnosticOptions DiagOpts;
601 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
602 }
603
604 // Create the AST unit.
605 llvm::OwningPtr<ASTUnit> AST;
606 AST.reset(new ASTUnit(false));
607 AST->Diagnostics = Diags;
608 AST->CaptureDiagnostics = CaptureDiagnostics;
609 AST->OnlyLocalDecls = OnlyLocalDecls;
610 AST->Invocation.reset(CI);
611
Douglas Gregor44c181a2010-07-23 00:33:23 +0000612 if (PrecompilePreamble)
613 AST->BuildPrecompiledPreamble();
614
Douglas Gregorabc563f2010-07-19 21:46:24 +0000615 if (!AST->Parse())
616 return AST.take();
617
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000618 return 0;
619}
Daniel Dunbar7b556682009-12-02 03:23:45 +0000620
621ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
622 const char **ArgEnd,
Douglas Gregor28019772010-04-05 23:52:57 +0000623 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Daniel Dunbar869824e2009-12-13 03:46:13 +0000624 llvm::StringRef ResourceFilesPath,
Daniel Dunbar7b556682009-12-02 03:23:45 +0000625 bool OnlyLocalDecls,
Douglas Gregor4db64a42010-01-23 00:14:00 +0000626 RemappedFile *RemappedFiles,
Douglas Gregora88084b2010-02-18 18:08:43 +0000627 unsigned NumRemappedFiles,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000628 bool CaptureDiagnostics,
629 bool PrecompilePreamble) {
Douglas Gregor28019772010-04-05 23:52:57 +0000630 if (!Diags.getPtr()) {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000631 // No diagnostics engine was provided, so create our own diagnostics object
632 // with the default options.
633 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000634 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000635 }
636
Daniel Dunbar7b556682009-12-02 03:23:45 +0000637 llvm::SmallVector<const char *, 16> Args;
638 Args.push_back("<clang>"); // FIXME: Remove dummy argument.
639 Args.insert(Args.end(), ArgBegin, ArgEnd);
640
641 // FIXME: Find a cleaner way to force the driver into restricted modes. We
642 // also want to force it to use clang.
643 Args.push_back("-fsyntax-only");
644
Daniel Dunbar869824e2009-12-13 03:46:13 +0000645 // FIXME: We shouldn't have to pass in the path info.
Daniel Dunbar0bbad512010-07-19 00:44:04 +0000646 driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000647 "a.out", false, false, *Diags);
Daniel Dunbar3bd54cc2010-01-25 00:44:02 +0000648
649 // Don't check that inputs exist, they have been remapped.
650 TheDriver.setCheckInputsExist(false);
651
Daniel Dunbar7b556682009-12-02 03:23:45 +0000652 llvm::OwningPtr<driver::Compilation> C(
653 TheDriver.BuildCompilation(Args.size(), Args.data()));
654
655 // We expect to get back exactly one command job, if we didn't something
656 // failed.
657 const driver::JobList &Jobs = C->getJobs();
658 if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
659 llvm::SmallString<256> Msg;
660 llvm::raw_svector_ostream OS(Msg);
661 C->PrintJob(OS, C->getJobs(), "; ", true);
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000662 Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
Daniel Dunbar7b556682009-12-02 03:23:45 +0000663 return 0;
664 }
665
666 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
667 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000668 Diags->Report(diag::err_fe_expected_clang_command);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000669 return 0;
670 }
671
672 const driver::ArgStringList &CCArgs = Cmd->getArguments();
Daniel Dunbar807b0612010-01-30 21:47:16 +0000673 llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
Dan Gohmancb421fa2010-04-19 16:39:44 +0000674 CompilerInvocation::CreateFromArgs(*CI,
675 const_cast<const char **>(CCArgs.data()),
676 const_cast<const char **>(CCArgs.data()) +
Douglas Gregor44c181a2010-07-23 00:33:23 +0000677 CCArgs.size(),
Douglas Gregor3687e9d2010-04-05 21:10:19 +0000678 *Diags);
Daniel Dunbar1e69fe32009-12-13 03:45:58 +0000679
Douglas Gregor4db64a42010-01-23 00:14:00 +0000680 // Override any files that need remapping
681 for (unsigned I = 0; I != NumRemappedFiles; ++I)
Daniel Dunbar807b0612010-01-30 21:47:16 +0000682 CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000683 RemappedFiles[I].second);
Douglas Gregor4db64a42010-01-23 00:14:00 +0000684
Daniel Dunbar8b9adfe2009-12-15 00:06:45 +0000685 // Override the resources path.
Daniel Dunbar807b0612010-01-30 21:47:16 +0000686 CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
Daniel Dunbar7b556682009-12-02 03:23:45 +0000687
Daniel Dunbarb26d4832010-02-16 01:55:04 +0000688 CI->getFrontendOpts().DisableFree = true;
Douglas Gregora88084b2010-02-18 18:08:43 +0000689 return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
Douglas Gregor44c181a2010-07-23 00:33:23 +0000690 CaptureDiagnostics, PrecompilePreamble);
Daniel Dunbar7b556682009-12-02 03:23:45 +0000691}
Douglas Gregorabc563f2010-07-19 21:46:24 +0000692
693bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
694 if (!Invocation.get())
695 return true;
696
697 // Clear out the diagnostics state.
698 getDiagnostics().Reset();
699
700 // Remap files.
701 Invocation->getPreprocessorOpts().clearRemappedFiles();
702 for (unsigned I = 0; I != NumRemappedFiles; ++I)
703 Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
704 RemappedFiles[I].second);
705
706 return Parse();
707}