]> granicus.if.org Git - clang/blobdiff - include/clang/Basic/FileManager.h
Header guard canonicalization, clang part.
[clang] / include / clang / Basic / FileManager.h
index 826859fb50db947411b2e7179c41916640399366..a7069e65edf885dc75100ad473bbc0ebfbc3fb92 100644 (file)
@@ -6,24 +6,28 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-//
-//  This file defines the FileManager interface.
-//
+///
+/// \file
+/// \brief Defines the clang::FileManager interface and associated types.
+///
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_FILEMANAGER_H
-#define LLVM_CLANG_FILEMANAGER_H
+#ifndef LLVM_CLANG_BASIC_FILEMANAGER_H
+#define LLVM_CLANG_BASIC_FILEMANAGER_H
 
 #include "clang/Basic/FileSystemOptions.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/OwningPtr.h"
 #include "llvm/Support/Allocator.h"
+#include <memory>
 // FIXME: Enhance libsystem to support inode and other fields in stat.
 #include <sys/types.h>
+#include <map>
 
 #ifdef _MSC_VER
 typedef unsigned short mode_t;
@@ -33,112 +37,130 @@ struct stat;
 
 namespace llvm {
 class MemoryBuffer;
-namespace sys { class Path; }
 }
 
 namespace clang {
 class FileManager;
 class FileSystemStatCache;
-  
-/// DirectoryEntry - Cached information about one directory (either on
-/// the disk or in the virtual file system).
-///
+
+/// \brief Cached information about one directory (either on disk or in
+/// the virtual file system).
 class DirectoryEntry {
   const char *Name;   // Name of the directory.
   friend class FileManager;
 public:
-  DirectoryEntry() : Name(0) {}
+  DirectoryEntry() : Name(nullptr) {}
   const char *getName() const { return Name; }
 };
 
-/// FileEntry - Cached information about one file (either on the disk
-/// or in the virtual file system).  If the 'FD' member is valid, then
-/// this FileEntry has an open file descriptor for the file.
+/// \brief Cached information about one file (either on disk
+/// or in the virtual file system).
 ///
+/// If the 'File' member is valid, then this FileEntry has an open file
+/// descriptor for the file.
 class FileEntry {
-  const char *Name;           // Name of the file.
+  std::string Name;           // Name of the file.
   off_t Size;                 // File size in bytes.
   time_t ModTime;             // Modification time of file.
   const DirectoryEntry *Dir;  // Directory file lives in.
   unsigned UID;               // A unique (small) ID for the file.
-  dev_t Device;               // ID for the device containing the file.
-  ino_t Inode;                // Inode number for the file.
-  mode_t FileMode;            // The file mode as returned by 'stat'.
-  
-  /// FD - The file descriptor for the file entry if it is opened and owned
-  /// by the FileEntry.  If not, this is set to -1.
-  mutable int FD;
+  llvm::sys::fs::UniqueID UniqueID;
+  bool IsNamedPipe;
+  bool InPCH;
+  bool IsValid;               // Is this \c FileEntry initialized and valid?
+
+  /// \brief The open file, if it is owned by the \p FileEntry.
+  mutable std::unique_ptr<vfs::File> File;
   friend class FileManager;
-  
-public:
-  FileEntry(dev_t device, ino_t inode, mode_t m)
-    : Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {}
-  // Add a default constructor for use with llvm::StringMap
-  FileEntry() : Name(0), Device(0), Inode(0), FileMode(0), FD(-1) {}
-
-  FileEntry(const FileEntry &FE) {
-    memcpy(this, &FE, sizeof(FE));
-    assert(FD == -1 && "Cannot copy a file-owning FileEntry");
-  }
-  
-  void operator=(const FileEntry &FE) {
-    memcpy(this, &FE, sizeof(FE));
-    assert(FD == -1 && "Cannot assign a file-owning FileEntry");
+
+  void closeFile() const {
+    File.reset(); // rely on destructor to close File
   }
 
-  ~FileEntry();
+  void operator=(const FileEntry &) LLVM_DELETED_FUNCTION;
 
-  const char *getName() const { return Name; }
+public:
+  FileEntry()
+      : UniqueID(0, 0), IsNamedPipe(false), InPCH(false), IsValid(false)
+  {}
+
+  // FIXME: this is here to allow putting FileEntry in std::map.  Once we have
+  // emplace, we shouldn't need a copy constructor anymore.
+  /// Intentionally does not copy fields that are not set in an uninitialized
+  /// \c FileEntry.
+  FileEntry(const FileEntry &FE) : UniqueID(FE.UniqueID),
+      IsNamedPipe(FE.IsNamedPipe), InPCH(FE.InPCH), IsValid(FE.IsValid) {
+    assert(!isValid() && "Cannot copy an initialized FileEntry");
+  }
+
+  const char *getName() const { return Name.c_str(); }
+  bool isValid() const { return IsValid; }
   off_t getSize() const { return Size; }
   unsigned getUID() const { return UID; }
-  ino_t getInode() const { return Inode; }
-  dev_t getDevice() const { return Device; }
+  const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
+  bool isInPCH() const { return InPCH; }
   time_t getModificationTime() const { return ModTime; }
-  mode_t getFileMode() const { return FileMode; }
 
-  /// getDir - Return the directory the file lives in.
-  ///
+  /// \brief Return the directory the file lives in.
   const DirectoryEntry *getDir() const { return Dir; }
 
-  bool operator<(const FileEntry &RHS) const {
-    return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode);
-  }
+  bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; }
+
+  /// \brief Check whether the file is a named pipe (and thus can't be opened by
+  /// the native FileManager methods).
+  bool isNamedPipe() const { return IsNamedPipe; }
 };
 
