diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index 7e3b8650fe41213fea5c47b5b9dfc7429560ef1e..563157fa8fbebcc597030ae30da9eb2d31f4e3e9 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -35,7 +35,8 @@ namespace clang {
 class FileManager;
 class FileSystemStatCache;
   
-/// DirectoryEntry - Cached information about one directory on the disk.
+/// DirectoryEntry - Cached information about one directory (either on
+/// the disk or in the virtual file system).
 ///
 class DirectoryEntry {
   const char *Name;   // Name of the directory.
@@ -45,9 +46,9 @@ public:
   const char *getName() const { return Name; }
 };
 
-/// FileEntry - Cached information about one file on the disk.  If the 'FD'
-/// member is valid, then this FileEntry has an open file descriptor for the
-/// file.
+/// 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.
 ///
 class FileEntry {
   const char *Name;           // Name of the file.
@@ -106,28 +107,36 @@ public:
 ///
 class FileManager {
   FileSystemOptions FileSystemOpts;
-  
+
   class UniqueDirContainer;
   class UniqueFileContainer;
 
-  /// UniqueDirs/UniqueFiles - Cache for existing directories/files.
+  /// UniqueRealDirs/UniqueRealFiles - Cache for existing real directories/files.
   ///
-  UniqueDirContainer &UniqueDirs;
-  UniqueFileContainer &UniqueFiles;
+  UniqueDirContainer &UniqueRealDirs;
+  UniqueFileContainer &UniqueRealFiles;
 
-  /// DirEntries/FileEntries - This is a cache of directory/file entries we have
-  /// looked up.  The actual Entry is owned by UniqueFiles/UniqueDirs above.
+  /// \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.
+  llvm::SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
+  /// \brief The virtual files that we have allocated.
+  llvm::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
+  /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries
+  /// for virtual directories/files are owned by
+  /// VirtualDirectoryEntries/VirtualFileEntries above.
   ///
-  llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> DirEntries;
-  llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> FileEntries;
+  llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries;
+  llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries;
 
   /// NextFileUID - Each FileEntry we create is assigned a unique ID #.
   ///
   unsigned NextFileUID;
 
-  /// \brief The virtual files that we have allocated.
-  llvm::SmallVector<FileEntry*, 4> VirtualFileEntries;
-
   // Statistics.
   unsigned NumDirLookups, NumFileLookups;
   unsigned NumDirCacheMisses, NumFileCacheMisses;
@@ -137,12 +146,17 @@ class FileManager {
 
   bool getStatValue(const char *Path, struct stat &StatBuf,
                     int *FileDescriptor);
+
+  /// Add all ancestors of the given path (pointing to either a file
+  /// or a directory) as virtual directories.
+  void addAncestorsAsVirtualDirs(llvm::StringRef Path);
+
 public:
   FileManager(const FileSystemOptions &FileSystemOpts);
   ~FileManager();
 
   /// \brief Installs the provided FileSystemStatCache object within
-  /// the FileManager. 
+  /// the FileManager.
   ///
   /// Ownership of this object is transferred to the FileManager.
   ///
@@ -156,14 +170,14 @@ public:
 
   /// \brief Removes the specified FileSystemStatCache object from the manager.
   void removeStatCache(FileSystemStatCache *statCache);
-  
-  /// getDirectory - Lookup, cache, and verify the specified directory.  This
-  /// returns null if the directory doesn't exist.
+
+  /// getDirectory - Lookup, cache, and verify the specified directory
+  /// (real or virtual).  This returns NULL if the directory doesn't exist.
   ///
-  const DirectoryEntry *getDirectory(llvm::StringRef Filename);
+  const DirectoryEntry *getDirectory(llvm::StringRef DirName);
 
-  /// getFile - Lookup, cache, and verify the specified file.  This returns null
-  /// if the file doesn't exist.
+  /// getFile - Lookup, cache, and verify the specified file (real or
+  /// virtual).  This returns NULL if the file doesn't exist.
   ///
   const FileEntry *getFile(llvm::StringRef Filename);
 
@@ -185,7 +199,7 @@ public:
   /// working directory.
   static void FixupRelativePath(llvm::sys::Path &path,
                                 const FileSystemOptions &FSOpts);
-  
+
   
   /// \brief Produce an array mapping from the unique IDs assigned to each
   /// file to the corresponding FileEntry pointer.
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index cfb24a2fa253094aa197fef222d076f9cf7b64e9..df3ed2830229e2324aceda4e1ea97139daabbd4e 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -84,7 +84,11 @@ class FileManager::UniqueDirContainer {
   llvm::StringMap<DirectoryEntry> UniqueDirs;
 
 public:
-  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
+  /// getDirectory - Return an existing DirectoryEntry with the given
+  /// name if there is already one; otherwise create and return a
+  /// default-constructed DirectoryEntry.
+  DirectoryEntry &getDirectory(const char *Name,
+                               const struct stat & /*StatBuf*/) {
     std::string FullPath(GetFullPath(Name));
     return UniqueDirs.GetOrCreateValue(FullPath).getValue();
   }
@@ -98,9 +102,12 @@ class FileManager::UniqueFileContainer {
   llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
 
 public:
-  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
+  /// getFile - Return an existing FileEntry with the given name if
+  /// there is already one; otherwise create and return a
+  /// default-constructed FileEntry.
+  FileEntry &getFile(const char *Name, const struct stat & /*StatBuf*/) {
     std::string FullPath(GetFullPath(Name));
-    
+
     // LowercaseString because Windows filesystem is case insensitive.
     FullPath = llvm::LowercaseString(FullPath);
     return UniqueFiles.GetOrCreateValue(FullPath).getValue();
@@ -122,7 +129,11 @@ class FileManager::UniqueDirContainer {
   std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
 
 public:
-  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
+  /// getDirectory - Return an existing DirectoryEntry with the given
+  /// ID's if there is already one; otherwise create and return a
+  /// default-constructed DirectoryEntry.
+  DirectoryEntry &getDirectory(const char * /*Name*/,
+                               const struct stat &StatBuf) {
     return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
   }
 
@@ -134,7 +145,10 @@ class FileManager::UniqueFileContainer {
   std::set<FileEntry> UniqueFiles;
 
 public:
-  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
+  /// getFile - Return an existing FileEntry with the given ID's if
+  /// there is already one; otherwise create and return a
+  /// default-constructed FileEntry.
+  FileEntry &getFile(const char * /*Name*/, const struct stat &StatBuf) {
     return
       const_cast<FileEntry&>(
                     *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
@@ -153,18 +167,20 @@ public:
 
 FileManager::FileManager(const FileSystemOptions &FSO)
   : FileSystemOpts(FSO),
-    UniqueDirs(*new UniqueDirContainer()),
-    UniqueFiles(*new UniqueFileContainer()),
-    DirEntries(64), FileEntries(64), NextFileUID(0) {
+    UniqueRealDirs(*new UniqueDirContainer()),
+    UniqueRealFiles(*new UniqueFileContainer()),
+    SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
   NumDirLookups = NumFileLookups = 0;
   NumDirCacheMisses = NumFileCacheMisses = 0;
 }
 
 FileManager::~FileManager() {
-  delete &UniqueDirs;
-  delete &UniqueFiles;
+  delete &UniqueRealDirs;
+  delete &UniqueRealFiles;
   for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
     delete VirtualFileEntries[i];
+  for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
+    delete VirtualDirectoryEntries[i];
 }
 
 void FileManager::addStatCache(FileSystemStatCache *statCache,
@@ -203,12 +219,16 @@ void FileManager::removeStatCache(FileSystemStatCache *statCache) {
 }
 
 /// \brief Retrieve the directory that the given file name resides in.
+/// Filename can point to either a real file or a virtual file.
 static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
                                                   llvm::StringRef Filename) {
   // Figure out what directory it is in.   If the string contains a / in it,
   // strip off everything after it.
   // FIXME: this logic should be in sys::Path.
   size_t SlashPos = Filename.size();
+  if (SlashPos == 0 || IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1]))
+    return NULL;  // If Filename is empty or a directory.
+
   while (SlashPos != 0 && !IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1]))
     --SlashPos;
 
@@ -216,9 +236,6 @@ static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
   if (SlashPos == 0)
     return FileMgr.getDirectory(".");
 
-  if (SlashPos == Filename.size()-1)
-    return 0;       // If filename ends with a /, it's a directory.
-
   // Ignore repeated //'s.
   while (SlashPos != 0 && IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1]))
     --SlashPos;
@@ -226,19 +243,58 @@ static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
   return FileMgr.getDirectory(Filename.substr(0, SlashPos));
 }
 
-/// getDirectory - Lookup, cache, and verify the specified directory.  This
-/// returns null if the directory doesn't exist.
+/// Add all ancestors of the given path (pointing to either a file or
+/// a directory) as virtual directories.
+void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) {
+  size_t SlashPos = Path.size();
+
+  // Find the beginning of the last segment in Path.
+  while (SlashPos != 0 && !IS_DIR_SEPARATOR_CHAR(Path[SlashPos-1]))
+    --SlashPos;
+
+  // Ignore repeated //'s.
+  while (SlashPos != 0 && IS_DIR_SEPARATOR_CHAR(Path[SlashPos-1]))
+    --SlashPos;
+
+  if (SlashPos == 0)
+    return;
+
+  llvm::StringRef DirName = Path.substr(0, SlashPos);
+  llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
+    SeenDirEntries.GetOrCreateValue(DirName);
+
+  // When caching a virtual directory, we always cache its ancestors
+  // at the same time.  Therefore, if DirName is already in the cache,
+  // we don't need to recurse as its ancestors must also already be in
+  // the cache.
+  if (NamedDirEnt.getValue())
+    return;
+
+  // Add the virtual directory to the cache.
+  DirectoryEntry *UDE = new DirectoryEntry;
+  UDE->Name = NamedDirEnt.getKeyData();
+  NamedDirEnt.setValue(UDE);
+  VirtualDirectoryEntries.push_back(UDE);
+
+  // Recursively add the other ancestors.
+  addAncestorsAsVirtualDirs(DirName);
+}
+
+/// getDirectory - Lookup, cache, and verify the specified directory
+/// (real or virtual).  This returns NULL if the directory doesn't
+/// exist.
 ///
-const DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) {
+const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
   // stat doesn't like trailing separators (at least on Windows).
-  if (Filename.size() > 1 && IS_DIR_SEPARATOR_CHAR(Filename.back()))
-    Filename = Filename.substr(0, Filename.size()-1);
+  if (DirName.size() > 1 && IS_DIR_SEPARATOR_CHAR(DirName.back()))
+    DirName = DirName.substr(0, DirName.size()-1);
 
   ++NumDirLookups;
   llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
-    DirEntries.GetOrCreateValue(Filename);
+    SeenDirEntries.GetOrCreateValue(DirName);
 
-  // See if there is already an entry in the map.
+  // See if there was already an entry in the map.  Note that the map
+  // contains both virtual and real directories.
   if (NamedDirEnt.getValue())
     return NamedDirEnt.getValue() == NON_EXISTENT_DIR
               ? 0 : NamedDirEnt.getValue();
@@ -249,37 +305,41 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) {
   NamedDirEnt.setValue(NON_EXISTENT_DIR);
 
   // Get the null-terminated directory name as stored as the key of the
-  // DirEntries map.
+  // SeenDirEntries map.
   const char *InterndDirName = NamedDirEnt.getKeyData();
 
   // Check to see if the directory exists.
   struct stat StatBuf;
-  if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/))
+  if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
+    // There's no real directory at the given path.
     return 0;
+  }
 
-  // It exists.  See if we have already opened a directory with the same inode.
-  // This occurs when one dir is symlinked to another, for example.
-  DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
+  // It exists.  See if we have already opened a directory with the
+  // same inode (this occurs on Unix-like systems when one dir is
+  // symlinked to another, for example) or the same path (on
+  // Windows).
+  DirectoryEntry &UDE = UniqueRealDirs.getDirectory(InterndDirName, StatBuf);
 
   NamedDirEnt.setValue(&UDE);
-  if (UDE.getName()) // Already have an entry with this inode, return it.
-    return &UDE;
+  if (!UDE.getName()) {
+    // We don't have this directory yet, add it.  We use the string
+    // key from the SeenDirEntries map as the string.
+    UDE.Name  = InterndDirName;
+  }
 
-  // Otherwise, we don't have this directory yet, add it.  We use the string
-  // key from the DirEntries map as the string.
-  UDE.Name  = InterndDirName;
   return &UDE;
 }
 
