]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Frontend/ASTUnit.cpp
Update clang to r96341.
[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 static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
102 }
103
104 ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
105                                   Diagnostic &Diags,
106                                   bool OnlyLocalDecls,
107                                   RemappedFile *RemappedFiles,
108                                   unsigned NumRemappedFiles) {
109   llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
110   AST->OnlyLocalDecls = OnlyLocalDecls;
111   AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
112
113   for (unsigned I = 0; I != NumRemappedFiles; ++I) {
114     // Create the file entry for the file that we're mapping from.
115     const FileEntry *FromFile
116       = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
117                                     RemappedFiles[I].second->getBufferSize(),
118                                              0);
119     if (!FromFile) {
120       Diags.Report(diag::err_fe_remap_missing_from_file)
121         << RemappedFiles[I].first;
122       continue;
123     }
124     
125     // Override the contents of the "from" file with the contents of
126     // the "to" file.
127     AST->getSourceManager().overrideFileContents(FromFile, 
128                                                  RemappedFiles[I].second);    
129   }
130   
131   // Gather Info for preprocessor construction later on.
132
133   LangOptions LangInfo;
134   HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
135   std::string TargetTriple;
136   std::string Predefines;
137   unsigned Counter;
138
139   llvm::OwningPtr<PCHReader> Reader;
140   llvm::OwningPtr<ExternalASTSource> Source;
141
142   Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
143                              Diags));
144   Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
145                                            Predefines, Counter));
146
147   switch (Reader->ReadPCH(Filename)) {
148   case PCHReader::Success:
149     break;
150
151   case PCHReader::Failure:
152   case PCHReader::IgnorePCH:
153     Diags.Report(diag::err_fe_unable_to_load_pch);
154     return NULL;
155   }
156
157   AST->OriginalSourceFile = Reader->getOriginalSourceFile();
158
159   // PCH loaded successfully. Now create the preprocessor.
160
161   // Get information about the target being compiled for.
162   //
163   // FIXME: This is broken, we should store the TargetOptions in the PCH.
164   TargetOptions TargetOpts;
165   TargetOpts.ABI = "";
166   TargetOpts.CPU = "";
167   TargetOpts.Features.clear();
168   TargetOpts.Triple = TargetTriple;
169   AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
170   AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
171                                  AST->getSourceManager(), HeaderInfo));
172   Preprocessor &PP = *AST->PP.get();
173
174   PP.setPredefines(Reader->getSuggestedPredefines());
175   PP.setCounterValue(Counter);
176   Reader->setPreprocessor(PP);
177
178   // Create and initialize the ASTContext.
179
180   AST->Ctx.reset(new ASTContext(LangInfo,
181                                 AST->getSourceManager(),
182                                 *AST->Target.get(),
183                                 PP.getIdentifierTable(),
184                                 PP.getSelectorTable(),
185                                 PP.getBuiltinInfo(),
186                                 /* FreeMemory = */ false,
187                                 /* size_reserve = */0));
188   ASTContext &Context = *AST->Ctx.get();
189
190   Reader->InitializeContext(Context);
191
192   // Attach the PCH reader to the AST context as an external AST
193   // source, so that declarations will be deserialized from the
194   // PCH file as needed.
195   Source.reset(Reader.take());
196   Context.setExternalSource(Source);
197
198   return AST.take();
199 }
200
201 namespace {
202
203 class TopLevelDeclTrackerConsumer : public ASTConsumer {
204   ASTUnit &Unit;
205
206 public:
207   TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
208
209   void HandleTopLevelDecl(DeclGroupRef D) {
210     for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
211       Unit.getTopLevelDecls().push_back(*it);
212   }
213 };
214
215 class TopLevelDeclTrackerAction : public ASTFrontendAction {
216 public:
217   ASTUnit &Unit;
218
219   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
220                                          llvm::StringRef InFile) {
221     return new TopLevelDeclTrackerConsumer(Unit);
222   }
223
224 public:
225   TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
226
227   virtual bool hasCodeCompletionSupport() const { return false; }
228 };
229
230 }
231
232 ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
233                                              Diagnostic &Diags,
234                                              bool OnlyLocalDecls) {
235   // Create the compiler instance to use for building the AST.
236   CompilerInstance Clang;
237   llvm::OwningPtr<ASTUnit> AST;
238   llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
239
240   Clang.setInvocation(CI);
241
242   Clang.setDiagnostics(&Diags);
243   Clang.setDiagnosticClient(Diags.getClient());
244
245   // Create the target instance.
246   Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
247                                                Clang.getTargetOpts()));
248   if (!Clang.hasTarget())
249     goto error;
250
251   // Inform the target of the language options.
252   //
253   // FIXME: We shouldn't need to do this, the target should be immutable once
254   // created. This complexity should be lifted elsewhere.
255   Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
256
257   assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
258          "Invocation must have exactly one source file!");
259   assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
260          "FIXME: AST inputs not yet supported here!");
261
262   // Create the AST unit.
263   AST.reset(new ASTUnit(false));
264
265   AST->OnlyLocalDecls = OnlyLocalDecls;
266   AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
267
268   // Create a file manager object to provide access to and cache the filesystem.
269   Clang.setFileManager(&AST->getFileManager());
270
271   // Create the source manager.
272   Clang.setSourceManager(&AST->getSourceManager());
273
274   // Create the preprocessor.
275   Clang.createPreprocessor();
276
277   Act.reset(new TopLevelDeclTrackerAction(*AST));
278   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
279                            /*IsAST=*/false))
280     goto error;
281
282   Act->Execute();
283
284   // Steal the created target, context, and preprocessor, and take back the
285   // source and file managers.
286   AST->Ctx.reset(Clang.takeASTContext());
287   AST->PP.reset(Clang.takePreprocessor());
288   Clang.takeSourceManager();
289   Clang.takeFileManager();
290   AST->Target.reset(Clang.takeTarget());
291
292   Act->EndSourceFile();
293
294   Clang.takeDiagnosticClient();
295   Clang.takeDiagnostics();
296   Clang.takeInvocation();
297
298   AST->Invocation.reset(Clang.takeInvocation());
299   return AST.take();
300
301 error:
302   Clang.takeSourceManager();
303   Clang.takeFileManager();
304   Clang.takeDiagnosticClient();
305   Clang.takeDiagnostics();
306   return 0;
307 }
308
309 ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
310                                       const char **ArgEnd,
311                                       Diagnostic &Diags,
312                                       llvm::StringRef ResourceFilesPath,
313                                       bool OnlyLocalDecls,
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
328   // Don't check that inputs exist, they have been remapped.
329   TheDriver.setCheckInputsExist(false);
330
331   llvm::OwningPtr<driver::Compilation> C(
332     TheDriver.BuildCompilation(Args.size(), Args.data()));
333
334   // We expect to get back exactly one command job, if we didn't something
335   // failed.
336   const driver::JobList &Jobs = C->getJobs();
337   if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
338     llvm::SmallString<256> Msg;
339     llvm::raw_svector_ostream OS(Msg);
340     C->PrintJob(OS, C->getJobs(), "; ", true);
341     Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
342     return 0;
343   }
344
345   const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
346   if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
347     Diags.Report(diag::err_fe_expected_clang_command);
348     return 0;
349   }
350
351   const driver::ArgStringList &CCArgs = Cmd->getArguments();
352   llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
353   CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
354                                      (const char**) CCArgs.data()+CCArgs.size(),
355                                      Diags);
356
357   // Override any files that need remapping
358   for (unsigned I = 0; I != NumRemappedFiles; ++I)
359     CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
360                                               RemappedFiles[I].second);
361   
362   // Override the resources path.
363   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
364
365   CI->getFrontendOpts().DisableFree = true;
366   return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls);
367 }