-/// FileManager - Implements support for file system lookup, file system
-/// caching, and directory search management.  This also handles more advanced
-/// properties, such as uniquing files based on "inode", so that a file with two
-/// names (e.g. symlinked) will be treated as a single file.
+struct FileData;
+
+/// \brief Implements support for file system lookup, file system caching,
+/// and directory search management.
 ///
-class FileManager : public llvm::RefCountedBase<FileManager> {
+/// This also handles more advanced properties, such as uniquing files based
+/// on "inode", so that a file with two names (e.g. symlinked) will be treated
+/// as a single file.
+///
+class FileManager : public RefCountedBase<FileManager> {
+  IntrusiveRefCntPtr<vfs::FileSystem> FS;
   FileSystemOptions FileSystemOpts;
 
-  class UniqueDirContainer;
-  class UniqueFileContainer;
+  /// \brief Cache for existing real directories.
+  std::map<llvm::sys::fs::UniqueID, DirectoryEntry> UniqueRealDirs;
 
-  /// UniqueRealDirs/UniqueRealFiles - Cache for existing real directories/files.
-  ///
-  UniqueDirContainer &UniqueRealDirs;
-  UniqueFileContainer &UniqueRealFiles;
+  /// \brief Cache for existing real files.
+  std::map<llvm::sys::fs::UniqueID, FileEntry> UniqueRealFiles;
 
-  /// \brief The virtual directories that we have allocated.  For each
-  /// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent
+  /// \brief The virtual directories that we have allocated.
+  ///
+  /// For each virtual file (e.g. foo/bar/baz.cpp), we add all of its parent
   /// directories (foo/ and foo/bar/) here.
   SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
   /// \brief The virtual files that we have allocated.
   SmallVector<FileEntry*, 4> VirtualFileEntries;
 
-  /// SeenDirEntries/SeenFileEntries - This is a cache that maps paths
-  /// to directory/file entries (either real or virtual) we have
-  /// looked up.  The actual Entries for real directories/files are
+  /// \brief A cache that maps paths to directory entries (either real or
+  /// virtual) we have looked up
+  ///
+  /// The actual Entries for real directories/files are
   /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries
   /// for virtual directories/files are owned by
   /// VirtualDirectoryEntries/VirtualFileEntries above.
   ///
   llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries;
+
+  /// \brief A cache that maps paths to file entries (either real or
+  /// virtual) we have looked up.
+  ///
+  /// \see SeenDirEntries
   llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries;
 
-  /// NextFileUID - Each FileEntry we create is assigned a unique ID #.
+  /// \brief The canonical names of directories.
+  llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames;
+
+  /// \brief Storage for canonical names that we have computed.
+  llvm::BumpPtrAllocator CanonicalNameStorage;
+
+  /// \brief Each FileEntry we create is assigned a unique ID #.
   ///
   unsigned NextFileUID;
 
@@ -147,17 +169,18 @@ class FileManager : public llvm::RefCountedBase<FileManager> {
   unsigned NumDirCacheMisses, NumFileCacheMisses;
 
   // Caching.
-  llvm::OwningPtr<FileSystemStatCache> StatCache;
+  std::unique_ptr<FileSystemStatCache> StatCache;
 
-  bool getStatValue(const char *Path, struct stat &StatBuf,
-                    int *FileDescriptor);
+  bool getStatValue(const char *Path, FileData &Data, bool isFile,
+                    std::unique_ptr<vfs::File> *F);
 
   /// Add all ancestors of the given path (pointing to either a file
   /// or a directory) as virtual directories.
   void addAncestorsAsVirtualDirs(StringRef Path);
 
 public:
-  FileManager(const FileSystemOptions &FileSystemOpts);
+  FileManager(const FileSystemOptions &FileSystemOpts,
+              IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr);
   ~FileManager();
 
   /// \brief Installs the provided FileSystemStatCache object within
@@ -171,46 +194,71 @@ public:
   /// \param AtBeginning whether this new stat cache must be installed at the
   /// beginning of the chain of stat caches. Otherwise, it will be added to
   /// the end of the chain.
-  void addStatCache(FileSystemStatCache *statCache, bool AtBeginning = false);
+  void addStatCache(std::unique_ptr<FileSystemStatCache> statCache,
+                    bool AtBeginning = false);
 
   /// \brief Removes the specified FileSystemStatCache object from the manager.
   void removeStatCache(FileSystemStatCache *statCache);
 
-  /// getDirectory - Lookup, cache, and verify the specified directory
-  /// (real or virtual).  This returns NULL if the directory doesn't exist.
+  /// \brief Removes all FileSystemStatCache objects from the manager.
+  void clearStatCaches();
+
+  /// \brief Lookup, cache, and verify the specified directory (real or
+  /// virtual).
+  ///
+  /// This returns NULL if the directory doesn't exist.
   ///
-  const DirectoryEntry *getDirectory(StringRef DirName);
+  /// \param CacheFailure If true and the file does not exist, we'll cache
+  /// the failure to find this file.
+  const DirectoryEntry *getDirectory(StringRef DirName,
+                                     bool CacheFailure = true);
 
   /// \brief Lookup, cache, and verify the specified file (real or
-  /// virtual).  This returns NULL if the file doesn't exist.
+  /// virtual).
+  ///
+  /// This returns NULL if the file doesn't exist.
+  ///
+  /// \param OpenFile if true and the file exists, it will be opened.
   ///
-  /// \param openFile if true and the file exists, it will be opened.
-  const FileEntry *getFile(StringRef Filename, bool openFile = false);
+  /// \param CacheFailure If true and the file does not exist, we'll cache
+  /// the failure to find this file.
+  const FileEntry *getFile(StringRef Filename, bool OpenFile = false,
+                           bool CacheFailure = true);
 
-  /// \brief Forget any information about the given file name, because (for 
-  /// example) something within this process has changed the file in some way.
-  void forgetFile(StringRef Filename);
-  
   /// \brief Returns the current file system options
   const FileSystemOptions &getFileSystemOptions() { return FileSystemOpts; }
 
+  IntrusiveRefCntPtr<vfs::FileSystem> getVirtualFileSystem() const {
+    return FS;
+  }
+
   /// \brief Retrieve a file entry for a "virtual" file that acts as
-  /// if there were a file with the given name on disk. The file
-  /// itself is not accessed.
+  /// if there were a file with the given name on disk.
+  ///
+  /// The file itself is not accessed.
   const FileEntry *getVirtualFile(StringRef Filename, off_t Size,
                                   time_t ModificationTime);
 
   /// \brief Open the specified file as a MemoryBuffer, returning a new
   /// MemoryBuffer if successful, otherwise returning null.
   llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry,
-                                       std::string *ErrorStr = 0);
+                                       std::string *ErrorStr = nullptr,
+                                       bool isVolatile = false,
+                                       bool ShouldCloseOpenFile = true);
   llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
-                                       std::string *ErrorStr = 0);
+                                       std::string *ErrorStr = nullptr);
+
+  /// \brief Get the 'stat' information for the given \p Path.
+  ///
+  /// If the path is relative, it will be resolved against the WorkingDir of the
+  /// FileManager's FileSystemOptions.
+  ///
+  /// \returns false on success, true on error.
+  bool getNoncachedStatValue(StringRef Path,
+                             vfs::Status &Result);
 
-  // getNoncachedStatValue - Will get the 'stat' information for the given path.
-  // If the path is relative, it will be resolved against the WorkingDir of the
-  // FileManager's FileSystemOptions.
-  bool getNoncachedStatValue(StringRef Path, struct stat &StatBuf);
+  /// \brief Remove the real file \p Entry from the cache.
+  void invalidateCache(const FileEntry *Entry);
 
   /// \brief If path is not absolute and FileSystemOptions set the working
   /// directory, the path is modified to be relative to the given
@@ -221,7 +269,19 @@ public:
   /// file to the corresponding FileEntry pointer.
   void GetUniqueIDMapping(
                     SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
-  
+
+  /// \brief Modifies the size and modification time of a previously created
+  /// FileEntry. Use with caution.
+  static void modifyFileEntry(FileEntry *File, off_t Size,
+                              time_t ModificationTime);
+
+  /// \brief Retrieve the canonical name for a given directory.
+  ///
+  /// This is a very expensive operation, despite its results being cached,
+  /// and should only be used when the physical layout of the file system is
+  /// required, which is (almost) never.
+  StringRef getCanonicalName(const DirectoryEntry *Dir);
+
   void PrintStats() const;
 };