-/// getFile - Lookup, cache, and verify the specified file.  This returns null
-/// if the file doesn't exist.
+/// getFile - Lookup, cache, and verify the specified file (real or
+/// virtual).  This returns NULL if the file doesn't exist.
 ///
 const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
   ++NumFileLookups;
 
   // See if there is already an entry in the map.
   llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
-    FileEntries.GetOrCreateValue(Filename);
+    SeenFileEntries.GetOrCreateValue(Filename);
 
   // See if there is already an entry in the map.
   if (NamedFileEnt.getValue())
@@ -291,12 +351,10 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
   // By default, initialize it to invalid.
   NamedFileEnt.setValue(NON_EXISTENT_FILE);
 
-
   // Get the null-terminated file name as stored as the key of the
-  // FileEntries map.
+  // SeenFileEntries map.
   const char *InterndFileName = NamedFileEnt.getKeyData();
 
-  
   // Look up the directory for the file.  When looking up something like
   // sys/foo.h we'll discover all of the search directories that have a 'sys'
   // subdirectory.  This will let us avoid having to waste time on known-to-fail
@@ -312,25 +370,27 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
   // Nope, there isn't.  Check to see if the file exists.
   int FileDescriptor = -1;
   struct stat StatBuf;
-  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor))
+  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
+    // There's no real file at the given path.
     return 0;
