ASTUnit.cpp revision 4ae8f6b1ae99f3c56057508e840a8d00dcc0e755
1d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===//
2d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//
3d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//                     The LLVM Compiler Infrastructure
4d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//
5d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// This file is distributed under the University of Illinois Open Source
6d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// License. See LICENSE.TXT for details.
7d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//
8d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//===----------------------------------------------------------------------===//
9d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//
10d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa// ASTUnit Implementation.
11d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//
12d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa//===----------------------------------------------------------------------===//
13d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa
14d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/ASTUnit.h"
15d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/PCHReader.h"
16d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/ASTContext.h"
17d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/ASTConsumer.h"
18d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/DeclVisitor.h"
19d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/AST/StmtVisitor.h"
20d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Compilation.h"
21d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Driver.h"
22d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Job.h"
23d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Driver/Tool.h"
248481d64e329bf5f70886add36165bc4b0459bd13Adrian Roos#include "clang/Frontend/CompilerInstance.h"
25d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/FrontendActions.h"
26d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#include "clang/Frontend/FrontendDiagnostic.h"
27771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Frontend/FrontendOptions.h"
28771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Lex/HeaderSearch.h"
29771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Lex/Preprocessor.h"
30771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Basic/TargetOptions.h"
31771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Basic/TargetInfo.h"
32771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "clang/Basic/Diagnostic.h"
33771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "llvm/Support/MemoryBuffer.h"
34771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "llvm/System/Host.h"
35771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#include "llvm/System/Path.h"
36771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lamusing namespace clang;
37771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam
38771fac591f6e00221713e6eb763148e3d191d7c2Maurice LamASTUnit::ASTUnit(bool _MainFileIsAST)
39771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam  : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) {
40771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam}
41771fac591f6e00221713e6eb763148e3d191d7c2Maurice LamASTUnit::~ASTUnit() {
42771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam#ifdef _DEBUG
43d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  ConcurrencyCheckValue = CheckLocked;
44d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa#endif
45d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
46771fac591f6e00221713e6eb763148e3d191d7c2Maurice Lam    TemporaryFiles[I].eraseFromDisk();
47d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa}
482662df843327dd938225c75722d0bbf3b01068f7Maurice Lam
492662df843327dd938225c75722d0bbf3b01068f7Maurice Lamnamespace {
50d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa
51d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa/// \brief Gathers information from PCHReader that will be used to initialize
52d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa/// a Preprocessor.
53d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawaclass PCHInfoCollector : public PCHReaderListener {
54d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  LangOptions &LangOpt;
55d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  HeaderSearch &HSI;
56d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  std::string &TargetTriple;
57d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  std::string &Predefines;
58d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa  unsigned &Counter;
59d36699282cbd0a6897f425106081d3f2c0db55d4Daisuke Miyakawa
60  unsigned NumHeaderInfos;
61
62public:
63  PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
64                   std::string &TargetTriple, std::string &Predefines,
65                   unsigned &Counter)
66    : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
67      Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
68
69  virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
70    LangOpt = LangOpts;
71    return false;
72  }
73
74  virtual bool ReadTargetTriple(llvm::StringRef Triple) {
75    TargetTriple = Triple;
76    return false;
77  }
78
79  virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
80                                    FileID PCHBufferID,
81                                    llvm::StringRef OriginalFileName,
82                                    std::string &SuggestedPredefines) {
83    Predefines = PCHPredef;
84    return false;
85  }
86
87  virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
88    HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
89  }
90
91  virtual void ReadCounter(unsigned Value) {
92    Counter = Value;
93  }
94};
95
96class StoredDiagnosticClient : public DiagnosticClient {
97  llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
98
99public:
100  explicit StoredDiagnosticClient(
101                          llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
102    : StoredDiags(StoredDiags) { }
103
104  virtual void HandleDiagnostic(Diagnostic::Level Level,
105                                const DiagnosticInfo &Info);
106};
107
108/// \brief RAII object that optionally captures diagnostics, if
109/// there is no diagnostic client to capture them already.
110class CaptureDroppedDiagnostics {
111  Diagnostic &Diags;
112  StoredDiagnosticClient Client;
113  DiagnosticClient *PreviousClient;
114
115public:
116  CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
117                           llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
118    : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient())
119  {
120    if (RequestCapture || Diags.getClient() == 0)
121      Diags.setClient(&Client);
122  }
123
124  ~CaptureDroppedDiagnostics() {
125    Diags.setClient(PreviousClient);
126  }
127};
128
129} // anonymous namespace
130
131void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
132                                              const DiagnosticInfo &Info) {
133  StoredDiags.push_back(StoredDiagnostic(Level, Info));
134}
135
136const std::string &ASTUnit::getOriginalSourceFileName() {
137  return OriginalSourceFile;
138}
139
140const std::string &ASTUnit::getPCHFileName() {
141  assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
142  return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
143}
144
145ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
146                                  Diagnostic &Diags,
147                                  bool OnlyLocalDecls,
148                                  RemappedFile *RemappedFiles,
149                                  unsigned NumRemappedFiles,
150                                  bool CaptureDiagnostics) {
151  llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
152  AST->OnlyLocalDecls = OnlyLocalDecls;
153  AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
154
155  // If requested, capture diagnostics in the ASTUnit.
156  CaptureDroppedDiagnostics Capture(CaptureDiagnostics, Diags,
157                                    AST->Diagnostics);
158
159  for (unsigned I = 0; I != NumRemappedFiles; ++I) {
160    // Create the file entry for the file that we're mapping from.
161    const FileEntry *FromFile
162      = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
163                                    RemappedFiles[I].second->getBufferSize(),
164                                             0);
165    if (!FromFile) {
166      Diags.Report(diag::err_fe_remap_missing_from_file)
167        << RemappedFiles[I].first;
168      delete RemappedFiles[I].second;
169      continue;
170    }
171
172    // Override the contents of the "from" file with the contents of
173    // the "to" file.
174    AST->getSourceManager().overrideFileContents(FromFile,
175                                                 RemappedFiles[I].second);
176  }
177
178  // Gather Info for preprocessor construction later on.
179
180  LangOptions LangInfo;
181  HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
182  std::string TargetTriple;
183  std::string Predefines;
184  unsigned Counter;
185
186  llvm::OwningPtr<PCHReader> Reader;
187  llvm::OwningPtr<ExternalASTSource> Source;
188
189  Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
190                             Diags));
191  Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
192                                           Predefines, Counter));
193
194  switch (Reader->ReadPCH(Filename)) {
195  case PCHReader::Success:
196    break;
197
198  case PCHReader::Failure:
199  case PCHReader::IgnorePCH:
200    Diags.Report(diag::err_fe_unable_to_load_pch);
201    return NULL;
202  }
203
204  AST->OriginalSourceFile = Reader->getOriginalSourceFile();
205
206  // PCH loaded successfully. Now create the preprocessor.
207
208  // Get information about the target being compiled for.
209  //
210  // FIXME: This is broken, we should store the TargetOptions in the PCH.
211  TargetOptions TargetOpts;
212  TargetOpts.ABI = "";
213  TargetOpts.CPU = "";
214  TargetOpts.Features.clear();
215  TargetOpts.Triple = TargetTriple;
216  AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
217  AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
218                                 AST->getSourceManager(), HeaderInfo));
219  Preprocessor &PP = *AST->PP.get();
220
221  PP.setPredefines(Reader->getSuggestedPredefines());
222  PP.setCounterValue(Counter);
223  Reader->setPreprocessor(PP);
224
225  // Create and initialize the ASTContext.
226
227  AST->Ctx.reset(new ASTContext(LangInfo,
228                                AST->getSourceManager(),
229                                *AST->Target.get(),
230                                PP.getIdentifierTable(),
231                                PP.getSelectorTable(),
232                                PP.getBuiltinInfo(),
233                                /* FreeMemory = */ false,
234                                /* size_reserve = */0));
235  ASTContext &Context = *AST->Ctx.get();
236
237  Reader->InitializeContext(Context);
238
239  // Attach the PCH reader to the AST context as an external AST
240  // source, so that declarations will be deserialized from the
241  // PCH file as needed.
242  Source.reset(Reader.take());
243  Context.setExternalSource(Source);
244
245  return AST.take();
246}
247
248namespace {
249
250class TopLevelDeclTrackerConsumer : public ASTConsumer {
251  ASTUnit &Unit;
252
253public:
254  TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
255
256  void HandleTopLevelDecl(DeclGroupRef D) {
257    for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
258      Unit.getTopLevelDecls().push_back(*it);
259  }
260};
261
262class TopLevelDeclTrackerAction : public ASTFrontendAction {
263public:
264  ASTUnit &Unit;
265
266  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
267                                         llvm::StringRef InFile) {
268    return new TopLevelDeclTrackerConsumer(Unit);
269  }
270
271public:
272  TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
273
274  virtual bool hasCodeCompletionSupport() const { return false; }
275};
276
277}
278
279ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
280                                             Diagnostic &Diags,
281                                             bool OnlyLocalDecls,
282                                             bool CaptureDiagnostics) {
283  // Create the compiler instance to use for building the AST.
284  CompilerInstance Clang;
285  llvm::OwningPtr<ASTUnit> AST;
286  llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
287
288  Clang.setInvocation(CI);
289
290  Clang.setDiagnostics(&Diags);
291  Clang.setDiagnosticClient(Diags.getClient());
292
293  // Create the target instance.
294  Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
295                                               Clang.getTargetOpts()));
296  if (!Clang.hasTarget()) {
297    Clang.takeSourceManager();
298    Clang.takeFileManager();
299    Clang.takeDiagnosticClient();
300    Clang.takeDiagnostics();
301    return 0;
302  }
303
304  // Inform the target of the language options.
305  //
306  // FIXME: We shouldn't need to do this, the target should be immutable once
307  // created. This complexity should be lifted elsewhere.
308  Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
309
310  assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
311         "Invocation must have exactly one source file!");
312  assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
313         "FIXME: AST inputs not yet supported here!");
314
315  // Create the AST unit.
316  AST.reset(new ASTUnit(false));
317  AST->OnlyLocalDecls = OnlyLocalDecls;
318  AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
319
320  // Capture any diagnostics that would otherwise be dropped.
321  CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
322                                    Clang.getDiagnostics(),
323                                    AST->Diagnostics);
324
325  // Create a file manager object to provide access to and cache the filesystem.
326  Clang.setFileManager(&AST->getFileManager());
327
328  // Create the source manager.
329  Clang.setSourceManager(&AST->getSourceManager());
330
331  // Create the preprocessor.
332  Clang.createPreprocessor();
333
334  Act.reset(new TopLevelDeclTrackerAction(*AST));
335  if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
336                           /*IsAST=*/false))
337    goto error;
338
339  Act->Execute();
340
341  // Steal the created target, context, and preprocessor, and take back the
342  // source and file managers.
343  AST->Ctx.reset(Clang.takeASTContext());
344  AST->PP.reset(Clang.takePreprocessor());
345  Clang.takeSourceManager();
346  Clang.takeFileManager();
347  AST->Target.reset(Clang.takeTarget());
348
349  Act->EndSourceFile();
350
351  Clang.takeDiagnosticClient();
352  Clang.takeDiagnostics();
353  Clang.takeInvocation();
354
355  AST->Invocation.reset(Clang.takeInvocation());
356  return AST.take();
357
358error:
359  Clang.takeSourceManager();
360  Clang.takeFileManager();
361  Clang.takeDiagnosticClient();
362  Clang.takeDiagnostics();
363  return 0;
364}
365
366ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
367                                      const char **ArgEnd,
368                                      Diagnostic &Diags,
369                                      llvm::StringRef ResourceFilesPath,
370                                      bool OnlyLocalDecls,
371                                      RemappedFile *RemappedFiles,
372                                      unsigned NumRemappedFiles,
373                                      bool CaptureDiagnostics) {
374  llvm::SmallVector<const char *, 16> Args;
375  Args.push_back("<clang>"); // FIXME: Remove dummy argument.
376  Args.insert(Args.end(), ArgBegin, ArgEnd);
377
378  // FIXME: Find a cleaner way to force the driver into restricted modes. We
379  // also want to force it to use clang.
380  Args.push_back("-fsyntax-only");
381
382  // FIXME: We shouldn't have to pass in the path info.
383  driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
384                           "a.out", false, Diags);
385
386  // Don't check that inputs exist, they have been remapped.
387  TheDriver.setCheckInputsExist(false);
388
389  llvm::OwningPtr<driver::Compilation> C(
390    TheDriver.BuildCompilation(Args.size(), Args.data()));
391
392  // We expect to get back exactly one command job, if we didn't something
393  // failed.
394  const driver::JobList &Jobs = C->getJobs();
395  if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
396    llvm::SmallString<256> Msg;
397    llvm::raw_svector_ostream OS(Msg);
398    C->PrintJob(OS, C->getJobs(), "; ", true);
399    Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
400    return 0;
401  }
402
403  const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
404  if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
405    Diags.Report(diag::err_fe_expected_clang_command);
406    return 0;
407  }
408
409  const driver::ArgStringList &CCArgs = Cmd->getArguments();
410  llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
411  CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
412                                     (const char**) CCArgs.data()+CCArgs.size(),
413                                     Diags);
414
415  // Override any files that need remapping
416  for (unsigned I = 0; I != NumRemappedFiles; ++I)
417    CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
418                                              RemappedFiles[I].second);
419
420  // Override the resources path.
421  CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
422
423  CI->getFrontendOpts().DisableFree = true;
424  return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
425                                    CaptureDiagnostics);
426}
427