ASTUnit.h revision eb8837b88c18631c69ac75f64ab1853762063180
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/Index/ASTLocation.h" 18#include "clang/Frontend/PCHBitCodes.h" 19#include "clang/Lex/PreprocessingRecord.h" 20#include "clang/Basic/SourceManager.h" 21#include "clang/Basic/FileManager.h" 22#include "llvm/ADT/IntrusiveRefCntPtr.h" 23#include "llvm/ADT/OwningPtr.h" 24#include "llvm/ADT/SmallVector.h" 25#include "llvm/ADT/StringMap.h" 26#include "llvm/System/Path.h" 27#include "llvm/Support/Timer.h" 28#include <map> 29#include <string> 30#include <vector> 31#include <cassert> 32#include <utility> 33#include <sys/types.h> 34 35namespace llvm { 36 class MemoryBuffer; 37} 38 39namespace clang { 40class ASTContext; 41class CompilerInvocation; 42class Decl; 43class Diagnostic; 44class FileEntry; 45class FileManager; 46class HeaderSearch; 47class Preprocessor; 48class SourceManager; 49class TargetInfo; 50 51using namespace idx; 52 53/// \brief Utility class for loading a ASTContext from a PCH file. 54/// 55class ASTUnit { 56public: 57 typedef std::map<FileID, std::vector<PreprocessedEntity *> > 58 PreprocessedEntitiesByFileMap; 59private: 60 llvm::IntrusiveRefCntPtr<Diagnostic> Diagnostics; 61 llvm::OwningPtr<FileManager> FileMgr; 62 llvm::OwningPtr<SourceManager> SourceMgr; 63 llvm::OwningPtr<HeaderSearch> HeaderInfo; 64 llvm::OwningPtr<TargetInfo> Target; 65 llvm::OwningPtr<Preprocessor> PP; 66 llvm::OwningPtr<ASTContext> Ctx; 67 68 /// Optional owned invocation, just used to make the invocation used in 69 /// LoadFromCommandLine available. 70 llvm::OwningPtr<CompilerInvocation> Invocation; 71 72 // OnlyLocalDecls - when true, walking this AST should only visit declarations 73 // that come from the AST itself, not from included precompiled headers. 74 // FIXME: This is temporary; eventually, CIndex will always do this. 75 bool OnlyLocalDecls; 76 77 /// \brief Whether to capture any diagnostics produced. 78 bool CaptureDiagnostics; 79 80 /// Track whether the main file was loaded from an AST or not. 81 bool MainFileIsAST; 82 83 /// Track the top-level decls which appeared in an ASTUnit which was loaded 84 /// from a source file. 85 // 86 // FIXME: This is just an optimization hack to avoid deserializing large parts 87 // of a PCH file when using the Index library on an ASTUnit loaded from 88 // source. In the long term we should make the Index library use efficient and 89 // more scalable search mechanisms. 90 std::vector<Decl*> TopLevelDecls; 91 92 /// The name of the original source file used to generate this ASTUnit. 93 std::string OriginalSourceFile; 94 95 // Critical optimization when using clang_getCursor(). 96 ASTLocation LastLoc; 97 98 /// \brief The set of diagnostics produced when creating this 99 /// translation unit. 100 llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics; 101 102 /// \brief Temporary files that should be removed when the ASTUnit is 103 /// destroyed. 104 llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles; 105 106 /// \brief A mapping from file IDs to the set of preprocessed entities 107 /// stored in that file. 108 /// 109 /// FIXME: This is just an optimization hack to avoid searching through 110 /// many preprocessed entities during cursor traversal in the CIndex library. 111 /// Ideally, we would just be able to perform a binary search within the 112 /// list of preprocessed entities. 113 PreprocessedEntitiesByFileMap PreprocessedEntitiesByFile; 114 115 /// \brief Simple hack to allow us to assert that ASTUnit is not being 116 /// used concurrently, which is not supported. 117 /// 118 /// Clients should create instances of the ConcurrencyCheck class whenever 119 /// using the ASTUnit in a way that isn't intended to be concurrent, which is 120 /// just about any usage. 121 unsigned int ConcurrencyCheckValue; 122 static const unsigned int CheckLocked = 28573289; 123 static const unsigned int CheckUnlocked = 9803453; 124 125 /// \brief The file in which the precompiled preamble is stored. 126 std::string PreambleFile; 127 128 /// \brief The contents of the preamble that has been precompiled to 129 /// \c PreambleFile. 130 std::vector<char> Preamble; 131 132 /// \brief Whether the preamble ends at the start of a new line. 133 /// 134 /// Used to inform the lexer as to whether it's starting at the beginning of 135 /// a line after skipping the preamble. 136 bool PreambleEndsAtStartOfLine; 137 138 /// \brief The size of the source buffer that we've reserved for the main 139 /// file within the precompiled preamble. 140 unsigned PreambleReservedSize; 141 142 /// \brief Keeps track of the files that were used when computing the 143 /// preamble, with both their buffer size and their modification time. 144 /// 145 /// If any of the files have changed from one compile to the next, 146 /// the preamble must be thrown away. 147 llvm::StringMap<std::pair<off_t, time_t> > FilesInPreamble; 148 149 /// \brief When non-NULL, this is the buffer used to store the contents of 150 /// the main file when it has been padded for use with the precompiled 151 /// preamble. 152 llvm::MemoryBuffer *SavedMainFileBuffer; 153 154 /// \brief The number of warnings that occurred while parsing the preamble. 155 /// 156 /// This value will be used to restore the state of the \c Diagnostic object 157 /// when re-using the precompiled preamble. Note that only the 158 /// number of warnings matters, since we will not save the preamble 159 /// when any errors are present. 160 unsigned NumWarningsInPreamble; 161 162 /// \brief The number of diagnostics that were stored when parsing 163 /// the precompiled preamble. 164 /// 165 /// This value is used to determine how many of the stored 166 /// diagnostics should be retained when reparsing in the presence of 167 /// a precompiled preamble. 168 unsigned NumStoredDiagnosticsInPreamble; 169 170 /// \brief The group of timers associated with this translation unit. 171 llvm::OwningPtr<llvm::TimerGroup> TimerGroup; 172 173 /// \brief A list of the PCH ID numbers for each of the top-level 174 /// declarations parsed within the precompiled preamble. 175 std::vector<pch::DeclID> TopLevelDeclsInPreamble; 176 177 /// \brief The timers we've created from the various parses, reparses, etc. 178 /// involved in this translation unit. 179 std::vector<llvm::Timer *> Timers; 180 181 ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT 182 ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT 183 184 explicit ASTUnit(bool MainFileIsAST); 185 186 void CleanTemporaryFiles(); 187 bool Parse(llvm::MemoryBuffer *OverrideMainBuffer); 188 189 std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > 190 ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer); 191 192 llvm::MemoryBuffer *BuildPrecompiledPreamble(); 193 void RealizeTopLevelDeclsFromPreamble(); 194 195public: 196 class ConcurrencyCheck { 197 volatile ASTUnit &Self; 198 199 public: 200 explicit ConcurrencyCheck(ASTUnit &Self) 201 : Self(Self) 202 { 203 assert(Self.ConcurrencyCheckValue == CheckUnlocked && 204 "Concurrent access to ASTUnit!"); 205 Self.ConcurrencyCheckValue = CheckLocked; 206 } 207 208 ~ConcurrencyCheck() { 209 Self.ConcurrencyCheckValue = CheckUnlocked; 210 } 211 }; 212 friend class ConcurrencyCheck; 213 214 ~ASTUnit(); 215 216 bool isMainFileAST() const { return MainFileIsAST; } 217 218 const Diagnostic &getDiagnostics() const { return *Diagnostics; } 219 Diagnostic &getDiagnostics() { return *Diagnostics; } 220 221 const SourceManager &getSourceManager() const { return *SourceMgr; } 222 SourceManager &getSourceManager() { return *SourceMgr; } 223 224 const Preprocessor &getPreprocessor() const { return *PP.get(); } 225 Preprocessor &getPreprocessor() { return *PP.get(); } 226 227 const ASTContext &getASTContext() const { return *Ctx.get(); } 228 ASTContext &getASTContext() { return *Ctx.get(); } 229 230 const FileManager &getFileManager() const { return *FileMgr; } 231 FileManager &getFileManager() { return *FileMgr; } 232 233 const std::string &getOriginalSourceFileName(); 234 const std::string &getPCHFileName(); 235 236 /// \brief Add a temporary file that the ASTUnit depends on. 237 /// 238 /// This file will be erased when the ASTUnit is destroyed. 239 void addTemporaryFile(const llvm::sys::Path &TempFile) { 240 TemporaryFiles.push_back(TempFile); 241 } 242 243 bool getOnlyLocalDecls() const { return OnlyLocalDecls; } 244 245 /// \brief Retrieve the maximum PCH level of declarations that a 246 /// traversal of the translation unit should consider. 247 unsigned getMaxPCHLevel() const; 248 249 void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; } 250 ASTLocation getLastASTLocation() const { return LastLoc; } 251 252 typedef std::vector<Decl *>::iterator top_level_iterator; 253 254 top_level_iterator top_level_begin() { 255 assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); 256 if (!TopLevelDeclsInPreamble.empty()) 257 RealizeTopLevelDeclsFromPreamble(); 258 return TopLevelDecls.begin(); 259 } 260 261 top_level_iterator top_level_end() { 262 assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); 263 if (!TopLevelDeclsInPreamble.empty()) 264 RealizeTopLevelDeclsFromPreamble(); 265 return TopLevelDecls.end(); 266 } 267 268 std::size_t top_level_size() const { 269 assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); 270 return TopLevelDeclsInPreamble.size() + TopLevelDecls.size(); 271 } 272 273 bool top_level_empty() const { 274 assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); 275 return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty(); 276 } 277 278 /// \brief Add a new top-level declaration. 279 void addTopLevelDecl(Decl *D) { 280 TopLevelDecls.push_back(D); 281 } 282 283 /// \brief Add a new top-level declaration, identified by its ID in 284 /// the precompiled preamble. 285 void addTopLevelDeclFromPreamble(pch::DeclID D) { 286 TopLevelDeclsInPreamble.push_back(D); 287 } 288 289 /// \brief Retrieve the mapping from File IDs to the preprocessed entities 290 /// within that file. 291 PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() { 292 return PreprocessedEntitiesByFile; 293 } 294 295 // Retrieve the diagnostics associated with this AST 296 typedef const StoredDiagnostic *stored_diag_iterator; 297 stored_diag_iterator stored_diag_begin() const { 298 return StoredDiagnostics.begin(); 299 } 300 stored_diag_iterator stored_diag_end() const { 301 return StoredDiagnostics.end(); 302 } 303 unsigned stored_diag_size() const { return StoredDiagnostics.size(); } 304 305 llvm::SmallVector<StoredDiagnostic, 4> &getStoredDiagnostics() { 306 return StoredDiagnostics; 307 } 308 309 /// \brief A mapping from a file name to the memory buffer that stores the 310 /// remapped contents of that file. 311 typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile; 312 313 /// \brief Create a ASTUnit from a PCH file. 314 /// 315 /// \param Filename - The PCH file to load. 316 /// 317 /// \param Diags - The diagnostics engine to use for reporting errors; its 318 /// lifetime is expected to extend past that of the returned ASTUnit. 319 /// 320 /// \returns - The initialized ASTUnit or null if the PCH failed to load. 321 static ASTUnit *LoadFromPCHFile(const std::string &Filename, 322 llvm::IntrusiveRefCntPtr<Diagnostic> Diags, 323 bool OnlyLocalDecls = false, 324 RemappedFile *RemappedFiles = 0, 325 unsigned NumRemappedFiles = 0, 326 bool CaptureDiagnostics = false); 327 328 /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a 329 /// CompilerInvocation object. 330 /// 331 /// \param CI - The compiler invocation to use; it must have exactly one input 332 /// source file. The ASTUnit takes ownership of the CompilerInvocation object. 333 /// 334 /// \param Diags - The diagnostics engine to use for reporting errors; its 335 /// lifetime is expected to extend past that of the returned ASTUnit. 336 // 337 // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we 338 // shouldn't need to specify them at construction time. 339 static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI, 340 llvm::IntrusiveRefCntPtr<Diagnostic> Diags, 341 bool OnlyLocalDecls = false, 342 bool CaptureDiagnostics = false, 343 bool PrecompilePreamble = false); 344 345 /// LoadFromCommandLine - Create an ASTUnit from a vector of command line 346 /// arguments, which must specify exactly one source file. 347 /// 348 /// \param ArgBegin - The beginning of the argument vector. 349 /// 350 /// \param ArgEnd - The end of the argument vector. 351 /// 352 /// \param Diags - The diagnostics engine to use for reporting errors; its 353 /// lifetime is expected to extend past that of the returned ASTUnit. 354 /// 355 /// \param ResourceFilesPath - The path to the compiler resource files. 356 // 357 // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we 358 // shouldn't need to specify them at construction time. 359 static ASTUnit *LoadFromCommandLine(const char **ArgBegin, 360 const char **ArgEnd, 361 llvm::IntrusiveRefCntPtr<Diagnostic> Diags, 362 llvm::StringRef ResourceFilesPath, 363 bool OnlyLocalDecls = false, 364 RemappedFile *RemappedFiles = 0, 365 unsigned NumRemappedFiles = 0, 366 bool CaptureDiagnostics = false, 367 bool PrecompilePreamble = false); 368 369 /// \brief Reparse the source files using the same command-line options that 370 /// were originally used to produce this translation unit. 371 /// 372 /// \returns True if a failure occurred that causes the ASTUnit not to 373 /// contain any translation-unit information, false otherwise. 374 bool Reparse(RemappedFile *RemappedFiles = 0, 375 unsigned NumRemappedFiles = 0); 376}; 377 378} // namespace clang 379 380#endif 381