+  }
 
   // It exists.  See if we have already opened a file with the same inode.
   // This occurs when one dir is symlinked to another, for example.
-  FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
+  FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf);
 
   NamedFileEnt.setValue(&UFE);
   if (UFE.getName()) { // Already have an entry with this inode, return it.
     // If the stat process opened the file, close it to avoid a FD leak.
     if (FileDescriptor != -1)
       close(FileDescriptor);
-    
+
     return &UFE;
   }
 
   // Otherwise, we don't have this directory yet, add it.
-  // FIXME: Change the name to be a char* that points back to the 'FileEntries'
-  // key.
+  // FIXME: Change the name to be a char* that points back to the
+  // 'SeenFileEntries' key.
   UFE.Name    = InterndFileName;
   UFE.Size    = StatBuf.st_size;
   UFE.ModTime = StatBuf.st_mtime;
@@ -347,7 +407,7 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
 
   // See if there is already an entry in the map.
   llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
-    FileEntries.GetOrCreateValue(Filename);
+    SeenFileEntries.GetOrCreateValue(Filename);
 
   // See if there is already an entry in the map.
   if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE)
@@ -358,37 +418,42 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   // By default, initialize it to invalid.
   NamedFileEnt.setValue(NON_EXISTENT_FILE);
 
-  // We allow the directory to not exist. If it does exist we store it.
+  addAncestorsAsVirtualDirs(Filename);
   FileEntry *UFE = 0;
