FileManager.h revision 9b555ea217565ac0f8bf7255b29496916cb03476
15f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===--- FileManager.h - File System Probing and Caching --------*- C++ -*-===// 25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// The LLVM Compiler Infrastructure 45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source 60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details. 75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===// 95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// This file defines the FileManager interface. 115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===// 135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#ifndef LLVM_CLANG_FILEMANAGER_H 155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#define LLVM_CLANG_FILEMANAGER_H 165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1739b49bcaaddb1049234fca9500c0ac02c088e23dChris Lattner#include "clang/Basic/FileSystemOptions.h" 18057e567f1b375190779e5341f42861896cdee442Douglas Gregor#include "llvm/ADT/SmallVector.h" 195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "llvm/ADT/StringMap.h" 20458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include "llvm/ADT/StringRef.h" 2196438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek#include "llvm/ADT/OwningPtr.h" 22f3eb9219cf4b4e80c377d37aed72d5d6d840b7bcTed Kremenek#include "llvm/Support/Allocator.h" 23ea684e699ea84e61711e279f5fa7a1b9f3d46bc2Cedric Venet#include "llvm/Config/config.h" // for mode_t 245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// FIXME: Enhance libsystem to support inode and other fields in stat. 255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include <sys/types.h> 2610e286aa8d39fb51a21412850265d9dae74613eeChris Lattner 2710e286aa8d39fb51a21412850265d9dae74613eeChris Lattnerstruct stat; 285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 29389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidisnamespace llvm { 30389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidisclass MemoryBuffer; 3110e286aa8d39fb51a21412850265d9dae74613eeChris Lattnernamespace sys { class Path; } 32389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis} 33389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis 345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencernamespace clang { 355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass FileManager; 3610e286aa8d39fb51a21412850265d9dae74613eeChris Lattnerclass FileSystemStatCache; 3710e286aa8d39fb51a21412850265d9dae74613eeChris Lattner 389b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan/// DirectoryEntry - Cached information about one directory (either on 399b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan/// the disk or in the virtual file system). 405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// 415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass DirectoryEntry { 425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *Name; // Name of the directory. 435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer friend class FileManager; 445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerpublic: 455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirectoryEntry() : Name(0) {} 461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const char *getName() const { return Name; } 475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}; 485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 499b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan/// FileEntry - Cached information about one file (either on the disk 509b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan/// or in the virtual file system). If the 'FD' member is valid, then 519b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan/// this FileEntry has an open file descriptor for the file. 525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// 535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass FileEntry { 54f17765d202d1ec34ada7ff3f18d18731588143c2Chris Lattner const char *Name; // Name of the file. 555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer off_t Size; // File size in bytes. 565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer time_t ModTime; // Modification time of file. 575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const DirectoryEntry *Dir; // Directory file lives in. 585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned UID; // A unique (small) ID for the file. 59bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek dev_t Device; // ID for the device containing the file. 60bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek ino_t Inode; // Inode number for the file. 6196438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek mode_t FileMode; // The file mode as returned by 'stat'. 62f9f7766846a205bc900b578f944567e679b221aaChris Lattner 63f9f7766846a205bc900b578f944567e679b221aaChris Lattner /// FD - The file descriptor for the file entry if it is opened and owned 64f9f7766846a205bc900b578f944567e679b221aaChris Lattner /// by the FileEntry. If not, this is set to -1. 655cc1c738b0c51af55cbfe7672c284c19f8e30eb2Chris Lattner mutable int FD; 665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer friend class FileManager; 67f9f7766846a205bc900b578f944567e679b221aaChris Lattner 685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerpublic: 6996438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek FileEntry(dev_t device, ino_t inode, mode_t m) 70f9f7766846a205bc900b578f944567e679b221aaChris Lattner : Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {} 716bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek // Add a default constructor for use with llvm::StringMap 72f9f7766846a205bc900b578f944567e679b221aaChris Lattner FileEntry() : Name(0), Device(0), Inode(0), FileMode(0), FD(-1) {} 73f9f7766846a205bc900b578f944567e679b221aaChris Lattner 74f9f7766846a205bc900b578f944567e679b221aaChris Lattner FileEntry(const FileEntry &FE) { 75f9f7766846a205bc900b578f944567e679b221aaChris Lattner memcpy(this, &FE, sizeof(FE)); 76e4fed47acee9e7ca9c9cfa77c3920eec4639d7d0Chris Lattner assert(FD == -1 && "Cannot copy a file-owning FileEntry"); 77e4fed47acee9e7ca9c9cfa77c3920eec4639d7d0Chris Lattner } 78e4fed47acee9e7ca9c9cfa77c3920eec4639d7d0Chris Lattner 79e4fed47acee9e7ca9c9cfa77c3920eec4639d7d0Chris Lattner void operator=(const FileEntry &FE) { 80e4fed47acee9e7ca9c9cfa77c3920eec4639d7d0Chris Lattner memcpy(this, &FE, sizeof(FE)); 81e4fed47acee9e7ca9c9cfa77c3920eec4639d7d0Chris Lattner assert(FD == -1 && "Cannot assign a file-owning FileEntry"); 82f9f7766846a205bc900b578f944567e679b221aaChris Lattner } 83f9f7766846a205bc900b578f944567e679b221aaChris Lattner 84f9f7766846a205bc900b578f944567e679b221aaChris Lattner ~FileEntry(); 851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *getName() const { return Name; } 875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer off_t getSize() const { return Size; } 885f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned getUID() const { return UID; } 89bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek ino_t getInode() const { return Inode; } 907f1752797d4a4344b539ad9452471871c0eec64bTed Kremenek dev_t getDevice() const { return Device; } 915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer time_t getModificationTime() const { return ModTime; } 9296438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek mode_t getFileMode() const { return FileMode; } 931eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 945f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// getDir - Return the directory the file lives in. 955f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// 965f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const DirectoryEntry *getDir() const { return Dir; } 971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 98f9f7766846a205bc900b578f944567e679b221aaChris Lattner bool operator<(const FileEntry &RHS) const { 99bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode); 100bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek } 1015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}; 1025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// FileManager - Implements support for file system lookup, file system 1045f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// caching, and directory search management. This also handles more advanced 1055f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// properties, such as uniquing files based on "inode", so that a file with two 1065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// names (e.g. symlinked) will be treated as a single file. 1075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// 1085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerclass FileManager { 10939b49bcaaddb1049234fca9500c0ac02c088e23dChris Lattner FileSystemOptions FileSystemOpts; 1109b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan 1116bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek class UniqueDirContainer; 1126bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek class UniqueFileContainer; 1136bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1149b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// UniqueRealDirs/UniqueRealFiles - Cache for existing real directories/files. 1155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// 1169b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan UniqueDirContainer &UniqueRealDirs; 1179b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan UniqueFileContainer &UniqueRealFiles; 1186bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1199b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// \brief The virtual directories that we have allocated. For each 1209b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent 1219b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// directories (foo/ and foo/bar/) here. 1229b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan llvm::SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries; 1239b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// \brief The virtual files that we have allocated. 1249b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan llvm::SmallVector<FileEntry*, 4> VirtualFileEntries; 1259b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan 1269b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// SeenDirEntries/SeenFileEntries - This is a cache that maps paths 1279b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// to directory/file entries (either real or virtual) we have 1289b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// looked up. The actual Entries for real directories/files are 1299b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries 1309b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// for virtual directories/files are owned by 1319b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// VirtualDirectoryEntries/VirtualFileEntries above. 1325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// 1339b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries; 1349b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries; 1351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// NextFileUID - Each FileEntry we create is assigned a unique ID #. 1375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer /// 1385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned NextFileUID; 1391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Statistics. 1415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned NumDirLookups, NumFileLookups; 1425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer unsigned NumDirCacheMisses, NumFileCacheMisses; 1431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 144fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek // Caching. 14510e286aa8d39fb51a21412850265d9dae74613eeChris Lattner llvm::OwningPtr<FileSystemStatCache> StatCache; 1461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 147898a061f69e1145bf89a987c08203132b9922a3cChris Lattner bool getStatValue(const char *Path, struct stat &StatBuf, 148898a061f69e1145bf89a987c08203132b9922a3cChris Lattner int *FileDescriptor); 1499b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan 1509b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// Add all ancestors of the given path (pointing to either a file 1519b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// or a directory) as virtual directories. 1529b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan void addAncestorsAsVirtualDirs(llvm::StringRef Path); 1539b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan 1545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerpublic: 1557ad97ffa631af6ad678c79b38341ac995f347ce9Chris Lattner FileManager(const FileSystemOptions &FileSystemOpts); 1566bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek ~FileManager(); 1575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 15810e286aa8d39fb51a21412850265d9dae74613eeChris Lattner /// \brief Installs the provided FileSystemStatCache object within 1599b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// the FileManager. 16052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// 16152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// Ownership of this object is transferred to the FileManager. 16252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// 16352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// \param statCache the new stat cache to install. Ownership of this 16452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// object is transferred to the FileManager. 16552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// 16652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// \param AtBeginning whether this new stat cache must be installed at the 16752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// beginning of the chain of stat caches. Otherwise, it will be added to 16852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor /// the end of the chain. 16910e286aa8d39fb51a21412850265d9dae74613eeChris Lattner void addStatCache(FileSystemStatCache *statCache, bool AtBeginning = false); 17052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor 17110e286aa8d39fb51a21412850265d9dae74613eeChris Lattner /// \brief Removes the specified FileSystemStatCache object from the manager. 17210e286aa8d39fb51a21412850265d9dae74613eeChris Lattner void removeStatCache(FileSystemStatCache *statCache); 1739b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan 1749b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// getDirectory - Lookup, cache, and verify the specified directory 1759b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// (real or virtual). This returns NULL if the directory doesn't exist. 1761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump /// 1779b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan const DirectoryEntry *getDirectory(llvm::StringRef DirName); 1781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1799b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// getFile - Lookup, cache, and verify the specified file (real or 1809b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan /// virtual). This returns NULL if the file doesn't exist. 1811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump /// 18239b49bcaaddb1049234fca9500c0ac02c088e23dChris Lattner const FileEntry *getFile(llvm::StringRef Filename); 1831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 184057e567f1b375190779e5341f42861896cdee442Douglas Gregor /// \brief Retrieve a file entry for a "virtual" file that acts as 185057e567f1b375190779e5341f42861896cdee442Douglas Gregor /// if there were a file with the given name on disk. The file 186057e567f1b375190779e5341f42861896cdee442Douglas Gregor /// itself is not accessed. 187ec1b1cc006cef19e0a95d0ea6fbfd37d0d615066Benjamin Kramer const FileEntry *getVirtualFile(llvm::StringRef Filename, off_t Size, 18839b49bcaaddb1049234fca9500c0ac02c088e23dChris Lattner time_t ModificationTime); 189389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis 190389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis /// \brief Open the specified file as a MemoryBuffer, returning a new 191389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis /// MemoryBuffer if successful, otherwise returning null. 192389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry, 19375dfb65c38d51772df9a00ce2d2feeefd55667adChris Lattner std::string *ErrorStr = 0); 194389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename, 19575dfb65c38d51772df9a00ce2d2feeefd55667adChris Lattner std::string *ErrorStr = 0); 196389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis 197389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis /// \brief If path is not absolute and FileSystemOptions set the working 198389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis /// directory, the path is modified to be relative to the given 199389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis /// working directory. 200389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis static void FixupRelativePath(llvm::sys::Path &path, 201389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis const FileSystemOptions &FSOpts); 2029b555ea217565ac0f8bf7255b29496916cb03476Zhanyong Wan 203cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor 204cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor /// \brief Produce an array mapping from the unique IDs assigned to each 205cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor /// file to the corresponding FileEntry pointer. 206cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor void GetUniqueIDMapping( 207cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const; 208cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor 2095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer void PrintStats() const; 2105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}; 2115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} // end namespace clang 2135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#endif 215