]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Frontend/ASTUnit.cpp
Update clang to r94309.
[FreeBSD/FreeBSD.git] / lib / Frontend / ASTUnit.cpp
1 //===--- 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
14 #include "clang/Frontend/ASTUnit.h"
15 #include "clang/Frontend/PCHReader.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/ASTConsumer.h"
18 #include "clang/AST/DeclVisitor.h"
19 #include "clang/AST/StmtVisitor.h"
20 #include "clang/Driver/Compilation.h"
21 #include "clang/Driver/Driver.h"
22 #include "clang/Driver/Job.h"
23 #include "clang/Driver/Tool.h"
24 #include "clang/Frontend/CompilerInstance.h"
25 #include "clang/Frontend/FrontendActions.h"
26 #include "clang/Frontend/FrontendDiagnostic.h"
27 #include "clang/Frontend/FrontendOptions.h"
28 #include "clang/Lex/HeaderSearch.h"
29 #include "clang/Lex/Preprocessor.h"
30 #include "clang/Basic/TargetOptions.h"
31 #include "clang/Basic/TargetInfo.h"
32 #include "clang/Basic/Diagnostic.h"
33 #include "llvm/Support/MemoryBuffer.h"
34 #include "llvm/System/Host.h"
35 #include "llvm/System/Path.h"
36 using namespace clang;
37
38 ASTUnit::ASTUnit(bool _MainFileIsAST)
39   : tempFile(false), MainFileIsAST(_MainFileIsAST) {
40 }
41 ASTUnit::~ASTUnit() {
42   if (tempFile)
43     llvm::sys::Path(getPCHFileName()).eraseFromDisk();
44 }
45
46 namespace {
47
48 /// \brief Gathers information from PCHReader that will be used to initialize
49 /// a Preprocessor.
50 class PCHInfoCollector : public PCHReaderListener {
51   LangOptions &LangOpt;
52   HeaderSearch &HSI;
53   std::string &TargetTriple;
54   std::string &Predefines;
55   unsigned &Counter;
56
57   unsigned NumHeaderInfos;
58
59 public:
60   PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
61                    std::string &TargetTriple, std::string &Predefines,
62                    unsigned &Counter)
63     : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
64       Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
65
66   virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
67     LangOpt = LangOpts;
68     return false;
69   }
70
71   virtual bool ReadTargetTriple(llvm::StringRef Triple) {
72     TargetTriple = Triple;
73     return false;
74   }
75
76   virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
77                                     FileID PCHBufferID,
78                                     llvm::StringRef OriginalFileName,
79                                     std::string &SuggestedPredefines) {
80     Predefines = PCHPredef;
81     return false;
82   }
83
84   virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
85     HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
86   }
87
88   virtual void ReadCounter(unsigned Value) {
89     Counter = Value;
90   }
91 };
92
93 } // anonymous namespace
94
95 const std::string &ASTUnit::getOriginalSourceFileName() {
96   return OriginalSourceFile;
97 }
98
99 const std::string &ASTUnit::getPCHFileName() {
100   assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
101   return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName();
102 }
103
104 ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
105                                   Diagnostic &Diags,
106                                   bool OnlyLocalDecls,
107                                   bool UseBumpAllocator,
108                                   RemappedFile *RemappedFiles,
109                                   unsigned NumRemappedFiles) {
110   llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
111   AST->OnlyLocalDecls = OnlyLocalDecls;
112   AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
113
114   for (unsigned I = 0; I != NumRemappedFiles; ++I) {
115     // Create the file entry for the file that we're mapping from.
116     const FileEntry *FromFile
117       = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
118                                     RemappedFiles[I].second->getBufferSize(),
119                                              0);
120     if (!FromFile) {
121       Diags.Report(diag::err_fe_remap_missing_from_file)
122         << RemappedFiles[I].first;
123       continue;
124     }
125     
126     // Override the contents of the "from" file with the contents of
127     // the "to" file.
128     AST->getSourceManager().overrideFileContents(FromFile, 
129                                                  RemappedFiles[I].second);    
130   }
131   
132   // Gather Info for preprocessor construction later on.
133
134   LangOptions LangInfo;
135   HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
136   std::string TargetTriple;
137   std::string Predefines;
138   unsigned Counter;
139
140   llvm::OwningPtr<PCHReader> Reader;
141   llvm::OwningPtr<ExternalASTSource> Source;
142
143   Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
144                              Diags));
145   Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
146                                            Predefines, Counter));
147
148   switch (Reader->ReadPCH(Filename)) {
149   case PCHReader::Success:
150     break;
151
152   case PCHReader::Failure:
153   case PCHReader::IgnorePCH:
154     Diags.Report(diag::err_fe_unable_to_load_pch);
155     return NULL;
156   }
157
158   AST->OriginalSourceFile = Reader->getOriginalSourceFile();
159
160   // PCH loaded successfully. Now create the preprocessor.
161
162   // Get information about the target being compiled for.
163   //
164   // FIXME: This is broken, we should store the TargetOptions in the PCH.
165   TargetOptions TargetOpts;
166   TargetOpts.ABI = "";
167   TargetOpts.CPU = "";
168   TargetOpts.Features.clear();
169   TargetOpts.Triple = TargetTriple;
170   AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
171   AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
172                                  AST->getSourceManager(), HeaderInfo));
173   Preprocessor &PP = *AST->PP.get();
174
175   PP.setPredefines(Reader->getSuggestedPredefines());
176   PP.setCounterValue(Counter);
177   Reader->setPreprocessor(PP);
178
179   // Create and initialize the ASTContext.
180
181   AST->Ctx.reset(new ASTContext(LangInfo,
182                                 AST->getSourceManager(),
183                                 *AST->Target.get(),
184                                 PP.getIdentifierTable(),
185                                 PP.getSelectorTable(),
186                                 PP.getBuiltinInfo(),
187                                 /* FreeMemory = */ !UseBumpAllocator,
188                                 /* size_reserve = */0));
189   ASTContext &Context = *AST->Ctx.get();
190
191   Reader->InitializeContext(Context);
192
193   // Attach the PCH reader to the AST context as an external AST
194   // source, so that declarations will be deserialized from the
195   // PCH file as needed.
196   Source.reset(Reader.take());
197   Context.setExternalSource(Source);
198
199   return AST.take();
200 }
201
202 namespace {
203
204 class TopLevelDeclTrackerConsumer : public ASTConsumer {
205   ASTUnit &Unit;
206
207 public:
208   TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
209
210   void HandleTopLevelDecl(DeclGroupRef D) {
211     for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
212       Unit.getTopLevelDecls().push_back(*it);
213   }
214 };
215
216 class TopLevelDeclTrackerAction : public ASTFrontendAction {
217 public:
218   ASTUnit &Unit;
219
220   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
221                                          llvm::StringRef InFile) {
222     return new TopLevelDeclTrackerConsumer(Unit);
223   }
224
225 public:
226   TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
227
228   virtual bool hasCodeCompletionSupport() const { return false; }
229 };
230
231 }
232
233 ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
234                                              Diagnostic &Diags,
235                                              bool OnlyLocalDecls) {
236   // Create the compiler instance to use for building the AST.
237   CompilerInstance Clang;
238   llvm::OwningPtr<ASTUnit> AST;
239   llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
240
241   Clang.getInvocation() = CI;
242
243   Clang.setDiagnostics(&Diags);
244   Clang.setDiagnosticClient(Diags.getClient());
245
246   // Create the target instance.
247   Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
248                                                Clang.getTargetOpts()));
249   if (!Clang.hasTarget())
250     goto error;
251
252   // Inform the target of the language options.
253   //
254   // FIXME: We shouldn't need to do this, the target should be immutable once
255   // created. This complexity should be lifted elsewhere.
256   Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
257
258   assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
259          "Invocation must have exactly one source file!");
260   assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
261          "FIXME: AST inputs not yet supported here!");
262
263   // Create the AST unit.
264   AST.reset(new ASTUnit(false));
265
266   AST->OnlyLocalDecls = OnlyLocalDecls;
267   AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
268
269   // Create a file manager object to provide access to and cache the filesystem.
270   Clang.setFileManager(&AST->getFileManager());
271
272   // Create the source manager.
273   Clang.setSourceManager(&AST->getSourceManager());
274
275   // Create the preprocessor.
276   Clang.createPreprocessor();
277
278   Act.reset(new TopLevelDeclTrackerAction(*AST));
279   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
280                            /*IsAST=*/false))
281     goto error;
282
283   Act->Execute();
284
285   // Steal the created target, context, and preprocessor, and take back the
286   // source and file managers.
287   AST->Ctx.reset(Clang.takeASTContext());
288   AST->PP.reset(Clang.takePreprocessor());
289   Clang.takeSourceManager();
290   Clang.takeFileManager();
291   AST->Target.reset(Clang.takeTarget());
292
293   Act->EndSourceFile();
294
295   Clang.takeDiagnosticClient();
296   Clang.takeDiagnostics();
297
298   return AST.take();
299
300 error:
301   Clang.takeSourceManager();
302   Clang.takeFileManager();
303   Clang.takeDiagnosticClient();
304   Clang.takeDiagnostics();
305   return 0;
306 }
307
308 ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
309                                       const char **ArgEnd,
310                                       Diagnostic &Diags,
311                                       llvm::StringRef ResourceFilesPath,
312                                       bool OnlyLocalDecls,
313                                       bool UseBumpAllocator,
314                                       RemappedFile *RemappedFiles,
315                                       unsigned NumRemappedFiles) {
316   llvm::SmallVector<const char *, 16> Args;
317   Args.push_back("<clang>"); // FIXME: Remove dummy argument.
318   Args.insert(Args.end(), ArgBegin, ArgEnd);
319
320   // FIXME: Find a cleaner way to force the driver into restricted modes. We
321   // also want to force it to use clang.
322   Args.push_back("-fsyntax-only");
323
324   // FIXME: We shouldn't have to pass in the path info.
325   driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
326                            "a.out", false, Diags);
327   llvm::OwningPtr<driver::Compilation> C(
328     TheDriver.BuildCompilation(Args.size(), Args.data()));
329
330   // We expect to get back exactly one command job, if we didn't something
331   // failed.
332   const driver::JobList &Jobs = C->getJobs();
333   if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
334     llvm::SmallString<256> Msg;
335     llvm::raw_svector_ostream OS(Msg);
336     C->PrintJob(OS, C->getJobs(), "; ", true);
337     Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
338     return 0;
339   }
340
341   const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
342   if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
343     Diags.Report(diag::err_fe_expected_clang_command);
344     return 0;
345   }
346
347   const driver::ArgStringList &CCArgs = Cmd->getArguments();
348   CompilerInvocation CI;
349   CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(),
350                                      (const char**) CCArgs.data()+CCArgs.size(),
351                                      Diags);
352
353   // Override any files that need remapping
354   for (unsigned I = 0; I != NumRemappedFiles; ++I)
355     CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
356                                              RemappedFiles[I].second);
357   
358   // Override the resources path.
359   CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
360
361   CI.getFrontendOpts().DisableFree = UseBumpAllocator;
362   return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls);
363 }