+
+  // Now that all ancestors of Filename are in the cache, the
+  // following call is guaranteed to find the DirectoryEntry from the
+  // cache.
   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
-  if (DirInfo) {
-    // Check to see if the file exists. If so, drop the virtual file
-    int FileDescriptor = -1;
-    struct stat StatBuf;
-    const char *InterndFileName = NamedFileEnt.getKeyData();
-    if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
-      // If the stat process opened the file, close it to avoid a FD leak.
-      if (FileDescriptor != -1)
-        close(FileDescriptor);
-
-      StatBuf.st_size = Size;
-      StatBuf.st_mtime = ModificationTime;
-      UFE = &UniqueFiles.getFile(InterndFileName, StatBuf);
-
-      NamedFileEnt.setValue(UFE);
-
-      // If we had already opened this file, close it now so we don't
-      // leak the descriptor. We're not going to use the file
-      // descriptor anyway, since this is a virtual file.
-      if (UFE->FD != -1) {
-        close(UFE->FD); 
-        UFE->FD = -1;
-      }
-
-      // If we already have an entry with this inode, return it.
-      if (UFE->getName()) 
-        return UFE;
+  assert(DirInfo &&
+         "The directory of a virtual file should already be in the cache.");
+
+  // Check to see if the file exists. If so, drop the virtual file
+  int FileDescriptor = -1;
+  struct stat StatBuf;
+  const char *InterndFileName = NamedFileEnt.getKeyData();
+  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
+    // If the stat process opened the file, close it to avoid a FD leak.
+    if (FileDescriptor != -1)
+      close(FileDescriptor);
+
+    StatBuf.st_size = Size;
+    StatBuf.st_mtime = ModificationTime;
+    UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf);
+
+    NamedFileEnt.setValue(UFE);
+
+    // If we had already opened this file, close it now so we don't
+    // leak the descriptor. We're not going to use the file
+    // descriptor anyway, since this is a virtual file.
+    if (UFE->FD != -1) {
+      close(UFE->FD);
+      UFE->FD = -1;
     }
