blob: 5b2af15c0d87186dc8ea4ff470b31c97d4ba407e [file] [log] [blame]
Argyrios Kyrtzidis3a08ec12009-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 Kyrtzidisce379752009-06-20 08:08:23 +000014#include "clang/Frontend/ASTUnit.h"
15#include "clang/Frontend/PCHReader.h"
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000016#include "clang/AST/ASTContext.h"
Daniel Dunbar764c0822009-12-01 09:51:01 +000017#include "clang/AST/ASTConsumer.h"
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000018#include "clang/AST/DeclVisitor.h"
19#include "clang/AST/StmtVisitor.h"
Daniel Dunbar55a17b62009-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 Dunbar764c0822009-12-01 09:51:01 +000024#include "clang/Frontend/CompilerInstance.h"
25#include "clang/Frontend/FrontendActions.h"
Daniel Dunbar55a17b62009-12-02 03:23:45 +000026#include "clang/Frontend/FrontendDiagnostic.h"
Daniel Dunbar764c0822009-12-01 09:51:01 +000027#include "clang/Frontend/FrontendOptions.h"
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000028#include "clang/Lex/HeaderSearch.h"
29#include "clang/Lex/Preprocessor.h"
Daniel Dunbarb9bbd542009-11-15 06:48:46 +000030#include "clang/Basic/TargetOptions.h"
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000031#include "clang/Basic/TargetInfo.h"
32#include "clang/Basic/Diagnostic.h"
Douglas Gregoraa98ed92010-01-23 00:14:00 +000033#include "llvm/Support/MemoryBuffer.h"
Daniel Dunbar55a17b62009-12-02 03:23:45 +000034#include "llvm/System/Host.h"
Benjamin Kramer6c839f82009-10-18 11:34:14 +000035#include "llvm/System/Path.h"
Douglas Gregorbe2d8c62010-07-23 00:33:23 +000036#include <cstdlib>
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000037using namespace clang;
38
Douglas Gregorbe2d8c62010-07-23 00:33:23 +000039PrecompiledPreamble::~PrecompiledPreamble() {
40 PreambleFile.eraseFromDisk();
41}
42
Douglas Gregord03e8232010-04-05 21:10:19 +000043ASTUnit::ASTUnit(bool _MainFileIsAST)
Douglas Gregoraa21cc42010-07-19 21:46:24 +000044 : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
45 ConcurrencyCheckValue(CheckUnlocked) { }
Douglas Gregord03e8232010-04-05 21:10:19 +000046
Daniel Dunbar764c0822009-12-01 09:51:01 +000047ASTUnit::~ASTUnit() {
Douglas Gregor0c7c2f82010-03-05 21:16:25 +000048 ConcurrencyCheckValue = CheckLocked;
Douglas Gregoraa21cc42010-07-19 21:46:24 +000049 CleanTemporaryFiles();
50}
51
52void ASTUnit::CleanTemporaryFiles() {
Douglas Gregor6cb5ba42010-02-18 23:35:40 +000053 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
54 TemporaryFiles[I].eraseFromDisk();
Douglas Gregoraa21cc42010-07-19 21:46:24 +000055 TemporaryFiles.clear();
Steve Naroff44cd60e2009-10-15 22:23:48 +000056}
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000057
58namespace {
59
60/// \brief Gathers information from PCHReader that will be used to initialize
61/// a Preprocessor.
Benjamin Kramer16634c22009-11-28 10:07:24 +000062class PCHInfoCollector : public PCHReaderListener {
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000063 LangOptions &LangOpt;
64 HeaderSearch &HSI;
65 std::string &TargetTriple;
66 std::string &Predefines;
67 unsigned &Counter;
Mike Stump11289f42009-09-09 15:08:12 +000068
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000069 unsigned NumHeaderInfos;
Mike Stump11289f42009-09-09 15:08:12 +000070
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000071public:
72 PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
73 std::string &TargetTriple, std::string &Predefines,
74 unsigned &Counter)
75 : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
76 Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
Mike Stump11289f42009-09-09 15:08:12 +000077
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000078 virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
79 LangOpt = LangOpts;
80 return false;
81 }
Mike Stump11289f42009-09-09 15:08:12 +000082
Daniel Dunbar20a682d2009-11-11 00:52:11 +000083 virtual bool ReadTargetTriple(llvm::StringRef Triple) {
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000084 TargetTriple = Triple;
85 return false;
86 }
Mike Stump11289f42009-09-09 15:08:12 +000087
Sebastian Redl8b41f302010-07-14 23:29:55 +000088 virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
Daniel Dunbar000c4ff2009-11-11 05:29:04 +000089 llvm::StringRef OriginalFileName,
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000090 std::string &SuggestedPredefines) {
Sebastian Redl8b41f302010-07-14 23:29:55 +000091 Predefines = Buffers[0].Data;
92 for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
93 Predefines += Buffers[I].Data;
94 }
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000095 return false;
96 }
Mike Stump11289f42009-09-09 15:08:12 +000097
Douglas Gregora2f49452010-03-16 19:09:18 +000098 virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +000099 HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
100 }
Mike Stump11289f42009-09-09 15:08:12 +0000101
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000102 virtual void ReadCounter(unsigned Value) {
103 Counter = Value;
104 }
105};
106
Douglas Gregor33cdd812010-02-18 18:08:43 +0000107class StoredDiagnosticClient : public DiagnosticClient {
108 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
109
110public:
111 explicit StoredDiagnosticClient(
112 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
113 : StoredDiags(StoredDiags) { }
114
115 virtual void HandleDiagnostic(Diagnostic::Level Level,
116 const DiagnosticInfo &Info);
117};
118
119/// \brief RAII object that optionally captures diagnostics, if
120/// there is no diagnostic client to capture them already.
121class CaptureDroppedDiagnostics {
122 Diagnostic &Diags;
123 StoredDiagnosticClient Client;
124 DiagnosticClient *PreviousClient;
125
126public:
127 CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
128 llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
129 : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
130 {
131 if (RequestCapture || Diags.getClient() == 0)
132 Diags.setClient(&Client);
133 }
134
135 ~CaptureDroppedDiagnostics() {
136 Diags.setClient(PreviousClient);
137 }
138};
139
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000140} // anonymous namespace
141
Douglas Gregor33cdd812010-02-18 18:08:43 +0000142void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
143 const DiagnosticInfo &Info) {
144 StoredDiags.push_back(StoredDiagnostic(Level, Info));
145}
146
Steve Naroffc0683b92009-09-03 18:19:54 +0000147const std::string &ASTUnit::getOriginalSourceFileName() {
Daniel Dunbara8a50932009-12-02 08:44:16 +0000148 return OriginalSourceFile;
Steve Naroffc0683b92009-09-03 18:19:54 +0000149}
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000150
Steve Naroff44cd60e2009-10-15 22:23:48 +0000151const std::string &ASTUnit::getPCHFileName() {
Daniel Dunbara18f9582009-12-02 21:47:43 +0000152 assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
Benjamin Kramer2ecf8eb2010-01-30 16:23:25 +0000153 return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
Steve Naroff44cd60e2009-10-15 22:23:48 +0000154}
155
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000156ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Douglas Gregor7f95d262010-04-05 23:52:57 +0000157 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Ted Kremenek8bcb1c62009-10-17 00:34:24 +0000158 bool OnlyLocalDecls,
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000159 RemappedFile *RemappedFiles,
Douglas Gregor33cdd812010-02-18 18:08:43 +0000160 unsigned NumRemappedFiles,
161 bool CaptureDiagnostics) {
Douglas Gregord03e8232010-04-05 21:10:19 +0000162 llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
163
Douglas Gregor7f95d262010-04-05 23:52:57 +0000164 if (!Diags.getPtr()) {
Douglas Gregord03e8232010-04-05 21:10:19 +0000165 // No diagnostics engine was provided, so create our own diagnostics object
166 // with the default options.
167 DiagnosticOptions DiagOpts;
Douglas Gregor7f95d262010-04-05 23:52:57 +0000168 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregord03e8232010-04-05 21:10:19 +0000169 }
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000170
171 AST->CaptureDiagnostics = CaptureDiagnostics;
Douglas Gregor16bef852009-10-16 20:01:17 +0000172 AST->OnlyLocalDecls = OnlyLocalDecls;
Douglas Gregor7f95d262010-04-05 23:52:57 +0000173 AST->Diagnostics = Diags;
Douglas Gregord03e8232010-04-05 21:10:19 +0000174 AST->FileMgr.reset(new FileManager);
175 AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
Steve Naroff505fb842009-10-19 14:34:22 +0000176 AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000177
Douglas Gregor33cdd812010-02-18 18:08:43 +0000178 // If requested, capture diagnostics in the ASTUnit.
Douglas Gregord03e8232010-04-05 21:10:19 +0000179 CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
Douglas Gregora2433152010-04-05 18:10:21 +0000180 AST->StoredDiagnostics);
Douglas Gregor33cdd812010-02-18 18:08:43 +0000181
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000182 for (unsigned I = 0; I != NumRemappedFiles; ++I) {
183 // Create the file entry for the file that we're mapping from.
184 const FileEntry *FromFile
185 = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
186 RemappedFiles[I].second->getBufferSize(),
187 0);
188 if (!FromFile) {
Douglas Gregord03e8232010-04-05 21:10:19 +0000189 AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000190 << RemappedFiles[I].first;
Douglas Gregor89a56c52010-02-27 01:32:48 +0000191 delete RemappedFiles[I].second;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000192 continue;
193 }
194
195 // Override the contents of the "from" file with the contents of
196 // the "to" file.
197 AST->getSourceManager().overrideFileContents(FromFile,
198 RemappedFiles[I].second);
199 }
200
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000201 // Gather Info for preprocessor construction later on.
Mike Stump11289f42009-09-09 15:08:12 +0000202
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000203 LangOptions LangInfo;
204 HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
205 std::string TargetTriple;
206 std::string Predefines;
207 unsigned Counter;
208
Daniel Dunbar3a0637b2009-09-03 05:59:50 +0000209 llvm::OwningPtr<PCHReader> Reader;
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000210 llvm::OwningPtr<ExternalASTSource> Source;
211
Ted Kremenek428c6372009-10-19 21:44:57 +0000212 Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
Douglas Gregord03e8232010-04-05 21:10:19 +0000213 AST->getDiagnostics()));
Daniel Dunbar2d9c7402009-09-03 05:59:35 +0000214 Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
215 Predefines, Counter));
216
217 switch (Reader->ReadPCH(Filename)) {
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000218 case PCHReader::Success:
219 break;
Mike Stump11289f42009-09-09 15:08:12 +0000220
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000221 case PCHReader::Failure:
Argyrios Kyrtzidis55c34112009-06-25 18:22:30 +0000222 case PCHReader::IgnorePCH:
Douglas Gregord03e8232010-04-05 21:10:19 +0000223 AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000224 return NULL;
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000225 }
Mike Stump11289f42009-09-09 15:08:12 +0000226
Daniel Dunbara8a50932009-12-02 08:44:16 +0000227 AST->OriginalSourceFile = Reader->getOriginalSourceFile();
228
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000229 // PCH loaded successfully. Now create the preprocessor.
Mike Stump11289f42009-09-09 15:08:12 +0000230
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000231 // Get information about the target being compiled for.
Daniel Dunbarb9bbd542009-11-15 06:48:46 +0000232 //
233 // FIXME: This is broken, we should store the TargetOptions in the PCH.
234 TargetOptions TargetOpts;
235 TargetOpts.ABI = "";
Charles Davis95a546e2010-06-11 01:06:47 +0000236 TargetOpts.CXXABI = "itanium";
Daniel Dunbarb9bbd542009-11-15 06:48:46 +0000237 TargetOpts.CPU = "";
238 TargetOpts.Features.clear();
239 TargetOpts.Triple = TargetTriple;
Douglas Gregord03e8232010-04-05 21:10:19 +0000240 AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
241 TargetOpts));
242 AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
243 *AST->Target.get(),
Daniel Dunbar7cd285f2009-09-21 03:03:39 +0000244 AST->getSourceManager(), HeaderInfo));
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000245 Preprocessor &PP = *AST->PP.get();
246
Daniel Dunbarb7bbfdd2009-09-21 03:03:47 +0000247 PP.setPredefines(Reader->getSuggestedPredefines());
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000248 PP.setCounterValue(Counter);
Daniel Dunbar2d9c7402009-09-03 05:59:35 +0000249 Reader->setPreprocessor(PP);
Mike Stump11289f42009-09-09 15:08:12 +0000250
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000251 // Create and initialize the ASTContext.
252
253 AST->Ctx.reset(new ASTContext(LangInfo,
Daniel Dunbar7cd285f2009-09-21 03:03:39 +0000254 AST->getSourceManager(),
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000255 *AST->Target.get(),
256 PP.getIdentifierTable(),
257 PP.getSelectorTable(),
258 PP.getBuiltinInfo(),
Daniel Dunbar19511922010-02-16 01:55:04 +0000259 /* FreeMemory = */ false,
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000260 /* size_reserve = */0));
261 ASTContext &Context = *AST->Ctx.get();
Mike Stump11289f42009-09-09 15:08:12 +0000262
Daniel Dunbar2d9c7402009-09-03 05:59:35 +0000263 Reader->InitializeContext(Context);
Mike Stump11289f42009-09-09 15:08:12 +0000264
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000265 // Attach the PCH reader to the AST context as an external AST
266 // source, so that declarations will be deserialized from the
267 // PCH file as needed.
Daniel Dunbar2d9c7402009-09-03 05:59:35 +0000268 Source.reset(Reader.take());
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000269 Context.setExternalSource(Source);
270
Mike Stump11289f42009-09-09 15:08:12 +0000271 return AST.take();
Argyrios Kyrtzidisce379752009-06-20 08:08:23 +0000272}
Daniel Dunbar764c0822009-12-01 09:51:01 +0000273
274namespace {
275
Daniel Dunbar644dca02009-12-04 08:17:33 +0000276class TopLevelDeclTrackerConsumer : public ASTConsumer {
277 ASTUnit &Unit;
278
279public:
280 TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
281
282 void HandleTopLevelDecl(DeclGroupRef D) {
Ted Kremenekacc59c32010-05-03 20:16:35 +0000283 for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
284 Decl *D = *it;
285 // FIXME: Currently ObjC method declarations are incorrectly being
286 // reported as top-level declarations, even though their DeclContext
287 // is the containing ObjC @interface/@implementation. This is a
288 // fundamental problem in the parser right now.
289 if (isa<ObjCMethodDecl>(D))
290 continue;
291 Unit.getTopLevelDecls().push_back(D);
292 }
Daniel Dunbar644dca02009-12-04 08:17:33 +0000293 }
294};
295
296class TopLevelDeclTrackerAction : public ASTFrontendAction {
297public:
298 ASTUnit &Unit;
299
Daniel Dunbar764c0822009-12-01 09:51:01 +0000300 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
301 llvm::StringRef InFile) {
Daniel Dunbar644dca02009-12-04 08:17:33 +0000302 return new TopLevelDeclTrackerConsumer(Unit);
Daniel Dunbar764c0822009-12-01 09:51:01 +0000303 }
304
305public:
Daniel Dunbar644dca02009-12-04 08:17:33 +0000306 TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
307
Daniel Dunbar764c0822009-12-01 09:51:01 +0000308 virtual bool hasCodeCompletionSupport() const { return false; }
309};
310
311}
312
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000313/// Parse the source file into a translation unit using the given compiler
314/// invocation, replacing the current translation unit.
315///
316/// \returns True if a failure occurred that causes the ASTUnit not to
317/// contain any translation-unit information, false otherwise.
318bool ASTUnit::Parse() {
319 if (!Invocation.get())
320 return true;
321
Daniel Dunbar764c0822009-12-01 09:51:01 +0000322 // Create the compiler instance to use for building the AST.
Daniel Dunbar7afbb8c2009-12-02 08:43:56 +0000323 CompilerInstance Clang;
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000324 Clang.setInvocation(Invocation.take());
325 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
326
327 // Set up diagnostics.
328 Clang.setDiagnostics(&getDiagnostics());
329 Clang.setDiagnosticClient(getDiagnostics().getClient());
Douglas Gregord03e8232010-04-05 21:10:19 +0000330
Daniel Dunbar764c0822009-12-01 09:51:01 +0000331 // Create the target instance.
332 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
333 Clang.getTargetOpts()));
Douglas Gregor33cdd812010-02-18 18:08:43 +0000334 if (!Clang.hasTarget()) {
Douglas Gregor33cdd812010-02-18 18:08:43 +0000335 Clang.takeDiagnosticClient();
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000336 return true;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000337 }
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000338
Daniel Dunbar764c0822009-12-01 09:51:01 +0000339 // Inform the target of the language options.
340 //
341 // FIXME: We shouldn't need to do this, the target should be immutable once
342 // created. This complexity should be lifted elsewhere.
343 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000344
Daniel Dunbar764c0822009-12-01 09:51:01 +0000345 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
346 "Invocation must have exactly one source file!");
Daniel Dunbar9b491e72010-06-07 23:22:09 +0000347 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
Daniel Dunbar764c0822009-12-01 09:51:01 +0000348 "FIXME: AST inputs not yet supported here!");
Daniel Dunbar9507f9c2010-06-07 23:26:47 +0000349 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
350 "IR inputs not support here!");
Daniel Dunbar764c0822009-12-01 09:51:01 +0000351
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000352 // Configure the various subsystems.
353 // FIXME: Should we retain the previous file manager?
354 FileMgr.reset(new FileManager);
355 SourceMgr.reset(new SourceManager(getDiagnostics()));
356 Ctx.reset();
357 PP.reset();
358
359 // Clear out old caches and data.
360 TopLevelDecls.clear();
361 StoredDiagnostics.clear();
362 CleanTemporaryFiles();
363 PreprocessedEntitiesByFile.clear();
364
Douglas Gregor33cdd812010-02-18 18:08:43 +0000365 // Capture any diagnostics that would otherwise be dropped.
366 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
367 Clang.getDiagnostics(),
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000368 StoredDiagnostics);
369
Daniel Dunbar764c0822009-12-01 09:51:01 +0000370 // Create a file manager object to provide access to and cache the filesystem.
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000371 Clang.setFileManager(&getFileManager());
372
Daniel Dunbar764c0822009-12-01 09:51:01 +0000373 // Create the source manager.
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000374 Clang.setSourceManager(&getSourceManager());
375
376 llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
377 Act.reset(new TopLevelDeclTrackerAction(*this));
Daniel Dunbar644dca02009-12-04 08:17:33 +0000378 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
Daniel Dunbar86546382010-06-07 23:23:06 +0000379 Clang.getFrontendOpts().Inputs[0].first))
Daniel Dunbar764c0822009-12-01 09:51:01 +0000380 goto error;
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000381
Daniel Dunbar644dca02009-12-04 08:17:33 +0000382 Act->Execute();
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000383
Daniel Dunbard2f8be32009-12-01 21:57:33 +0000384 // Steal the created target, context, and preprocessor, and take back the
385 // source and file managers.
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000386 Ctx.reset(Clang.takeASTContext());
387 PP.reset(Clang.takePreprocessor());
Daniel Dunbar764c0822009-12-01 09:51:01 +0000388 Clang.takeSourceManager();
389 Clang.takeFileManager();
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000390 Target.reset(Clang.takeTarget());
391
Daniel Dunbar644dca02009-12-04 08:17:33 +0000392 Act->EndSourceFile();
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000393
Daniel Dunbar764c0822009-12-01 09:51:01 +0000394 Clang.takeDiagnosticClient();
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000395
396 Invocation.reset(Clang.takeInvocation());
397 return false;
398
Daniel Dunbar764c0822009-12-01 09:51:01 +0000399error:
400 Clang.takeSourceManager();
401 Clang.takeFileManager();
402 Clang.takeDiagnosticClient();
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000403 Invocation.reset(Clang.takeInvocation());
404 return true;
405}
406
Douglas Gregorbe2d8c62010-07-23 00:33:23 +0000407/// \brief Simple function to retrieve a path for a preamble precompiled header.
408static std::string GetPreamblePCHPath() {
409 // FIXME: This is lame; sys::Path should provide this function (in particular,
410 // it should know how to find the temporary files dir).
411 // FIXME: This is really lame. I copied this code from the Driver!
412 std::string Error;
413 const char *TmpDir = ::getenv("TMPDIR");
414 if (!TmpDir)
415 TmpDir = ::getenv("TEMP");
416 if (!TmpDir)
417 TmpDir = ::getenv("TMP");
418 if (!TmpDir)
419 TmpDir = "/tmp";
420 llvm::sys::Path P(TmpDir);
421 P.appendComponent("preamble");
422 if (P.createTemporaryFileOnDisk())
423 return std::string();
424
425 P.appendSuffix("pch");
426 return P.str();
427}
428
429void ASTUnit::BuildPrecompiledPreamble() {
430 CompilerInvocation PreambleInvocation(*Invocation);
431 FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
432 PreprocessorOptions &PreprocessorOpts
433 = PreambleInvocation.getPreprocessorOpts();
434
435 // 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).
438 llvm::MemoryBuffer *Buffer = 0;
439 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
443 M = PreprocessorOpts.remapped_file_begin(),
444 E = PreprocessorOpts.remapped_file_end();
445 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.
451 if (Buffer)
452 delete Buffer;
453 Buffer = llvm::MemoryBuffer::getFile(M->second);
454 if (!Buffer)
455 return;
456
457 // Remove the file-file remapping.
458 M = PreprocessorOpts.eraseRemappedFile(M);
459 E = PreprocessorOpts.remapped_file_end();
460 }
461 }
462 }
463
464 // Check whether there is a file-buffer remapping. It supercedes the
465 // file-file remapping.
466 for (PreprocessorOptions::remapped_file_buffer_iterator
467 M = PreprocessorOpts.remapped_file_buffer_begin(),
468 E = PreprocessorOpts.remapped_file_buffer_end();
469 M != E;
470 ++M) {
471 llvm::sys::PathWithStatus MPath(M->first);
472 if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
473 if (MainFileStatus->uniqueID == MStatus->uniqueID) {
474 // We found a remapping.
475 if (Buffer)
476 delete Buffer;
477 Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
478
479 // Remove the file-buffer remapping.
480 M = PreprocessorOpts.eraseRemappedFile(M);
481 E = PreprocessorOpts.remapped_file_buffer_end();
482 }
483 }
484 }
485 }
486
487 // If the main source file was not remapped, load it now.
488 if (!Buffer) {
489 Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
490 if (!Buffer)
491 return;
492 }
493
494 // Try to compute the preamble.
495 unsigned PreambleLength = Lexer::ComputePreamble(Buffer);
496 if (PreambleLength == 0)
497 return;
498
499 // Create a new buffer that stores the preamble. The buffer also contains
500 // extra space for the original contents of the file (which will be present
501 // when we actually parse the file) along with more room in case the file
502 // grows.
503 unsigned PreambleBufferSize = Buffer->getBufferSize();
504 if (PreambleBufferSize < 4096)
505 PreambleBufferSize = 8192;
506 else
507 PreambleBufferSize *= 2;
508
509 llvm::MemoryBuffer *PreambleBuffer
510 = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleBufferSize,
511 FrontendOpts.Inputs[0].second);
512 memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
513 Buffer->getBufferStart(), PreambleLength);
514 memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + PreambleLength,
515 ' ', PreambleBufferSize - PreambleLength - 1);
516 const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = 0;
517 delete Buffer;
518
519 // Remap the main source file to the preamble buffer.
520 PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
521
522 // Tell the compiler invocation to generate a temporary precompiled header.
523 FrontendOpts.ProgramAction = frontend::GeneratePCH;
524 // FIXME: Set ChainedPCH, once it is ready.
525 // FIXME: Generate the precompiled header into memory?
526 FrontendOpts.OutputFile = GetPreamblePCHPath();
527
528 // Create the compiler instance to use for building the precompiled preamble.
529 CompilerInstance Clang;
530 Clang.setInvocation(&PreambleInvocation);
531 OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
532
533 // Set up diagnostics.
534 Clang.setDiagnostics(&getDiagnostics());
535 Clang.setDiagnosticClient(getDiagnostics().getClient());
536
537 // Create the target instance.
538 Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
539 Clang.getTargetOpts()));
540 if (!Clang.hasTarget()) {
541 Clang.takeDiagnosticClient();
542 return;
543 }
544
545 // Inform the target of the language options.
546 //
547 // FIXME: We shouldn't need to do this, the target should be immutable once
548 // created. This complexity should be lifted elsewhere.
549 Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
550
551 assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
552 "Invocation must have exactly one source file!");
553 assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
554 "FIXME: AST inputs not yet supported here!");
555 assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
556 "IR inputs not support here!");
557
558 // Clear out old caches and data.
559 StoredDiagnostics.clear();
560
561 // Capture any diagnostics that would otherwise be dropped.
562 CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
563 Clang.getDiagnostics(),
564 StoredDiagnostics);
565
566 // Create a file manager object to provide access to and cache the filesystem.
567 Clang.setFileManager(new FileManager);
568
569 // Create the source manager.
570 Clang.setSourceManager(new SourceManager(getDiagnostics()));
571
572 // FIXME: Eventually, we'll have to track top-level declarations here, too.
573 llvm::OwningPtr<GeneratePCHAction> Act;
574 Act.reset(new GeneratePCHAction);
575 if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
576 Clang.getFrontendOpts().Inputs[0].first)) {
577 Clang.takeDiagnosticClient();
578 Clang.takeInvocation();
579 return;
580 }
581
582 Act->Execute();
583 Act->EndSourceFile();
584 Clang.takeDiagnosticClient();
585 Clang.takeInvocation();
586
587 // FIXME: Keep track of the actual preamble header we created!
588 fprintf(stderr, "Preamble PCH: %s\n", FrontendOpts.OutputFile.c_str());
589}
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000590
591ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
592 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
593 bool OnlyLocalDecls,
Douglas Gregorbe2d8c62010-07-23 00:33:23 +0000594 bool CaptureDiagnostics,
595 bool PrecompilePreamble) {
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000596 if (!Diags.getPtr()) {
597 // No diagnostics engine was provided, so create our own diagnostics object
598 // with the default options.
599 DiagnosticOptions DiagOpts;
600 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
601 }
602
603 // Create the AST unit.
604 llvm::OwningPtr<ASTUnit> AST;
605 AST.reset(new ASTUnit(false));
606 AST->Diagnostics = Diags;
607 AST->CaptureDiagnostics = CaptureDiagnostics;
608 AST->OnlyLocalDecls = OnlyLocalDecls;
609 AST->Invocation.reset(CI);
610
Douglas Gregorbe2d8c62010-07-23 00:33:23 +0000611 if (PrecompilePreamble)
612 AST->BuildPrecompiledPreamble();
613
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000614 if (!AST->Parse())
615 return AST.take();
616
Daniel Dunbar764c0822009-12-01 09:51:01 +0000617 return 0;
618}
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000619
620ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
621 const char **ArgEnd,
Douglas Gregor7f95d262010-04-05 23:52:57 +0000622 llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
Daniel Dunbar8d4a2022009-12-13 03:46:13 +0000623 llvm::StringRef ResourceFilesPath,
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000624 bool OnlyLocalDecls,
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000625 RemappedFile *RemappedFiles,
Douglas Gregor33cdd812010-02-18 18:08:43 +0000626 unsigned NumRemappedFiles,
Douglas Gregorbe2d8c62010-07-23 00:33:23 +0000627 bool CaptureDiagnostics,
628 bool PrecompilePreamble) {
Douglas Gregor7f95d262010-04-05 23:52:57 +0000629 if (!Diags.getPtr()) {
Douglas Gregord03e8232010-04-05 21:10:19 +0000630 // No diagnostics engine was provided, so create our own diagnostics object
631 // with the default options.
632 DiagnosticOptions DiagOpts;
Douglas Gregor7f95d262010-04-05 23:52:57 +0000633 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregord03e8232010-04-05 21:10:19 +0000634 }
635
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000636 llvm::SmallVector<const char *, 16> Args;
637 Args.push_back("<clang>"); // FIXME: Remove dummy argument.
638 Args.insert(Args.end(), ArgBegin, ArgEnd);
639
640 // FIXME: Find a cleaner way to force the driver into restricted modes. We
641 // also want to force it to use clang.
642 Args.push_back("-fsyntax-only");
643
Daniel Dunbar8d4a2022009-12-13 03:46:13 +0000644 // FIXME: We shouldn't have to pass in the path info.
Daniel Dunbare38764c2010-07-19 00:44:04 +0000645 driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
Douglas Gregord03e8232010-04-05 21:10:19 +0000646 "a.out", false, false, *Diags);
Daniel Dunbarfcf2d422010-01-25 00:44:02 +0000647
648 // Don't check that inputs exist, they have been remapped.
649 TheDriver.setCheckInputsExist(false);
650
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000651 llvm::OwningPtr<driver::Compilation> C(
652 TheDriver.BuildCompilation(Args.size(), Args.data()));
653
654 // We expect to get back exactly one command job, if we didn't something
655 // failed.
656 const driver::JobList &Jobs = C->getJobs();
657 if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
658 llvm::SmallString<256> Msg;
659 llvm::raw_svector_ostream OS(Msg);
660 C->PrintJob(OS, C->getJobs(), "; ", true);
Douglas Gregord03e8232010-04-05 21:10:19 +0000661 Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000662 return 0;
663 }
664
665 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
666 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
Douglas Gregord03e8232010-04-05 21:10:19 +0000667 Diags->Report(diag::err_fe_expected_clang_command);
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000668 return 0;
669 }
670
671 const driver::ArgStringList &CCArgs = Cmd->getArguments();
Daniel Dunbar6b03ece2010-01-30 21:47:16 +0000672 llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
Dan Gohman145f3f12010-04-19 16:39:44 +0000673 CompilerInvocation::CreateFromArgs(*CI,
674 const_cast<const char **>(CCArgs.data()),
675 const_cast<const char **>(CCArgs.data()) +
Douglas Gregorbe2d8c62010-07-23 00:33:23 +0000676 CCArgs.size(),
Douglas Gregord03e8232010-04-05 21:10:19 +0000677 *Diags);
Daniel Dunbard6136772009-12-13 03:45:58 +0000678
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000679 // Override any files that need remapping
680 for (unsigned I = 0; I != NumRemappedFiles; ++I)
Daniel Dunbar6b03ece2010-01-30 21:47:16 +0000681 CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
Daniel Dunbar19511922010-02-16 01:55:04 +0000682 RemappedFiles[I].second);
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000683
Daniel Dunbara5a166d2009-12-15 00:06:45 +0000684 // Override the resources path.
Daniel Dunbar6b03ece2010-01-30 21:47:16 +0000685 CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000686
Daniel Dunbar19511922010-02-16 01:55:04 +0000687 CI->getFrontendOpts().DisableFree = true;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000688 return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
Douglas Gregorbe2d8c62010-07-23 00:33:23 +0000689 CaptureDiagnostics, PrecompilePreamble);
Daniel Dunbar55a17b62009-12-02 03:23:45 +0000690}
Douglas Gregoraa21cc42010-07-19 21:46:24 +0000691
692bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
693 if (!Invocation.get())
694 return true;
695
696 // Clear out the diagnostics state.
697 getDiagnostics().Reset();
698
699 // Remap files.
700 Invocation->getPreprocessorOpts().clearRemappedFiles();
701 for (unsigned I = 0; I != NumRemappedFiles; ++I)
702 Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
703 RemappedFiles[I].second);
704
705 return Parse();
706}