ASTUnit.h revision 175c4a9aa61f4449f27b729737e4438684ac6d92
1//===--- ASTUnit.h - ASTUnit utility ----------------------------*- C++ -*-===//
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 utility class.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
15#define LLVM_CLANG_FRONTEND_ASTUNIT_H
16
17#include "clang/Lex/PreprocessingRecord.h"
18#include "clang/Basic/SourceManager.h"
19#include "llvm/ADT/IntrusiveRefCntPtr.h"
20#include "llvm/ADT/OwningPtr.h"
21#include "clang/Basic/FileManager.h"
22#include "clang/Index/ASTLocation.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/System/Path.h"
25#include <map>
26#include <string>
27#include <vector>
28#include <cassert>
29#include <utility>
30
31namespace llvm {
32  class MemoryBuffer;
33}
34
35namespace clang {
36class ASTContext;
37class CompilerInvocation;
38class Decl;
39class Diagnostic;
40class FileEntry;
41class FileManager;
42class HeaderSearch;
43class Preprocessor;
44class SourceManager;
45class TargetInfo;
46
47using namespace idx;
48
49/// \brief Utility class for loading a ASTContext from a PCH file.
50///
51class ASTUnit {
52public:
53  typedef std::map<FileID, std::vector<PreprocessedEntity *> >
54    PreprocessedEntitiesByFileMap;
55private:
56  llvm::IntrusiveRefCntPtr<Diagnostic> Diagnostics;
57  llvm::OwningPtr<FileManager>      FileMgr;
58  llvm::OwningPtr<SourceManager>    SourceMgr;
59  llvm::OwningPtr<HeaderSearch>     HeaderInfo;
60  llvm::OwningPtr<TargetInfo>       Target;
61  llvm::OwningPtr<Preprocessor>     PP;
62  llvm::OwningPtr<ASTContext>       Ctx;
63
64  /// Optional owned invocation, just used to make the invocation used in
65  /// LoadFromCommandLine available.
66  llvm::OwningPtr<CompilerInvocation> Invocation;
67
68  // OnlyLocalDecls - when true, walking this AST should only visit declarations
69  // that come from the AST itself, not from included precompiled headers.
70  // FIXME: This is temporary; eventually, CIndex will always do this.
71  bool                              OnlyLocalDecls;
72
73  /// \brief Whether to capture any diagnostics produced.
74  bool CaptureDiagnostics;
75
76  /// Track whether the main file was loaded from an AST or not.
77  bool MainFileIsAST;
78
79  /// Track the top-level decls which appeared in an ASTUnit which was loaded
80  /// from a source file.
81  //
82  // FIXME: This is just an optimization hack to avoid deserializing large parts
83  // of a PCH file when using the Index library on an ASTUnit loaded from
84  // source. In the long term we should make the Index library use efficient and
85  // more scalable search mechanisms.
86  std::vector<Decl*> TopLevelDecls;
87
88  /// The name of the original source file used to generate this ASTUnit.
89  std::string OriginalSourceFile;
90
91  // Critical optimization when using clang_getCursor().
92  ASTLocation LastLoc;
93
94  /// \brief The set of diagnostics produced when creating this
95  /// translation unit.
96  llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
97
98  /// \brief Temporary files that should be removed when the ASTUnit is
99  /// destroyed.
100  llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
101
102  /// \brief A mapping from file IDs to the set of preprocessed entities
103  /// stored in that file.
104  ///
105  /// FIXME: This is just an optimization hack to avoid searching through
106  /// many preprocessed entities during cursor traversal in the CIndex library.
107  /// Ideally, we would just be able to perform a binary search within the
108  /// list of preprocessed entities.
109  PreprocessedEntitiesByFileMap PreprocessedEntitiesByFile;
110
111  /// \brief Simple hack to allow us to assert that ASTUnit is not being
112  /// used concurrently, which is not supported.
113  ///
114  /// Clients should create instances of the ConcurrencyCheck class whenever
115  /// using the ASTUnit in a way that isn't intended to be concurrent, which is
116  /// just about any usage.
117  unsigned int ConcurrencyCheckValue;
118  static const unsigned int CheckLocked = 28573289;
119  static const unsigned int CheckUnlocked = 9803453;
120
121  /// \brief The file in which the precompiled preamble is stored.
122  llvm::sys::Path PreambleFile;
123
124  /// \brief The contents of the preamble that has been precompiled to
125  /// \c PreambleFile.
126  std::vector<char> Preamble;
127
128  /// \brief The size of the source buffer that we've reserved for the main
129  /// file within the precompiled preamble.
130  unsigned PreambleReservedSize;
131
132  ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT
133  ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT
134
135  explicit ASTUnit(bool MainFileIsAST);
136
137  void CleanTemporaryFiles();
138  bool Parse();
139
140  std::pair<llvm::MemoryBuffer *, unsigned> ComputePreamble(
141                                                CompilerInvocation &Invocation,
142                                                          bool &CreatedBuffer);
143
144  std::pair<llvm::MemoryBuffer *, bool> BuildPrecompiledPreamble();
145
146public:
147  class ConcurrencyCheck {
148    volatile ASTUnit &Self;
149
150  public:
151    explicit ConcurrencyCheck(ASTUnit &Self)
152      : Self(Self)
153    {
154      assert(Self.ConcurrencyCheckValue == CheckUnlocked &&
155             "Concurrent access to ASTUnit!");
156      Self.ConcurrencyCheckValue = CheckLocked;
157    }
158
159    ~ConcurrencyCheck() {
160      Self.ConcurrencyCheckValue = CheckUnlocked;
161    }
162  };
163  friend class ConcurrencyCheck;
164
165  ~ASTUnit();
166
167  bool isMainFileAST() const { return MainFileIsAST; }
168
169  const Diagnostic &getDiagnostics() const { return *Diagnostics; }
170  Diagnostic &getDiagnostics()             { return *Diagnostics; }
171
172  const SourceManager &getSourceManager() const { return *SourceMgr; }
173        SourceManager &getSourceManager()       { return *SourceMgr; }
174
175  const Preprocessor &getPreprocessor() const { return *PP.get(); }
176        Preprocessor &getPreprocessor()       { return *PP.get(); }
177
178  const ASTContext &getASTContext() const { return *Ctx.get(); }
179        ASTContext &getASTContext()       { return *Ctx.get(); }
180
181  const FileManager &getFileManager() const { return *FileMgr; }
182        FileManager &getFileManager()       { return *FileMgr; }
183
184  const std::string &getOriginalSourceFileName();
185  const std::string &getPCHFileName();
186
187  /// \brief Add a temporary file that the ASTUnit depends on.
188  ///
189  /// This file will be erased when the ASTUnit is destroyed.
190  void addTemporaryFile(const llvm::sys::Path &TempFile) {
191    TemporaryFiles.push_back(TempFile);
192  }
193
194  bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
195
196  void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; }
197  ASTLocation getLastASTLocation() const { return LastLoc; }
198
199  std::vector<Decl*> &getTopLevelDecls() {
200    assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
201    return TopLevelDecls;
202  }
203  const std::vector<Decl*> &getTopLevelDecls() const {
204    assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
205    return TopLevelDecls;
206  }
207
208  /// \brief Retrieve the mapping from File IDs to the preprocessed entities
209  /// within that file.
210  PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() {
211    return PreprocessedEntitiesByFile;
212  }
213
214  // Retrieve the diagnostics associated with this AST
215  typedef const StoredDiagnostic *stored_diag_iterator;
216  stored_diag_iterator stored_diag_begin() const {
217    return StoredDiagnostics.begin();
218  }
219  stored_diag_iterator stored_diag_end() const {
220    return StoredDiagnostics.end();
221  }
222  unsigned stored_diag_size() const { return StoredDiagnostics.size(); }
223
224  llvm::SmallVector<StoredDiagnostic, 4> &getStoredDiagnostics() {
225    return StoredDiagnostics;
226  }
227
228  /// \brief A mapping from a file name to the memory buffer that stores the
229  /// remapped contents of that file.
230  typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile;
231
232  /// \brief Create a ASTUnit from a PCH file.
233  ///
234  /// \param Filename - The PCH file to load.
235  ///
236  /// \param Diags - The diagnostics engine to use for reporting errors; its
237  /// lifetime is expected to extend past that of the returned ASTUnit.
238  ///
239  /// \returns - The initialized ASTUnit or null if the PCH failed to load.
240  static ASTUnit *LoadFromPCHFile(const std::string &Filename,
241                                  llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
242                                  bool OnlyLocalDecls = false,
243                                  RemappedFile *RemappedFiles = 0,
244                                  unsigned NumRemappedFiles = 0,
245                                  bool CaptureDiagnostics = false);
246
247  /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a
248  /// CompilerInvocation object.
249  ///
250  /// \param CI - The compiler invocation to use; it must have exactly one input
251  /// source file. The ASTUnit takes ownership of the CompilerInvocation object.
252  ///
253  /// \param Diags - The diagnostics engine to use for reporting errors; its
254  /// lifetime is expected to extend past that of the returned ASTUnit.
255  //
256  // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
257  // shouldn't need to specify them at construction time.
258  static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
259                                     llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
260                                             bool OnlyLocalDecls = false,
261                                             bool CaptureDiagnostics = false,
262                                             bool PrecompilePreamble = false);
263
264  /// LoadFromCommandLine - Create an ASTUnit from a vector of command line
265  /// arguments, which must specify exactly one source file.
266  ///
267  /// \param ArgBegin - The beginning of the argument vector.
268  ///
269  /// \param ArgEnd - The end of the argument vector.
270  ///
271  /// \param Diags - The diagnostics engine to use for reporting errors; its
272  /// lifetime is expected to extend past that of the returned ASTUnit.
273  ///
274  /// \param ResourceFilesPath - The path to the compiler resource files.
275  //
276  // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
277  // shouldn't need to specify them at construction time.
278  static ASTUnit *LoadFromCommandLine(const char **ArgBegin,
279                                      const char **ArgEnd,
280                                    llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
281                                      llvm::StringRef ResourceFilesPath,
282                                      bool OnlyLocalDecls = false,
283                                      RemappedFile *RemappedFiles = 0,
284                                      unsigned NumRemappedFiles = 0,
285                                      bool CaptureDiagnostics = false,
286                                      bool PrecompilePreamble = false);
287
288  /// \brief Reparse the source files using the same command-line options that
289  /// were originally used to produce this translation unit.
290  ///
291  /// \returns True if a failure occurred that causes the ASTUnit not to
292  /// contain any translation-unit information, false otherwise.
293  bool Reparse(RemappedFile *RemappedFiles = 0,
294               unsigned NumRemappedFiles = 0);
295};
296
297} // namespace clang
298
299#endif
300