+
+    // If we already have an entry with this inode, return it.
+    if (UFE->getName())
+      return UFE;
   }
 
   if (!UFE) {
@@ -397,10 +462,6 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
     NamedFileEnt.setValue(UFE);
   }
 
-  // Get the null-terminated file name as stored as the key of the
-  // FileEntries map.
-  const char *InterndFileName = NamedFileEnt.getKeyData();
-   
   UFE->Name    = InterndFileName;
   UFE->Size    = Size;
   UFE->ModTime = ModificationTime;
@@ -472,12 +533,11 @@ getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
   return Result.take();
 }
 
-/// getStatValue - Get the 'stat' information for the specified path, using the
-/// cache to accelerate it if possible.  This returns true if the path does not
-/// exist or false if it exists.
-///
-/// The isForDir member indicates whether this is a directory lookup or not.
-/// This will return failure if the lookup isn't the expected kind.
+/// getStatValue - Get the 'stat' information for the specified path,
+/// using the cache to accelerate it if possible.  This returns true
+/// if the path points to a virtual file or does not exist, or returns
+/// false if it's an existent real file.  If FileDescriptor is NULL,
+/// do directory look-up instead of file look-up.
 bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
                                int *FileDescriptor) {
   // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
@@ -485,7 +545,7 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
   if (FileSystemOpts.WorkingDir.empty())
     return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
                                     StatCache.get());
-  
+
   llvm::sys::Path FilePath(Path);
   FixupRelativePath(FilePath, FileSystemOpts);
 
@@ -500,7 +560,7 @@ void FileManager::GetUniqueIDMapping(
   
   // Map file entries
   for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
-         FE = FileEntries.begin(), FEEnd = FileEntries.end();
+         FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
        FE != FEEnd; ++FE)
     if (FE->getValue() && FE->getValue() != NON_EXISTENT_FILE)
       UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
@@ -516,8 +576,10 @@ void FileManager::GetUniqueIDMapping(
 
 void FileManager::PrintStats() const {
   llvm::errs() << "\n*** File Manager Stats:\n";
-  llvm::errs() << UniqueFiles.size() << " files found, "
-               << UniqueDirs.size() << " dirs found.\n";
+  llvm::errs() << UniqueRealFiles.size() << " real files found, "
+               << UniqueRealDirs.size() << " real dirs found.\n";
+  llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
+               << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
   llvm::errs() << NumDirLookups << " dir lookups, "
                << NumDirCacheMisses << " dir cache misses.\n";
   llvm::errs() << NumFileLookups << " file lookups, "
@@ -525,4 +587,3 @@ void FileManager::PrintStats() const {
 
   //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
 }
-
diff --git a/unittests/FileManager/FileManagerTest.cpp b/unittests/FileManager/FileManagerTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a7d3df3125d7d5bd9a155046611442c6be86c715
--- /dev/null
+++ b/unittests/FileManager/FileManagerTest.cpp
@@ -0,0 +1,222 @@
+//===- unittests/FileManager/FileMangerTest.cpp ------ FileManger tests ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/FileSystemStatCache.h"
+#include "clang/Basic/FileManager.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// Used to create a fake file system for running the tests with such
+// that the tests are not affected by the structure/contents of the
+// file system on the machine running the tests.
+class FakeStatCache : public FileSystemStatCache {
+private:
+  // Maps a file/directory path to its desired stat result.  Anything
+  // not in this map is considered to not exist in the file system.
+  llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls;
+
+  void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
+    struct stat statBuf = {};
+    statBuf.st_dev = 1;
+#ifndef LLVM_ON_WIN32  // struct stat has no st_ino field on Windows.
+    statBuf.st_ino = INode;
+#endif
+    statBuf.st_mode = IsFile ? (0777 | S_IFREG)  // a regular file
+        : (0777 | S_IFDIR);  // a directory
+    StatCalls[Path] = statBuf;
+  }
+
+public:
+  // Inject a file with the given inode value to the fake file system.
+  void InjectFile(const char *Path, ino_t INode) {
+    InjectFileOrDirectory(Path, INode, /*IsFile=*/true);
+  }
+
+  // Inject a directory with the given inode value to the fake file system.
+  void InjectDirectory(const char *Path, ino_t INode) {
+    InjectFileOrDirectory(Path, INode, /*IsFile=*/false);
+  }
+
+  // Implement FileSystemStatCache::getStat().
+  virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
+                               int *FileDescriptor) {
+    if (StatCalls.count(Path) != 0) {
+      StatBuf = StatCalls[Path];
+      return CacheExists;
+    }
+
+    return CacheMissing;  // This means the file/directory doesn't exist.
+  }
+};
+
+// The test fixture.
+class FileManagerTest : public ::testing::Test {
+ protected:
+  FileManagerTest() : manager(options) {
+  }
+
+  FileSystemOptions options;
+  FileManager manager;
+};
+
+// When a virtual file is added, its getDir() field is set correctly
+// (not NULL, correct name).
+TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
+  const FileEntry *file = manager.getVirtualFile("foo.cpp", 42, 0);
+  ASSERT_TRUE(file != NULL);
+
+  const DirectoryEntry *dir = file->getDir();
+  ASSERT_TRUE(dir != NULL);
+  EXPECT_STREQ(".", dir->getName());
+
+  file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
+  ASSERT_TRUE(file != NULL);
+
+  dir = file->getDir();
+  ASSERT_TRUE(dir != NULL);
+  EXPECT_STREQ("x/y", dir->getName());
+}
+
+// Before any virtual file is added, no virtual directory exists.
+TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
+  // An empty FakeStatCache causes all stat calls made by the
+  // FileManager to report "file/directory doesn't exist".  This
+  // avoids the possibility of the result of this test being affected
+  // by what's in the real file system.
+  manager.addStatCache(new FakeStatCache);
+
+  EXPECT_EQ(NULL, manager.getDirectory("virtual/dir/foo"));
+  EXPECT_EQ(NULL, manager.getDirectory("virtual/dir"));
+  EXPECT_EQ(NULL, manager.getDirectory("virtual"));
+}
+
+// When a virtual file is added, all of its ancestors should be created.
+TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
+  // Fake an empty real file system.
+  manager.addStatCache(new FakeStatCache);
+
+  manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
+  EXPECT_EQ(NULL, manager.getDirectory("virtual/dir/foo"));
+
+  const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
+  ASSERT_TRUE(dir != NULL);
+  EXPECT_STREQ("virtual/dir", dir->getName());
+
+  dir = manager.getDirectory("virtual");
+  ASSERT_TRUE(dir != NULL);
+  EXPECT_STREQ("virtual", dir->getName());
+}
+
+// getFile() returns non-NULL if a real file exists at the given path.
+TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
+  // Inject fake files into the file system.
+  FakeStatCache *statCache = new FakeStatCache;
+  statCache->InjectDirectory("/tmp", 42);
+  statCache->InjectFile("/tmp/test", 43);
+  manager.addStatCache(statCache);
+
+  const FileEntry *file = manager.getFile("/tmp/test");
+  ASSERT_TRUE(file != NULL);
+  EXPECT_STREQ("/tmp/test", file->getName());
+
+  const DirectoryEntry *dir = file->getDir();
+  ASSERT_TRUE(dir != NULL);
+  EXPECT_STREQ("/tmp", dir->getName());
+}
+
+// getFile() returns non-NULL if a virtual file exists at the given path.
+TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
+  // Fake an empty real file system.
+  manager.addStatCache(new FakeStatCache);
+
+  manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
+  const FileEntry *file = manager.getFile("virtual/dir/bar.h");
+  ASSERT_TRUE(file != NULL);
+  EXPECT_STREQ("virtual/dir/bar.h", file->getName());
+
+  const DirectoryEntry *dir = file->getDir();
+  ASSERT_TRUE(dir != NULL);
+  EXPECT_STREQ("virtual/dir", dir->getName());
+}
+
+// getFile() returns different FileEntries for different paths when
+// there's no aliasing.
+TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
+  // Inject two fake files into the file system.  Different inodes
+  // mean the files are not symlinked together.
+  FakeStatCache *statCache = new FakeStatCache;
+  statCache->InjectDirectory(".", 41);
+  statCache->InjectFile("foo.cpp", 42);
+  statCache->InjectFile("bar.cpp", 43);
+  manager.addStatCache(statCache);
+
+  const FileEntry *fileFoo = manager.getFile("foo.cpp");
+  const FileEntry *fileBar = manager.getFile("bar.cpp");
+  ASSERT_TRUE(fileFoo != NULL);
+  ASSERT_TRUE(fileBar != NULL);
+  EXPECT_NE(fileFoo, fileBar);
+}
+
+// getFile() returns NULL if neither a real file nor a virtual file
+// exists at the given path.
+TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
+  // Inject a fake foo.cpp into the file system.
+  FakeStatCache *statCache = new FakeStatCache;
+  statCache->InjectDirectory(".", 41);
+  statCache->InjectFile("foo.cpp", 42);
+  manager.addStatCache(statCache);
+
+  // Create a virtual bar.cpp file.
+  manager.getVirtualFile("bar.cpp", 200, 0);
+
+  const FileEntry *file = manager.getFile("xyz.txt");
+  EXPECT_EQ(NULL, file);
+}
+
+// The following tests apply to Unix-like system only.
+
+#ifndef LLVM_ON_WIN32
+
+// getFile() returns the same FileEntry for real files that are aliases.
+TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
+  // Inject two real files with the same inode.
+  FakeStatCache *statCache = new FakeStatCache;
+  statCache->InjectDirectory("abc", 41);
+  statCache->InjectFile("abc/foo.cpp", 42);
+  statCache->InjectFile("abc/bar.cpp", 42);
+  manager.addStatCache(statCache);
+
+  EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
+}
+
+// getFile() returns the same FileEntry for virtual files that have
+// corresponding real files that are aliases.
+TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
+  // Inject two real files with the same inode.
+  FakeStatCache *statCache = new FakeStatCache;
+  statCache->InjectDirectory("abc", 41);
+  statCache->InjectFile("abc/foo.cpp", 42);
+  statCache->InjectFile("abc/bar.cpp", 42);
+  manager.addStatCache(statCache);
+
+  manager.getVirtualFile("abc/foo.cpp", 100, 0);
+  manager.getVirtualFile("abc/bar.cpp", 200, 0);
+
+  EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
+}
+
+#endif  // !LLVM_ON_WIN32
+
+} // anonymous namespace
diff --git a/unittests/FileManager/Makefile b/unittests/FileManager/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3851aa4f59cdf3422fa9c7b8a3bed1ee06adf8a8
--- /dev/null
+++ b/unittests/FileManager/Makefile
@@ -0,0 +1,15 @@
+##===- unittests/FileManager/Makefile ----------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = FileManager
+LINK_COMPONENTS := core support mc
+USEDLIBS = clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Makefile b/unittests/Makefile
index 685e397864a4ac54743006597b6ef19a4b863b5a..e8b4d55f3de4dcd3069f44e6e490a313bcac4288 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
 
 IS_UNITTEST_LEVEL := 1
 CLANG_LEVEL := ..
-PARALLEL_DIRS = Frontend
+PARALLEL_DIRS = FileManager Frontend
 
 endif  # CLANG_LEVEL