arphaman updated this revision to Diff 215718.
arphaman marked 8 inline comments as done.
arphaman added a comment.

Address review comments and proper `use-external-names` support.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D65907/new/

https://reviews.llvm.org/D65907

Files:
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Basic/SourceManager.h
  clang/include/clang/Lex/DirectoryLookup.h
  clang/include/clang/Lex/HeaderMap.h
  clang/include/clang/Lex/HeaderSearch.h
  clang/include/clang/Lex/Preprocessor.h
  clang/lib/Basic/FileManager.cpp
  clang/lib/Basic/SourceManager.cpp
  clang/lib/Frontend/CompilerInstance.cpp
  clang/lib/Frontend/DependencyFile.cpp
  clang/lib/Frontend/FrontendActions.cpp
  clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
  clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
  clang/lib/Lex/HeaderMap.cpp
  clang/lib/Lex/HeaderSearch.cpp
  clang/lib/Lex/HeaderSearch.cpp.rej
  clang/lib/Lex/PPDirectives.cpp
  clang/lib/Lex/PPMacroExpansion.cpp
  clang/lib/Lex/Pragma.cpp
  clang/lib/Lex/Preprocessor.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/test/VFS/external-names.c
  clang/unittests/Tooling/CMakeLists.txt
  clang/unittests/Tooling/DependencyScannerTest.cpp

Index: clang/unittests/Tooling/DependencyScannerTest.cpp
===================================================================
--- /dev/null
+++ clang/unittests/Tooling/DependencyScannerTest.cpp
@@ -0,0 +1,118 @@
+//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gtest/gtest.h"
+#include <algorithm>
+#include <string>
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Prints out all of the gathered dependencies into a string.
+class TestFileCollector : public DependencyFileGenerator {
+public:
+  TestFileCollector(DependencyOutputOptions &Opts,
+                    std::vector<std::string> &Deps)
+      : DependencyFileGenerator(Opts), Deps(Deps) {}
+
+  void finishedMainFile(DiagnosticsEngine &Diags) override {
+    Deps = getDependencies();
+  }
+
+private:
+  std::vector<std::string> &Deps;
+};
+
+class TestDependencyScanningAction : public tooling::ToolAction {
+public:
+  TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {}
+
+  bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
+                     FileManager *FileMgr,
+                     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+                     DiagnosticConsumer *DiagConsumer) override {
+    CompilerInstance Compiler(std::move(PCHContainerOps));
+    Compiler.setInvocation(std::move(Invocation));
+    Compiler.setFileManager(FileMgr);
+
+    Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
+    if (!Compiler.hasDiagnostics())
+      return false;
+
+    Compiler.createSourceManager(*FileMgr);
+    Compiler.addDependencyCollector(std::make_shared<TestFileCollector>(
+        Compiler.getInvocation().getDependencyOutputOpts(), Deps));
+
+    auto Action = std::make_unique<PreprocessOnlyAction>();
+    return Compiler.ExecuteAction(*Action);
+  }
+
+private:
+  std::vector<std::string> &Deps;
+};
+
+} // namespace
+
+TEST(DependencyScanner, ScanDepsReuseFilemanager) {
+  std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
+  StringRef CWD = "/root";
+  FixedCompilationDatabase CDB(CWD, Compilation);
+
+  auto VFS = new llvm::vfs::InMemoryFileSystem();
+  VFS->setCurrentWorkingDirectory(CWD);
+  VFS->addFile("/root/header.h", 0, llvm::MemoryBuffer::getMemBuffer("\n"));
+  VFS->addHardLink("/root/symlink.h", "/root/header.h");
+  VFS->addFile("/root/test.cpp", 0,
+               llvm::MemoryBuffer::getMemBuffer(
+                   "#include \"symlink.h\"\n#include \"header.h\"\n"));
+
+  ClangTool Tool(CDB, {"test.cpp"}, std::make_shared<PCHContainerOperations>(),
+                 VFS);
+  Tool.clearArgumentsAdjusters();
+  std::vector<std::string> Deps;
+  TestDependencyScanningAction Action(Deps);
+  Tool.run(&Action);
+  // The first invocation should return dependencies in order of access.
+  ASSERT_EQ(Deps.size(), 3u);
+  EXPECT_EQ(Deps[0], "/root/test.cpp");
+  EXPECT_EQ(Deps[1], "/root/symlink.h");
+  EXPECT_EQ(Deps[2], "/root/header.h");
+
+  // The file manager should still have two FileEntries, as one file is a
+  // hardlink.
+  FileManager &Files = Tool.getFiles();
+  EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
+
+  Deps.clear();
+  Tool.run(&Action);
+  // The second invocation should have the same order of dependencies.
+  ASSERT_EQ(Deps.size(), 3u);
+  EXPECT_EQ(Deps[0], "/root/test.cpp");
+  EXPECT_EQ(Deps[1], "/root/symlink.h");
+  EXPECT_EQ(Deps[2], "/root/header.h");
+
+  EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
+}
+
+} // end namespace tooling
+} // end namespace clang
Index: clang/unittests/Tooling/CMakeLists.txt
===================================================================
--- clang/unittests/Tooling/CMakeLists.txt
+++ clang/unittests/Tooling/CMakeLists.txt
@@ -15,6 +15,7 @@
   CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
+  DependencyScannerTest.cpp
   DiagnosticsYamlTest.cpp
   ExecutionTest.cpp
   FixItTest.cpp
Index: clang/test/VFS/external-names.c
===================================================================
--- clang/test/VFS/external-names.c
+++ clang/test/VFS/external-names.c
@@ -3,6 +3,9 @@
 // REQUIRES: shell
 
 #include "external-names.h"
+#ifdef REINCLUDE
+#include "external-names.h"
+#endif
 
 ////
 // Preprocessor (__FILE__ macro and # directives):
@@ -33,3 +36,16 @@
 
 // RUN: %clang_cc1 -I %t -ivfsoverlay %t.yaml -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-DEBUG %s
 // CHECK-DEBUG-NOT: Inputs
+
+////
+// Dependency file
+
+// RUN: %clang_cc1 -D REINCLUDE -I %t -ivfsoverlay %t.external.yaml -Eonly %s -MTfoo -dependency-file %t.external.dep
+// RUN: echo "EOF" >> %t.external.dep
+// RUN: cat %t.external.dep | FileCheck --check-prefix=CHECK-DEP-EXTERNAL %s
+// CHECK-DEP-EXTERNAL: Inputs{{.}}external-names.h
+// CHECK-DEP-EXTERNAL-NEXT: EOF
+
+// RUN: %clang_cc1 -D REINCLUDE -I %t -ivfsoverlay %t.yaml -Eonly %s -MTfoo -dependency-file %t.dep
+// RUN: cat %t.dep | FileCheck --check-prefix=CHECK-DEP %s
+// CHECK-DEP-NOT: Inputs
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -1842,6 +1842,7 @@
         Entry.IsTransient,
         Entry.IsTopLevelModuleMap};
 
+    // FIXME: The path should be taken from the FileEntryRef.
     EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
   }
 
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -1514,6 +1514,7 @@
     }
     SrcMgr::CharacteristicKind
       FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+    // FIXME: The FileID should be created from the FileEntryRef.
     FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
                                         ID, BaseOffset + Record[0]);
     SrcMgr::FileInfo &FileInfo =
Index: clang/lib/Lex/Preprocessor.cpp
===================================================================
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -563,7 +563,7 @@
     // Lookup and save the FileID for the through header. If it isn't found
     // in the search path, it's a fatal error.
     const DirectoryLookup *CurDir;
-    const FileEntry *File = LookupFile(
+    Optional<FileEntryRef> File = LookupFile(
         SourceLocation(), PPOpts->PCHThroughHeader,
         /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir,
         /*SearchPath=*/nullptr, /*RelativePath=*/nullptr,
@@ -575,7 +575,7 @@
       return;
     }
     setPCHThroughHeaderFileID(
-        SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User));
+        SourceMgr.createFileID(*File, SourceLocation(), SrcMgr::C_User));
   }
 
   // Skip tokens from the Predefines and if needed the main file.
Index: clang/lib/Lex/Pragma.cpp
===================================================================
--- clang/lib/Lex/Pragma.cpp
+++ clang/lib/Lex/Pragma.cpp
@@ -498,7 +498,7 @@
 
   // Search include directories for this file.
   const DirectoryLookup *CurDir;
-  const FileEntry *File =
+  Optional<FileEntryRef> File =
       LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
                  nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
   if (!File) {
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1210,19 +1210,21 @@
 
   // Search include directories.
   const DirectoryLookup *CurDir;
-  const FileEntry *File =
+  Optional<FileEntryRef> File =
       PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
                     CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
 
   if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
     SrcMgr::CharacteristicKind FileType = SrcMgr::C_User;
     if (File)
-      FileType = PP.getHeaderSearchInfo().getFileDirFlavor(File);
-    Callbacks->HasInclude(FilenameLoc, Filename, isAngled, File, FileType);
+      FileType =
+          PP.getHeaderSearchInfo().getFileDirFlavor(&File->getFileEntry());
+    Callbacks->HasInclude(FilenameLoc, Filename, isAngled,
+                          File ? &File->getFileEntry() : nullptr, FileType);
   }
 
   // Get the result value.  A result of true means the file exists.
-  return File != nullptr;
+  return File.hasValue();
 }
 
 /// EvaluateHasInclude - Process a '__has_include("path")' expression.
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -679,7 +679,7 @@
   return nullptr;
 }
 
-const FileEntry *Preprocessor::LookupFile(
+Optional<FileEntryRef> Preprocessor::LookupFile(
     SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
     const DirectoryLookup *FromDir, const FileEntry *FromFile,
     const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
@@ -740,7 +740,7 @@
     // the include path until we find that file or run out of files.
     const DirectoryLookup *TmpCurDir = CurDir;
     const DirectoryLookup *TmpFromDir = nullptr;
-    while (const FileEntry *FE = HeaderInfo.LookupFile(
+    while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
                Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
                Includers, SearchPath, RelativePath, RequestingModule,
                SuggestedModule, /*IsMapped=*/nullptr,
@@ -748,7 +748,7 @@
       // Keep looking as if this file did a #include_next.
       TmpFromDir = TmpCurDir;
       ++TmpFromDir;
-      if (FE == FromFile) {
+      if (&FE->getFileEntry() == FromFile) {
         // Found it.
         FromDir = TmpFromDir;
         CurDir = TmpCurDir;
@@ -758,7 +758,7 @@
   }
 
   // Do a standard file entry lookup.
-  const FileEntry *FE = HeaderInfo.LookupFile(
+  Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
       Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
       RelativePath, RequestingModule, SuggestedModule, IsMapped,
       IsFrameworkFound, SkipCache, BuildSystemModule);
@@ -766,7 +766,7 @@
     if (SuggestedModule && !LangOpts.AsmPreprocessor)
       HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
           RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc,
-          Filename, FE);
+          Filename, &FE->getFileEntry());
     return FE;
   }
 
@@ -776,14 +776,13 @@
   // headers on the #include stack and pass them to HeaderInfo.
   if (IsFileLexer()) {
     if ((CurFileEnt = CurPPLexer->getFileEntry())) {
-      if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
-                                                    SearchPath, RelativePath,
-                                                    RequestingModule,
-                                                    SuggestedModule))) {
+      if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
+              Filename, CurFileEnt, SearchPath, RelativePath, RequestingModule,
+              SuggestedModule)) {
         if (SuggestedModule && !LangOpts.AsmPreprocessor)
           HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
               RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc,
-              Filename, FE);
+              Filename, &FE->getFileEntry());
         return FE;
       }
     }
@@ -792,13 +791,13 @@
   for (IncludeStackInfo &ISEntry : llvm::reverse(IncludeMacroStack)) {
     if (IsFileLexer(ISEntry)) {
       if ((CurFileEnt = ISEntry.ThePPLexer->getFileEntry())) {
-        if ((FE = HeaderInfo.LookupSubframeworkHeader(
+        if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
                 Filename, CurFileEnt, SearchPath, RelativePath,
-                RequestingModule, SuggestedModule))) {
+                RequestingModule, SuggestedModule)) {
           if (SuggestedModule && !LangOpts.AsmPreprocessor)
             HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
                 RequestingModule, RequestingModuleIsModuleInterface,
-                FilenameLoc, Filename, FE);
+                FilenameLoc, Filename, &FE->getFileEntry());
           return FE;
         }
       }
@@ -806,7 +805,7 @@
   }
 
   // Otherwise, we really couldn't find the file.
-  return nullptr;
+  return None;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1676,6 +1675,130 @@
   }
 }
 
+Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
+    const DirectoryLookup *&CurDir, StringRef Filename,
+    SourceLocation FilenameLoc, CharSourceRange FilenameRange,
+    const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
+    bool &IsMapped, const DirectoryLookup *LookupFrom,
+    const FileEntry *LookupFromFile, SmallString<128> &NormalizedPath,
+    SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
+    ModuleMap::KnownHeader &SuggestedModule, bool isAngled) {
+  Optional<FileEntryRef> File = LookupFile(
+      FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
+      isAngled, LookupFrom, LookupFromFile, CurDir,
+      Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+      &SuggestedModule, &IsMapped, &IsFrameworkFound);
+  if (File)
+    return File;
+
+  if (Callbacks) {
+    // Give the clients a chance to recover.
+    SmallString<128> RecoveryPath;
+    if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
+      if (auto DE = FileMgr.getDirectory(RecoveryPath)) {
+        // Add the recovery path to the list of search paths.
+        DirectoryLookup DL(*DE, SrcMgr::C_User, false);
+        HeaderInfo.AddSearchPath(DL, isAngled);
+
+        // Try the lookup again, skipping the cache.
+        Optional<FileEntryRef> File = LookupFile(
+            FilenameLoc,
+            LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
+            LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
+            &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr,
+            /*SkipCache*/ true);
+        if (File)
+          return File;
+      }
+    }
+  }
+
+  if (SuppressIncludeNotFoundError)
+    return None;
+
+  // If the file could not be located and it was included via angle
+  // brackets, we can attempt a lookup as though it were a quoted path to
+  // provide the user with a possible fixit.
+  if (isAngled) {
+    Optional<FileEntryRef> File = LookupFile(
+        FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
+        false, LookupFrom, LookupFromFile, CurDir,
+        Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+        &SuggestedModule, &IsMapped,
+        /*IsFrameworkFound=*/nullptr);
+    if (File) {
+      Diag(FilenameTok, diag::err_pp_file_not_found_angled_include_not_fatal)
+          << Filename << IsImportDecl
+          << FixItHint::CreateReplacement(FilenameRange,
+                                          "\"" + Filename.str() + "\"");
+      return File;
+    }
+  }
+
+  // Check for likely typos due to leading or trailing non-isAlphanumeric
+  // characters
+  StringRef OriginalFilename = Filename;
+  if (LangOpts.SpellChecking) {
+    // A heuristic to correct a typo file name by removing leading and
+    // trailing non-isAlphanumeric characters.
+    auto CorrectTypoFilename = [](llvm::StringRef Filename) {
+      Filename = Filename.drop_until(isAlphanumeric);
+      while (!Filename.empty() && !isAlphanumeric(Filename.back())) {
+        Filename = Filename.drop_back();
+      }
+      return Filename;
+    };
+    StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
+    SmallString<128> NormalizedTypoCorrectionPath;
+    if (LangOpts.MSVCCompat) {
+      NormalizedTypoCorrectionPath = TypoCorrectionName.str();
+#ifndef _WIN32
+      llvm::sys::path::native(NormalizedTypoCorrectionPath);
+#endif
+    }
+    Optional<FileEntryRef> File = LookupFile(
+        FilenameLoc,
+        LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str()
+                            : TypoCorrectionName,
+        isAngled, LookupFrom, LookupFromFile, CurDir,
+        Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+        &SuggestedModule, &IsMapped,
+        /*IsFrameworkFound=*/nullptr);
+    if (File) {
+      auto Hint =
+          isAngled ? FixItHint::CreateReplacement(
+                         FilenameRange, "<" + TypoCorrectionName.str() + ">")
+                   : FixItHint::CreateReplacement(
+                         FilenameRange, "\"" + TypoCorrectionName.str() + "\"");
+      Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
+          << OriginalFilename << TypoCorrectionName << Hint;
+      // We found the file, so set the Filename to the name after typo
+      // correction.
+      Filename = TypoCorrectionName;
+      return File;
+    }
+  }
+
+  // If the file is still not found, just go with the vanilla diagnostic
+  assert(!File.hasValue() && "expected missing file");
+  Diag(FilenameTok, diag::err_pp_file_not_found)
+      << OriginalFilename << FilenameRange;
+  if (IsFrameworkFound) {
+    size_t SlashPos = OriginalFilename.find('/');
+    assert(SlashPos != StringRef::npos &&
+           "Include with framework name should have '/' in the filename");
+    StringRef FrameworkName = OriginalFilename.substr(0, SlashPos);
+    FrameworkCacheEntry &CacheEntry =
+        HeaderInfo.LookupFrameworkCache(FrameworkName);
+    assert(CacheEntry.Directory && "Found framework should be in cache");
+    Diag(FilenameTok, diag::note_pp_framework_without_header)
+        << OriginalFilename.substr(SlashPos + 1) << FrameworkName
+        << CacheEntry.Directory->getName();
+  }
+
+  return None;
+}
+
 /// Handle either a #include-like directive or an import declaration that names
 /// a header file.
 ///
@@ -1754,120 +1877,14 @@
     llvm::sys::path::native(NormalizedPath);
 #endif
   }
-  const FileEntry *File = LookupFile(
-      FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
-      isAngled, LookupFrom, LookupFromFile, CurDir,
-      Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
-      &SuggestedModule, &IsMapped, &IsFrameworkFound);
-
-  if (!File) {
-    if (Callbacks) {
-      // Give the clients a chance to recover.
-      SmallString<128> RecoveryPath;
-      if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
-        if (auto DE = FileMgr.getDirectory(RecoveryPath)) {
-          // Add the recovery path to the list of search paths.
-          DirectoryLookup DL(*DE, SrcMgr::C_User, false);
-          HeaderInfo.AddSearchPath(DL, isAngled);
-
-          // Try the lookup again, skipping the cache.
-          File = LookupFile(
-              FilenameLoc,
-              LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
-              LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
-              &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr,
-              /*SkipCache*/ true);
-        }
-      }
-    }
-
-    if (!SuppressIncludeNotFoundError) {
-      // If the file could not be located and it was included via angle
-      // brackets, we can attempt a lookup as though it were a quoted path to
-      // provide the user with a possible fixit.
-      if (isAngled) {
-        File = LookupFile(
-            FilenameLoc,
-            LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false,
-            LookupFrom, LookupFromFile, CurDir,
-            Callbacks ? &SearchPath : nullptr,
-            Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
-            /*IsFrameworkFound=*/nullptr);
-        if (File) {
-          Diag(FilenameTok,
-               diag::err_pp_file_not_found_angled_include_not_fatal)
-              << Filename << IsImportDecl
-              << FixItHint::CreateReplacement(FilenameRange,
-                                              "\"" + Filename.str() + "\"");
-        }
-      }
 
-      // Check for likely typos due to leading or trailing non-isAlphanumeric
-      // characters
-      StringRef OriginalFilename = Filename;
-      if (LangOpts.SpellChecking && !File) {
-        // A heuristic to correct a typo file name by removing leading and
-        // trailing non-isAlphanumeric characters.
-        auto CorrectTypoFilename = [](llvm::StringRef Filename) {
-          Filename = Filename.drop_until(isAlphanumeric);
-          while (!Filename.empty() && !isAlphanumeric(Filename.back())) {
-            Filename = Filename.drop_back();
-          }
-          return Filename;
-        };
-        StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
-        SmallString<128> NormalizedTypoCorrectionPath;
-        if (LangOpts.MSVCCompat) {
-          NormalizedTypoCorrectionPath = TypoCorrectionName.str();
-#ifndef _WIN32
-          llvm::sys::path::native(NormalizedTypoCorrectionPath);
-#endif
-        }
-        File = LookupFile(
-            FilenameLoc,
-            LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str()
-                                : TypoCorrectionName,
-            isAngled, LookupFrom, LookupFromFile, CurDir,
-            Callbacks ? &SearchPath : nullptr,
-            Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
-            /*IsFrameworkFound=*/nullptr);
-        if (File) {
-          auto Hint =
-              isAngled
-                  ? FixItHint::CreateReplacement(
-                        FilenameRange, "<" + TypoCorrectionName.str() + ">")
-                  : FixItHint::CreateReplacement(
-                        FilenameRange, "\"" + TypoCorrectionName.str() + "\"");
-          Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
-              << OriginalFilename << TypoCorrectionName << Hint;
-          // We found the file, so set the Filename to the name after typo
-          // correction.
-          Filename = TypoCorrectionName;
-        }
-      }
-
-      // If the file is still not found, just go with the vanilla diagnostic
-      if (!File) {
-        Diag(FilenameTok, diag::err_pp_file_not_found) << OriginalFilename
-                                                       << FilenameRange;
-        if (IsFrameworkFound) {
-          size_t SlashPos = OriginalFilename.find('/');
-          assert(SlashPos != StringRef::npos &&
-                 "Include with framework name should have '/' in the filename");
-          StringRef FrameworkName = OriginalFilename.substr(0, SlashPos);
-          FrameworkCacheEntry &CacheEntry =
-              HeaderInfo.LookupFrameworkCache(FrameworkName);
-          assert(CacheEntry.Directory && "Found framework should be in cache");
-          Diag(FilenameTok, diag::note_pp_framework_without_header)
-              << OriginalFilename.substr(SlashPos + 1) << FrameworkName
-              << CacheEntry.Directory->getName();
-        }
-      }
-    }
-  }
+  Optional<FileEntryRef> File = LookupHeaderIncludeOrImport(
+      CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok,
+      IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
+      NormalizedPath, RelativePath, SearchPath, SuggestedModule, isAngled);
 
   if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
-    if (isPCHThroughHeader(File))
+    if (File && isPCHThroughHeader(&File->getFileEntry()))
       SkippingUntilPCHThroughHeader = false;
     return {ImportAction::None};
   }
@@ -1878,7 +1895,8 @@
   // some directives (e.g. #endif of a header guard) will never be seen.
   // Since this will lead to confusing errors, avoid the inclusion.
   if (File && PreambleConditionalStack.isRecording() &&
-      SourceMgr.translateFile(File) == SourceMgr.getMainFileID()) {
+      SourceMgr.translateFile(&File->getFileEntry()) ==
+          SourceMgr.getMainFileID()) {
     Diag(FilenameTok.getLocation(),
          diag::err_pp_including_mainfile_in_preamble);
     return {ImportAction::None};
@@ -1897,7 +1915,7 @@
   // include cycle. Don't enter already processed files again as it can lead to
   // reaching the max allowed include depth again.
   if (Action == Enter && HasReachedMaxIncludeDepth && File &&
-      HeaderInfo.getFileInfo(File).NumIncludes)
+      HeaderInfo.getFileInfo(&File->getFileEntry()).NumIncludes)
     Action = IncludeLimitReached;
 
   // Determine whether we should try to import the module for this #include, if
@@ -1973,7 +1991,8 @@
   SrcMgr::CharacteristicKind FileCharacter =
       SourceMgr.getFileCharacteristic(FilenameTok.getLocation());
   if (File)
-    FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter);
+    FileCharacter = std::max(HeaderInfo.getFileDirFlavor(&File->getFileEntry()),
+                             FileCharacter);
 
   // If this is a '#import' or an import-declaration, don't re-enter the file.
   //
@@ -1987,8 +2006,8 @@
   // Ask HeaderInfo if we should enter this #include file.  If not, #including
   // this file will have no effect.
   if (Action == Enter && File &&
-      !HeaderInfo.ShouldEnterIncludeFile(*this, File, EnterOnce,
-                                         getLangOpts().Modules,
+      !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(),
+                                         EnterOnce, getLangOpts().Modules,
                                          SuggestedModule.getModule())) {
     // Even if we've already preprocessed this header once and know that we
     // don't need to see its contents again, we still need to import it if it's
@@ -2006,11 +2025,11 @@
     Callbacks->InclusionDirective(
         HashLoc, IncludeTok,
         LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
-        FilenameRange, File, SearchPath, RelativePath,
-        Action == Import ? SuggestedModule.getModule() : nullptr,
+        FilenameRange, File ? &File->getFileEntry() : nullptr, SearchPath,
+        RelativePath, Action == Import ? SuggestedModule.getModule() : nullptr,
         FileCharacter);
-    if (Action == Skip)
-      Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
+    if (Action == Skip && File)
+      Callbacks->FileSkipped(File->getFileEntry(), FilenameTok, FileCharacter);
   }
 
   if (!File)
@@ -2027,11 +2046,11 @@
   // Issue a diagnostic if the name of the file on disk has a different case
   // than the one we're about to open.
   const bool CheckIncludePathPortability =
-      !IsMapped && File && !File->tryGetRealPathName().empty();
+      !IsMapped && !File->getFileEntry().tryGetRealPathName().empty();
 
   if (CheckIncludePathPortability) {
     StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename;
-    StringRef RealPathName = File->tryGetRealPathName();
+    StringRef RealPathName = File->getFileEntry().tryGetRealPathName();
     SmallVector<StringRef, 16> Components(llvm::sys::path::begin(Name),
                                           llvm::sys::path::end(Name));
 
@@ -2102,7 +2121,7 @@
   // position on the file where it will be included and after the expansions.
   if (IncludePos.isMacroID())
     IncludePos = SourceMgr.getExpansionRange(IncludePos).getEnd();
-  FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter);
+  FileID FID = SourceMgr.createFileID(*File, IncludePos, FileCharacter);
   assert(FID.isValid() && "Expected valid file ID");
 
   // If all is good, enter the new file!
Index: clang/lib/Lex/HeaderSearch.cpp.rej
===================================================================
--- /dev/null
+++ clang/lib/Lex/HeaderSearch.cpp.rej
@@ -0,0 +1,75 @@
+***************
+*** 303,341 ****
+    return getHeaderMap()->getFileName();
+  }
+  
+- const FileEntry *HeaderSearch::getFileAndSuggestModule(
+      StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
+      bool IsSystemHeaderDir, Module *RequestingModule,
+      ModuleMap::KnownHeader *SuggestedModule) {
+    // If we have a module map that might map this header, load it and
+    // check whether we'll have a suggestion for a module.
+-   auto File = getFileMgr().getFile(FileName, /*OpenFile=*/true);
+    if (!File)
+-     return nullptr;
+  
+    // If there is a module that corresponds to this header, suggest it.
+-   if (!findUsableModuleForHeader(*File, Dir ? Dir : (*File)->getDir(),
+-                                  RequestingModule, SuggestedModule,
+-                                  IsSystemHeaderDir))
+-     return nullptr;
+  
+    return *File;
+  }
+  
+  /// LookupFile - Lookup the specified file in this search path, returning it
+  /// if it exists or returning null if not.
+- const FileEntry *DirectoryLookup::LookupFile(
+-     StringRef &Filename,
+-     HeaderSearch &HS,
+-     SourceLocation IncludeLoc,
+-     SmallVectorImpl<char> *SearchPath,
+-     SmallVectorImpl<char> *RelativePath,
+-     Module *RequestingModule,
+-     ModuleMap::KnownHeader *SuggestedModule,
+-     bool &InUserSpecifiedSystemFramework,
+-     bool &IsFrameworkFound,
+-     bool &HasBeenMapped,
+-     SmallVectorImpl<char> &MappedName) const {
+    InUserSpecifiedSystemFramework = false;
+    HasBeenMapped = false;
+  
+--- 303,335 ----
+    return getHeaderMap()->getFileName();
+  }
+  
++ Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
+      StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
+      bool IsSystemHeaderDir, Module *RequestingModule,
+      ModuleMap::KnownHeader *SuggestedModule) {
+    // If we have a module map that might map this header, load it and
+    // check whether we'll have a suggestion for a module.
++   auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
+    if (!File)
++     return None;
+  
+    // If there is a module that corresponds to this header, suggest it.
++   if (!findUsableModuleForHeader(
++           &File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
++           RequestingModule, SuggestedModule, IsSystemHeaderDir))
++     return None;
+  
+    return *File;
+  }
+  
+  /// LookupFile - Lookup the specified file in this search path, returning it
+  /// if it exists or returning null if not.
++ Optional<FileEntryRef> DirectoryLookup::LookupFile(
++     StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
++     SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
++     Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
++     bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
++     bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const {
+    InUserSpecifiedSystemFramework = false;
+    HasBeenMapped = false;
+  
Index: clang/lib/Lex/HeaderSearch.cpp
===================================================================
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -304,14 +304,13 @@
   return getHeaderMap()->getFileName();
 }
 
-const FileEntry *HeaderSearch::getFileAndSuggestModule(
+Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
     StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
     bool IsSystemHeaderDir, Module *RequestingModule,
     ModuleMap::KnownHeader *SuggestedModule) {
   // If we have a module map that might map this header, load it and
   // check whether we'll have a suggestion for a module.
-  llvm::ErrorOr<const FileEntry *> File =
-      getFileMgr().getFile(FileName, /*OpenFile=*/true);
+  auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
   if (!File) {
     // For rare, surprising errors (e.g. "out of file handles"), diag the EC
     // message.
@@ -322,32 +321,26 @@
       Diags.Report(IncludeLoc, diag::err_cannot_open_file)
           << FileName << EC.message();
     }
-    return nullptr;
+    return None;
   }
 
   // If there is a module that corresponds to this header, suggest it.
-  if (!findUsableModuleForHeader(*File, Dir ? Dir : (*File)->getDir(),
-                                 RequestingModule, SuggestedModule,
-                                 IsSystemHeaderDir))
-    return nullptr;
+  if (!findUsableModuleForHeader(
+          &File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
+          RequestingModule, SuggestedModule, IsSystemHeaderDir))
+    return None;
 
   return *File;
 }
 
 /// LookupFile - Lookup the specified file in this search path, returning it
 /// if it exists or returning null if not.
-const FileEntry *DirectoryLookup::LookupFile(
-    StringRef &Filename,
-    HeaderSearch &HS,
-    SourceLocation IncludeLoc,
-    SmallVectorImpl<char> *SearchPath,
-    SmallVectorImpl<char> *RelativePath,
-    Module *RequestingModule,
-    ModuleMap::KnownHeader *SuggestedModule,
-    bool &InUserSpecifiedSystemFramework,
-    bool &IsFrameworkFound,
-    bool &HasBeenMapped,
-    SmallVectorImpl<char> &MappedName) const {
+Optional<FileEntryRef> DirectoryLookup::LookupFile(
+    StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
+    SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+    Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
+    bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
+    bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const {
   InUserSpecifiedSystemFramework = false;
   HasBeenMapped = false;
 
@@ -381,9 +374,19 @@
   SmallString<1024> Path;
   StringRef Dest = HM->lookupFilename(Filename, Path);
   if (Dest.empty())
-    return nullptr;
+    return None;
 
-  const FileEntry *Result;
+  auto FixupSearchPath = [&]() {
+    if (SearchPath) {
+      StringRef SearchPathRef(getName());
+      SearchPath->clear();
+      SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+    }
+    if (RelativePath) {
+      RelativePath->clear();
+      RelativePath->append(Filename.begin(), Filename.end());
+    }
+  };
 
   // Check if the headermap maps the filename to a framework include
   // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
@@ -393,25 +396,17 @@
     MappedName.append(Dest.begin(), Dest.end());
     Filename = StringRef(MappedName.begin(), MappedName.size());
     HasBeenMapped = true;
-    Result = HM->LookupFile(Filename, HS.getFileMgr());
-  } else if (auto Res = HS.getFileMgr().getFile(Dest)) {
-    Result = *Res;
-  } else {
-    Result = nullptr;
-  }
-
-  if (Result) {
-    if (SearchPath) {
-      StringRef SearchPathRef(getName());
-      SearchPath->clear();
-      SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
-    }
-    if (RelativePath) {
-      RelativePath->clear();
-      RelativePath->append(Filename.begin(), Filename.end());
+    Optional<FileEntryRef> Result = HM->LookupFile(Filename, HS.getFileMgr());
+    if (Result) {
+      FixupSearchPath();
+      return *Result;
     }
+  } else if (auto Res = HS.getFileMgr().getFileRef(Dest)) {
+    FixupSearchPath();
+    return *Res;
   }
-  return Result;
+
+  return None;
 }
 
 /// Given a framework directory, find the top-most framework directory.
@@ -476,7 +471,7 @@
 
 /// DoFrameworkLookup - Do a lookup of the specified file in the current
 /// DirectoryLookup, which is a framework directory.
-const FileEntry *DirectoryLookup::DoFrameworkLookup(
+Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
     StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
     SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
     ModuleMap::KnownHeader *SuggestedModule,
@@ -485,7 +480,8 @@
 
   // Framework names must have a '/' in the filename.
   size_t SlashPos = Filename.find('/');
-  if (SlashPos == StringRef::npos) return nullptr;
+  if (SlashPos == StringRef::npos)
+    return None;
 
   // Find out if this is the home for the specified framework, by checking
   // HeaderSearch.  Possible answers are yes/no and unknown.
@@ -494,7 +490,7 @@
 
   // If it is known and in some other directory, fail.
   if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
-    return nullptr;
+    return None;
 
   // Otherwise, construct the path to this framework dir.
 
@@ -517,7 +513,8 @@
 
     // If the framework dir doesn't exist, we fail.
     auto Dir = FileMgr.getDirectory(FrameworkName);
-    if (!Dir) return nullptr;
+    if (!Dir)
+      return None;
 
     // Otherwise, if it does, remember that this is the right direntry for this
     // framework.
@@ -556,11 +553,10 @@
 
   FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
 
-  const FileEntry *FE = nullptr;
-  if (auto File = FileMgr.getFile(FrameworkName, /*OpenFile=*/!SuggestedModule))
-    FE = *File;
+  llvm::ErrorOr<FileEntryRef> File =
+      FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
 
-  if (!FE) {
+  if (!File) {
     // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
     const char *Private = "Private";
     FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
@@ -569,15 +565,13 @@
       SearchPath->insert(SearchPath->begin()+OrigSize, Private,
                          Private+strlen(Private));
 
-    if (auto File = FileMgr.getFile(FrameworkName, 
-                                    /*OpenFile=*/!SuggestedModule))
-      FE = *File;
+    File = FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
   }
 
   // If we found the header and are allowed to suggest a module, do so now.
-  if (FE && needModuleLookup(RequestingModule, SuggestedModule)) {
+  if (File && needModuleLookup(RequestingModule, SuggestedModule)) {
     // Find the framework in which this header occurs.
-    StringRef FrameworkPath = FE->getDir()->getName();
+    StringRef FrameworkPath = File->getFileEntry().getDir()->getName();
     bool FoundFramework = false;
     do {
       // Determine whether this directory exists.
@@ -601,15 +595,19 @@
     bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
     if (FoundFramework) {
       if (!HS.findUsableModuleForFrameworkHeader(
-              FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
-        return nullptr;
+              &File->getFileEntry(), FrameworkPath, RequestingModule,
+              SuggestedModule, IsSystem))
+        return None;
     } else {
-      if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
-                                        SuggestedModule, IsSystem))
-        return nullptr;
+      if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(),
+                                        RequestingModule, SuggestedModule,
+                                        IsSystem))
+        return None;
     }
   }
-  return FE;
+  if (File)
+    return *File;
+  return None;
 }
 
 void HeaderSearch::setTarget(const TargetInfo &Target) {
@@ -714,7 +712,7 @@
 /// for system \#include's or not (i.e. using <> instead of ""). Includers, if
 /// non-empty, indicates where the \#including file(s) are, in case a relative
 /// search is needed. Microsoft mode will pass all \#including files.
-const FileEntry *HeaderSearch::LookupFile(
+Optional<FileEntryRef> HeaderSearch::LookupFile(
     StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
     const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
     ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
@@ -736,7 +734,8 @@
     CurDir = nullptr;
 
     // If this was an #include_next "/absolute/file", fail.
-    if (FromDir) return nullptr;
+    if (FromDir)
+      return None;
 
     if (SearchPath)
       SearchPath->clear();
@@ -751,8 +750,9 @@
   }
 
   // This is the header that MSVC's header search would have found.
-  const FileEntry *MSFE = nullptr;
   ModuleMap::KnownHeader MSSuggestedModule;
+  const FileEntry *MSFE_FE = nullptr;
+  StringRef MSFE_Name;
 
   // Unless disabled, check to see if the file is in the #includer's
   // directory.  This cannot be based on CurDir, because each includer could be
@@ -781,7 +781,7 @@
       bool IncluderIsSystemHeader =
           Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
           BuildSystemModule;
-      if (const FileEntry *FE = getFileAndSuggestModule(
+      if (Optional<FileEntryRef> FE = getFileAndSuggestModule(
               TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
               RequestingModule, SuggestedModule)) {
         if (!Includer) {
@@ -800,7 +800,7 @@
         bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
         StringRef Framework = FromHFI.Framework;
 
-        HeaderFileInfo &ToHFI = getFileInfo(FE);
+        HeaderFileInfo &ToHFI = getFileInfo(&FE->getFileEntry());
         ToHFI.DirInfo = DirInfo;
         ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
         ToHFI.Framework = Framework;
@@ -817,7 +817,7 @@
         if (First) {
           diagnoseFrameworkInclude(Diags, IncludeLoc,
                                    IncluderAndDir.second->getName(), Filename,
-                                   FE);
+                                   &FE->getFileEntry());
           return FE;
         }
 
@@ -827,7 +827,8 @@
         if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
           return FE;
         } else {
-          MSFE = FE;
+          MSFE_FE = &FE->getFileEntry();
+          MSFE_Name = FE->getName();
           if (SuggestedModule) {
             MSSuggestedModule = *SuggestedModule;
             *SuggestedModule = ModuleMap::KnownHeader();
@@ -839,6 +840,9 @@
     }
   }
 
+  Optional<FileEntryRef> MSFE(MSFE_FE ? FileEntryRef(MSFE_Name, *MSFE_FE)
+                                      : Optional<FileEntryRef>());
+
   CurDir = nullptr;
 
   // If this is a system #include, ignore the user #include locs.
@@ -880,7 +884,7 @@
     bool InUserSpecifiedSystemFramework = false;
     bool HasBeenMapped = false;
     bool IsFrameworkFoundInDir = false;
-    const FileEntry *FE = SearchDirs[i].LookupFile(
+    Optional<FileEntryRef> File = SearchDirs[i].LookupFile(
         Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
         SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
         HasBeenMapped, MappedName);
@@ -895,12 +899,13 @@
       // lookups, ignore IsFrameworkFoundInDir after the first remapping and not
       // just for remapping in a current search directory.
       *IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName);
-    if (!FE) continue;
+    if (!File)
+      continue;
 
     CurDir = &SearchDirs[i];
 
     // This file is a system header or C++ unfriendly if the dir is.
-    HeaderFileInfo &HFI = getFileInfo(FE);
+    HeaderFileInfo &HFI = getFileInfo(&File->getFileEntry());
     HFI.DirInfo = CurDir->getDirCharacteristic();
 
     // If the directory characteristic is User but this framework was
@@ -930,7 +935,8 @@
       }
     }
 
-    if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+    if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+                              &File->getFileEntry(), IncludeLoc)) {
       if (SuggestedModule)
         *SuggestedModule = MSSuggestedModule;
       return MSFE;
@@ -938,13 +944,13 @@
 
     bool FoundByHeaderMap = !IsMapped ? false : *IsMapped;
     if (!Includers.empty())
-      diagnoseFrameworkInclude(Diags, IncludeLoc,
-                               Includers.front().second->getName(), Filename,
-                               FE, isAngled, FoundByHeaderMap);
+      diagnoseFrameworkInclude(
+          Diags, IncludeLoc, Includers.front().second->getName(), Filename,
+          &File->getFileEntry(), isAngled, FoundByHeaderMap);
 
     // Remember this location for the next lookup we do.
     CacheLookup.HitIdx = i;
-    return FE;
+    return File;
   }
 
   // If we are including a file with a quoted include "foo.h" from inside
@@ -960,12 +966,14 @@
       ScratchFilename += '/';
       ScratchFilename += Filename;
 
-      const FileEntry *FE = LookupFile(
+      Optional<FileEntryRef> File = LookupFile(
           ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
           Includers.front(), SearchPath, RelativePath, RequestingModule,
           SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
 
-      if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+      if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+                                File ? &File->getFileEntry() : nullptr,
+                                IncludeLoc)) {
         if (SuggestedModule)
           *SuggestedModule = MSSuggestedModule;
         return MSFE;
@@ -974,11 +982,12 @@
       LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
       CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx;
       // FIXME: SuggestedModule.
-      return FE;
+      return File;
     }
   }
 
-  if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
+  if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+                            nullptr, IncludeLoc)) {
     if (SuggestedModule)
       *SuggestedModule = MSSuggestedModule;
     return MSFE;
@@ -986,7 +995,7 @@
 
   // Otherwise, didn't find it. Remember we didn't find this.
   CacheLookup.HitIdx = SearchDirs.size();
-  return nullptr;
+  return None;
 }
 
 /// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -994,19 +1003,17 @@
 /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
 /// is a subframework within Carbon.framework.  If so, return the FileEntry
 /// for the designated file, otherwise return null.
-const FileEntry *HeaderSearch::
-LookupSubframeworkHeader(StringRef Filename,
-                         const FileEntry *ContextFileEnt,
-                         SmallVectorImpl<char> *SearchPath,
-                         SmallVectorImpl<char> *RelativePath,
-                         Module *RequestingModule,
-                         ModuleMap::KnownHeader *SuggestedModule) {
+Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
+    StringRef Filename, const FileEntry *ContextFileEnt,
+    SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+    Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
   assert(ContextFileEnt && "No context file?");
 
   // Framework names must have a '/' in the filename.  Find it.
   // FIXME: Should we permit '\' on Windows?
   size_t SlashPos = Filename.find('/');
-  if (SlashPos == StringRef::npos) return nullptr;
+  if (SlashPos == StringRef::npos)
+    return None;
 
   // Look up the base framework name of the ContextFileEnt.
   StringRef ContextName = ContextFileEnt->getName();
@@ -1017,7 +1024,7 @@
   if (FrameworkPos == StringRef::npos ||
       (ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
        ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
-    return nullptr;
+    return None;
 
   SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
                                                           FrameworkPos +
@@ -1037,7 +1044,7 @@
       CacheLookup.first().size() == FrameworkName.size() &&
       memcmp(CacheLookup.first().data(), &FrameworkName[0],
              CacheLookup.first().size()) != 0)
-    return nullptr;
+    return None;
 
   // Cache subframework.
   if (!CacheLookup.second.Directory) {
@@ -1045,14 +1052,14 @@
 
     // If the framework dir doesn't exist, we fail.
     auto Dir = FileMgr.getDirectory(FrameworkName);
-    if (!Dir) return nullptr;
+    if (!Dir)
+      return None;
 
     // Otherwise, if it does, remember that this is the right direntry for this
     // framework.
     CacheLookup.second.Directory = *Dir;
   }
 
-  const FileEntry *FE = nullptr;
 
   if (RelativePath) {
     RelativePath->clear();
@@ -1069,10 +1076,10 @@
   }
 
   HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-  if (auto File = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true))
-    FE = *File;
+  llvm::ErrorOr<FileEntryRef> File =
+      FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true);
 
-  if (!FE) {
+  if (!File) {
     // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
     HeadersFilename = FrameworkName;
     HeadersFilename += "PrivateHeaders/";
@@ -1083,11 +1090,10 @@
     }
 
     HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-    if (auto File = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true))
-      FE = *File;
-  
-    if (!FE)
-      return nullptr;
+    File = FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true);
+
+    if (!File)
+      return None;
   }
 
   // This file is a system header or C++ unfriendly if the old file is.
@@ -1096,14 +1102,15 @@
   // getFileInfo could resize the vector and we don't want to rely on order
   // of evaluation.
   unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
-  getFileInfo(FE).DirInfo = DirInfo;
+  getFileInfo(&File->getFileEntry()).DirInfo = DirInfo;
 
   FrameworkName.pop_back(); // remove the trailing '/'
-  if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
-                                          SuggestedModule, /*IsSystem*/ false))
-    return nullptr;
+  if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName,
+                                          RequestingModule, SuggestedModule,
+                                          /*IsSystem*/ false))
+    return None;
 
-  return FE;
+  return *File;
 }
 
 //===----------------------------------------------------------------------===//
Index: clang/lib/Lex/HeaderMap.cpp
===================================================================
--- clang/lib/Lex/HeaderMap.cpp
+++ clang/lib/Lex/HeaderMap.cpp
@@ -196,17 +196,17 @@
 
 /// LookupFile - Check to see if the specified relative filename is located in
 /// this HeaderMap.  If so, open it and return its FileEntry.
-const FileEntry *HeaderMap::LookupFile(
-    StringRef Filename, FileManager &FM) const {
+Optional<FileEntryRef> HeaderMap::LookupFile(StringRef Filename,
+                                             FileManager &FM) const {
 
   SmallString<1024> Path;
   StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
   if (Dest.empty())
-    return nullptr;
+    return None;
 
-  if (auto File = FM.getFile(Dest))
+  if (auto File = FM.getFileRef(Dest))
     return *File;
-  return nullptr;
+  return None;
 }
 
 StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
Index: clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
===================================================================
--- clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -528,15 +528,16 @@
 
         // Lookup file via Preprocessor, like a #include.
         const DirectoryLookup *CurDir;
-        const FileEntry *FE =
+        Optional<FileEntryRef> File =
             PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
                            nullptr, nullptr, nullptr, nullptr, nullptr);
-        if (!FE) {
+        if (!File) {
           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
                        diag::err_verify_missing_file) << Filename << KindStr;
           continue;
         }
 
+        const FileEntry *FE = &File->getFileEntry();
         if (SM.translateFile(FE).isInvalid())
           SM.createFileID(FE, Pos, SrcMgr::C_User);
 
Index: clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
===================================================================
--- clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -412,11 +412,11 @@
       Includers;
   Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
   // FIXME: Why don't we call PP.LookupFile here?
-  const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
+  Optional<FileEntryRef> File = PP.getHeaderSearchInfo().LookupFile(
       Filename, SourceLocation(), isAngled, Lookup, CurDir, Includers, nullptr,
       nullptr, nullptr, nullptr, nullptr, nullptr);
 
-  FileExists = File != nullptr;
+  FileExists = File.hasValue();
   return true;
 }
 
Index: clang/lib/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/Frontend/FrontendActions.cpp
+++ clang/lib/Frontend/FrontendActions.cpp
@@ -287,15 +287,15 @@
   SmallVector<Module::Header, 16> Headers;
   for (StringRef Name : ModuleHeaders) {
     const DirectoryLookup *CurDir = nullptr;
-    const FileEntry *FE = HS.LookupFile(
-        Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir,
-        None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+    Optional<FileEntryRef> FE = HS.LookupFile(
+        Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None,
+        nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
     if (!FE) {
       CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
         << Name;
       continue;
     }
-    Headers.push_back({Name, FE});
+    Headers.push_back({Name, &FE->getFileEntry()});
   }
   HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
 
Index: clang/lib/Frontend/DependencyFile.cpp
===================================================================
--- clang/lib/Frontend/DependencyFile.cpp
+++ clang/lib/Frontend/DependencyFile.cpp
@@ -46,13 +46,13 @@
     // Dependency generation really does want to go all the way to the
     // file entry for a source location to find out what is depended on.
     // We do not want #line markers to affect dependency generation!
-    const FileEntry *FE =
-        SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
-    if (!FE)
+    Optional<FileEntryRef> File =
+        SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+    if (!File)
       return;
 
     StringRef Filename =
-        llvm::sys::path::remove_leading_dotslash(FE->getName());
+        llvm::sys::path::remove_leading_dotslash(File->getName());
 
     DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
                                     isSystem(FileType),
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -831,33 +831,37 @@
 
   // Figure out where to get and map in the main file.
   if (InputFile != "-") {
-    auto FileOrErr = FileMgr.getFile(InputFile, /*OpenFile=*/true);
+    auto FileOrErr = FileMgr.getFileRef(InputFile, /*OpenFile=*/true);
     if (!FileOrErr) {
       Diags.Report(diag::err_fe_error_reading) << InputFile;
       return false;
     }
-    auto File = *FileOrErr;
+    FileEntryRef File = *FileOrErr;
 
     // The natural SourceManager infrastructure can't currently handle named
     // pipes, but we would at least like to accept them for the main
     // file. Detect them here, read them with the volatile flag so FileMgr will
     // pick up the correct size, and simply override their contents as we do for
     // STDIN.
-    if (File->isNamedPipe()) {
-      auto MB = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
+    if (File.getFileEntry().isNamedPipe()) {
+      auto MB =
+          FileMgr.getBufferForFile(&File.getFileEntry(), /*isVolatile=*/true);
       if (MB) {
         // Create a new virtual file that will have the correct size.
-        File = FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
-        SourceMgr.overrideFileContents(File, std::move(*MB));
+        const FileEntry *FE =
+            FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
+        SourceMgr.overrideFileContents(FE, std::move(*MB));
+        SourceMgr.setMainFileID(
+            SourceMgr.createFileID(FE, SourceLocation(), Kind));
       } else {
         Diags.Report(diag::err_cannot_open_file) << InputFile
                                                  << MB.getError().message();
         return false;
       }
+    } else {
+      SourceMgr.setMainFileID(
+          SourceMgr.createFileID(File, SourceLocation(), Kind));
     }
-
-    SourceMgr.setMainFileID(
-        SourceMgr.createFileID(File, SourceLocation(), Kind));
   } else {
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr =
         llvm::MemoryBuffer::getSTDIN();
Index: clang/lib/Basic/SourceManager.cpp
===================================================================
--- clang/lib/Basic/SourceManager.cpp
+++ clang/lib/Basic/SourceManager.cpp
@@ -466,10 +466,9 @@
     // If the file of the SLocEntry changed we could still have loaded it.
     if (!SLocEntryLoaded[Index]) {
       // Try to recover; create a SLocEntry so the rest of clang can handle it.
-      LoadedSLocEntryTable[Index] = SLocEntry::get(0,
-                                 FileInfo::get(SourceLocation(),
-                                               getFakeContentCacheForRecovery(),
-                                               SrcMgr::C_User));
+      LoadedSLocEntryTable[Index] = SLocEntry::get(
+          0, FileInfo::get(SourceLocation(), getFakeContentCacheForRecovery(),
+                           SrcMgr::C_User, ""));
     }
   }
 
@@ -556,7 +555,7 @@
 /// createFileID - Create a new FileID for the specified ContentCache and
 /// include position.  This works regardless of whether the ContentCache
 /// corresponds to a file or some other input source.
-FileID SourceManager::createFileID(const ContentCache *File,
+FileID SourceManager::createFileID(const ContentCache *File, StringRef Filename,
                                    SourceLocation IncludePos,
                                    SrcMgr::CharacteristicKind FileCharacter,
                                    int LoadedID, unsigned LoadedOffset) {
@@ -565,14 +564,14 @@
     unsigned Index = unsigned(-LoadedID) - 2;
     assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
     assert(!SLocEntryLoaded[Index] && "FileID already loaded");
-    LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset,
-        FileInfo::get(IncludePos, File, FileCharacter));
+    LoadedSLocEntryTable[Index] = SLocEntry::get(
+        LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename));
     SLocEntryLoaded[Index] = true;
     return FileID::get(LoadedID);
   }
-  LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset,
-                                               FileInfo::get(IncludePos, File,
-                                                             FileCharacter)));
+  LocalSLocEntryTable.push_back(
+      SLocEntry::get(NextLocalOffset,
+                     FileInfo::get(IncludePos, File, FileCharacter, Filename)));
   unsigned FileSize = File->getSize();
   assert(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
          NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset &&
Index: clang/lib/Basic/FileManager.cpp
===================================================================
--- clang/lib/Basic/FileManager.cpp
+++ clang/lib/Basic/FileManager.cpp
@@ -184,13 +184,30 @@
 
 llvm::ErrorOr<const FileEntry *>
 FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
+  auto Result = getFileRef(Filename, openFile, CacheFailure);
+  if (Result)
+    return &Result->getFileEntry();
+  return Result.getError();
+}
+
+llvm::ErrorOr<FileEntryRef>
+FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
   ++NumFileLookups;
 
   // See if there is already an entry in the map.
   auto SeenFileInsertResult =
       SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory});
-  if (!SeenFileInsertResult.second)
-    return promoteInnerReference(SeenFileInsertResult.first->second);
+  if (!SeenFileInsertResult.second) {
+    if (!SeenFileInsertResult.first->second)
+      return SeenFileInsertResult.first->second.getError();
+    // Construct and return and FileEntryRef, unless it's a redirect to another
+    // filename.
+    SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second;
+    FileEntry *FE;
+    if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
+      return FileEntryRef(SeenFileInsertResult.first->first(), *FE);
+    return getFileRef(*Value.get<const StringRef *>(), openFile, CacheFailure);
+  }
 
   // We've not seen this before. Fill it in.
   ++NumFileCacheMisses;
@@ -241,16 +258,20 @@
   // This occurs when one dir is symlinked to another, for example.
   FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
 
-  NamedFileEnt.second = UFE;
+  NamedFileEnt.second = &UFE;
 
   // If the name returned by getStatValue is different than Filename, re-intern
   // the name.
   if (Status.getName() != Filename) {
     auto &NamedFileEnt =
-      *SeenFileEntries.insert({Status.getName(), UFE}).first;
-    assert(&*NamedFileEnt.second == &UFE &&
+        *SeenFileEntries.insert({Status.getName(), &UFE}).first;
+    assert((*NamedFileEnt.second).get<FileEntry *>() == &UFE &&
            "filename from getStatValue() refers to wrong file");
     InterndFileName = NamedFileEnt.first().data();
+    // In addition to re-interning the name, construct a redirecting seen file
+    // entry, that will point to the name the filesystem actually wants to use.
+    StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName);
+    SeenFileInsertResult.first->second = Redirect;
   }
 
   if (UFE.isValid()) { // Already have an entry with this inode, return it.
@@ -269,9 +290,11 @@
     // to switch towards a design where we return a FileName object that
     // encapsulates both the name by which the file was accessed and the
     // corresponding FileEntry.
+    // FIXME: The Name should be removed from FileEntry once all clients
+    // adopt FileEntryRef.
     UFE.Name = InterndFileName;
 
-    return &UFE;
+    return FileEntryRef(InterndFileName, UFE);
   }
 
   // Otherwise, we don't have this file yet, add it.
@@ -292,7 +315,7 @@
     // We should still fill the path even if we aren't opening the file.
     fillRealPathName(&UFE, InterndFileName);
   }
-  return &UFE;
+  return FileEntryRef(InterndFileName, UFE);
 }
 
 const FileEntry *
@@ -303,8 +326,14 @@
   // See if there is already an entry in the map for an existing file.
   auto &NamedFileEnt = *SeenFileEntries.insert(
       {Filename, std::errc::no_such_file_or_directory}).first;
-  if (NamedFileEnt.second)
-    return &*NamedFileEnt.second;
+  if (NamedFileEnt.second) {
+    SeenFileEntryOrRedirect Value = *NamedFileEnt.second;
+    FileEntry *FE;
+    if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
+      return FE;
+    return getVirtualFile(*Value.get<const StringRef *>(), Size,
+                          ModificationTime);
+  }
 
   // We've not seen this before, or the file is cached as non-existent.
   ++NumFileCacheMisses;
@@ -329,7 +358,7 @@
       Status.getUser(), Status.getGroup(), Size,
       Status.getType(), Status.getPermissions());
 
-    NamedFileEnt.second = *UFE;
+    NamedFileEnt.second = 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
@@ -347,7 +376,7 @@
   } else {
     VirtualFileEntries.push_back(std::make_unique<FileEntry>());
     UFE = VirtualFileEntries.back().get();
-    NamedFileEnt.second = *UFE;
+    NamedFileEnt.second = UFE;
   }
 
   UFE->Name    = InterndFileName;
@@ -493,12 +522,14 @@
   UIDToFiles.resize(NextFileUID);
 
   // Map file entries
-  for (llvm::StringMap<llvm::ErrorOr<FileEntry &>,
+  for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
                        llvm::BumpPtrAllocator>::const_iterator
-         FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
+           FE = SeenFileEntries.begin(),
+           FEEnd = SeenFileEntries.end();
        FE != FEEnd; ++FE)
-    if (auto Entry = FE->getValue()) {
-      UIDToFiles[Entry->getUID()] = &*Entry;
+    if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) {
+      if (const auto *FE = (*Entry).dyn_cast<FileEntry *>())
+        UIDToFiles[FE->getUID()] = FE;
     }
 
   // Map virtual file entries
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -1949,17 +1949,15 @@
 
   /// Given a "foo" or \<foo> reference, look up the indicated file.
   ///
-  /// Returns null on failure.  \p isAngled indicates whether the file
+  /// Returns None on failure.  \p isAngled indicates whether the file
   /// reference is for system \#include's or not (i.e. using <> instead of "").
-  const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename,
-                              bool isAngled, const DirectoryLookup *FromDir,
-                              const FileEntry *FromFile,
-                              const DirectoryLookup *&CurDir,
-                              SmallVectorImpl<char> *SearchPath,
-                              SmallVectorImpl<char> *RelativePath,
-                              ModuleMap::KnownHeader *SuggestedModule,
-                              bool *IsMapped, bool *IsFrameworkFound,
-                              bool SkipCache = false);
+  Optional<FileEntryRef>
+  LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
+             const DirectoryLookup *FromDir, const FileEntry *FromFile,
+             const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
+             SmallVectorImpl<char> *RelativePath,
+             ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped,
+             bool *IsFrameworkFound, bool SkipCache = false);
 
   /// Get the DirectoryLookup structure used to find the current
   /// FileEntry, if CurLexer is non-null and if applicable.
@@ -2202,6 +2200,15 @@
     }
   };
 
+  Optional<FileEntryRef> LookupHeaderIncludeOrImport(
+      const DirectoryLookup *&CurDir, StringRef Filename,
+      SourceLocation FilenameLoc, CharSourceRange FilenameRange,
+      const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
+      bool &IsMapped, const DirectoryLookup *LookupFrom,
+      const FileEntry *LookupFromFile, SmallString<128> &NormalizedPath,
+      SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
+      ModuleMap::KnownHeader &SuggestedModule, bool isAngled);
+
   // File inclusion.
   void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok,
                               const DirectoryLookup *LookupFrom = nullptr,
Index: clang/include/clang/Lex/HeaderSearch.h
===================================================================
--- clang/include/clang/Lex/HeaderSearch.h
+++ clang/include/clang/Lex/HeaderSearch.h
@@ -395,7 +395,7 @@
   /// found in any of searched SearchDirs. Will be set to false if a framework
   /// is found only through header maps. Doesn't guarantee the requested file is
   /// found.
-  const FileEntry *LookupFile(
+  Optional<FileEntryRef> LookupFile(
       StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
       const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
       ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
@@ -410,7 +410,7 @@
   /// within ".../Carbon.framework/Headers/Carbon.h", check to see if
   /// HIToolbox is a subframework within Carbon.framework.  If so, return
   /// the FileEntry for the designated file, otherwise return null.
-  const FileEntry *LookupSubframeworkHeader(
+  Optional<FileEntryRef> LookupSubframeworkHeader(
       StringRef Filename, const FileEntry *ContextFileEnt,
       SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
       Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule);
@@ -649,7 +649,7 @@
 
   /// Look up the file with the specified name and determine its owning
   /// module.
-  const FileEntry *
+  Optional<FileEntryRef>
   getFileAndSuggestModule(StringRef FileName, SourceLocation IncludeLoc,
                           const DirectoryEntry *Dir, bool IsSystemHeaderDir,
                           Module *RequestingModule,
Index: clang/include/clang/Lex/HeaderMap.h
===================================================================
--- clang/include/clang/Lex/HeaderMap.h
+++ clang/include/clang/Lex/HeaderMap.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_LEX_HEADERMAP_H
 #define LLVM_CLANG_LEX_HEADERMAP_H
 
+#include "clang/Basic/FileManager.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/Compiler.h"
@@ -21,8 +22,6 @@
 
 namespace clang {
 
-class FileEntry;
-class FileManager;
 struct HMapBucket;
 struct HMapHeader;
 
@@ -78,7 +77,7 @@
   /// NULL and the file is found, RawPath will be set to the raw path at which
   /// the file was found in the file system. For example, for a search path
   /// ".." and a filename "../file.h" this would be "../../file.h".
-  const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const;
+  Optional<FileEntryRef> LookupFile(StringRef Filename, FileManager &FM) const;
 
   using HeaderMapImpl::lookupFilename;
   using HeaderMapImpl::getFileName;
Index: clang/include/clang/Lex/DirectoryLookup.h
===================================================================
--- clang/include/clang/Lex/DirectoryLookup.h
+++ clang/include/clang/Lex/DirectoryLookup.h
@@ -176,27 +176,20 @@
   /// \param [out] MappedName if this is a headermap which maps the filename to
   /// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this
   /// vector and point Filename to it.
-  const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS,
-                              SourceLocation IncludeLoc,
-                              SmallVectorImpl<char> *SearchPath,
-                              SmallVectorImpl<char> *RelativePath,
-                              Module *RequestingModule,
-                              ModuleMap::KnownHeader *SuggestedModule,
-                              bool &InUserSpecifiedSystemFramework,
-                              bool &IsFrameworkFound,
-                              bool &HasBeenMapped,
-                              SmallVectorImpl<char> &MappedName) const;
+  Optional<FileEntryRef>
+  LookupFile(StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
+             SmallVectorImpl<char> *SearchPath,
+             SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
+             ModuleMap::KnownHeader *SuggestedModule,
+             bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
+             bool &HasBeenMapped, SmallVectorImpl<char> &MappedName) const;
 
 private:
-  const FileEntry *DoFrameworkLookup(
-      StringRef Filename, HeaderSearch &HS,
-      SmallVectorImpl<char> *SearchPath,
-      SmallVectorImpl<char> *RelativePath,
-      Module *RequestingModule,
+  Optional<FileEntryRef> DoFrameworkLookup(
+      StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
+      SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
       ModuleMap::KnownHeader *SuggestedModule,
-      bool &InUserSpecifiedSystemFramework,
-      bool &IsFrameworkFound) const;
-
+      bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound) const;
 };
 
 }  // end namespace clang
Index: clang/include/clang/Basic/SourceManager.h
===================================================================
--- clang/include/clang/Basic/SourceManager.h
+++ clang/include/clang/Basic/SourceManager.h
@@ -265,16 +265,21 @@
     llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind>
         ContentAndKind;
 
+    /// The filename that is used to access the file entry represented by the
+    /// content cache.
+    StringRef Filename;
+
   public:
     /// Return a FileInfo object.
     static FileInfo get(SourceLocation IL, const ContentCache *Con,
-                        CharacteristicKind FileCharacter) {
+                        CharacteristicKind FileCharacter, StringRef Filename) {
       FileInfo X;
       X.IncludeLoc = IL.getRawEncoding();
       X.NumCreatedFIDs = 0;
       X.HasLineDirectives = false;
       X.ContentAndKind.setPointer(Con);
       X.ContentAndKind.setInt(FileCharacter);
+      X.Filename = Filename;
       return X;
     }
 
@@ -299,6 +304,10 @@
     void setHasLineDirectives() {
       HasLineDirectives = true;
     }
+
+    /// Returns the name of the file that was used when the file was loaded from
+    /// the underlying file system.
+    StringRef getName() const { return Filename; }
   };
 
   /// Each ExpansionInfo encodes the expansion location - where
@@ -821,7 +830,18 @@
     const SrcMgr::ContentCache *IR =
         getOrCreateContentCache(SourceFile, isSystem(FileCharacter));
     assert(IR && "getOrCreateContentCache() cannot return NULL");
-    return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
+    return createFileID(IR, SourceFile->getName(), IncludePos, FileCharacter,
+                        LoadedID, LoadedOffset);
+  }
+
+  FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos,
+                      SrcMgr::CharacteristicKind FileCharacter,
+                      int LoadedID = 0, unsigned LoadedOffset = 0) {
+    const SrcMgr::ContentCache *IR = getOrCreateContentCache(
+        &SourceFile.getFileEntry(), isSystem(FileCharacter));
+    assert(IR && "getOrCreateContentCache() cannot return NULL");
+    return createFileID(IR, SourceFile.getName(), IncludePos, FileCharacter,
+                        LoadedID, LoadedOffset);
   }
 
   /// Create a new FileID that represents the specified memory buffer.
@@ -832,9 +852,10 @@
                       SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
                       int LoadedID = 0, unsigned LoadedOffset = 0,
                       SourceLocation IncludeLoc = SourceLocation()) {
+    StringRef Name = Buffer->getBufferIdentifier();
     return createFileID(
         createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false),
-        IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+        Name, IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
   }
 
   enum UnownedTag { Unowned };
@@ -847,8 +868,9 @@
                       SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
                       int LoadedID = 0, unsigned LoadedOffset = 0,
                       SourceLocation IncludeLoc = SourceLocation()) {
-    return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true),
-                        IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+    return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/ true),
+                        Buffer->getBufferIdentifier(), IncludeLoc,
+                        FileCharacter, LoadedID, LoadedOffset);
   }
 
   /// Get the FileID for \p SourceFile if it exists. Otherwise, create a
@@ -997,6 +1019,19 @@
     return Content->OrigEntry;
   }
 
+  /// Returns the FileEntryRef for the provided FileID.
+  Optional<FileEntryRef> getFileEntryRefForID(FileID FID) const {
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+    if (Invalid || !Entry.isFile())
+      return None;
+
+    const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache();
+    if (!Content || !Content->OrigEntry)
+      return None;
+    return FileEntryRef(Entry.getFile().getName(), *Content->OrigEntry);
+  }
+
   /// Returns the FileEntry record for the provided SLocEntry.
   const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
   {
@@ -1785,10 +1820,10 @@
   ///
   /// This works regardless of whether the ContentCache corresponds to a
   /// file or some other input source.
-  FileID createFileID(const SrcMgr::ContentCache* File,
+  FileID createFileID(const SrcMgr::ContentCache *File, StringRef Filename,
                       SourceLocation IncludePos,
-                      SrcMgr::CharacteristicKind DirCharacter,
-                      int LoadedID, unsigned LoadedOffset);
+                      SrcMgr::CharacteristicKind DirCharacter, int LoadedID,
+                      unsigned LoadedOffset);
 
   const SrcMgr::ContentCache *
     getOrCreateContentCache(const FileEntry *SourceFile,
Index: clang/include/clang/Basic/FileManager.h
===================================================================
--- clang/include/clang/Basic/FileManager.h
+++ clang/include/clang/Basic/FileManager.h
@@ -106,6 +106,32 @@
   bool isOpenForTests() const { return File != nullptr; }
 };
 
+/// A reference to a \c FileEntry that includes the name of the file as it was
+/// accessed by the FileManager's client.
+class FileEntryRef {
+public:
+  FileEntryRef(StringRef Name, const FileEntry &Entry)
+      : Name(Name), Entry(Entry) {}
+
+  const StringRef getName() const { return Name; }
+
+  const FileEntry &getFileEntry() const { return Entry; }
+
+  off_t getSize() const { return Entry.getSize(); }
+
+  unsigned getUID() const { return Entry.getUID(); }
+
+  const llvm::sys::fs::UniqueID &getUniqueID() const {
+    return Entry.getUniqueID();
+  }
+
+  time_t getModificationTime() const { return Entry.getModificationTime(); }
+
+private:
+  StringRef Name;
+  const FileEntry &Entry;
+};
+
 /// Implements support for file system lookup, file system caching,
 /// and directory search management.
 ///
@@ -143,13 +169,25 @@
   llvm::StringMap<llvm::ErrorOr<DirectoryEntry &>, llvm::BumpPtrAllocator>
   SeenDirEntries;
 
+  /// A reference to the file entry that is associated with a particular
+  /// filename, or a reference to another filename that should be looked up
+  /// instead of the accessed filename.
+  ///
+  /// The reference to another filename is specifically useful for Redirecting
+  /// VFSs that use external names. In that case, the \c FileEntryRef returned
+  /// by the \c FileManager will have the external name, and not the name that
+  /// was used to lookup the file.
+  using SeenFileEntryOrRedirect =
+      llvm::PointerUnion<FileEntry *, const StringRef *>;
+
   /// A cache that maps paths to file entries (either real or
   /// virtual) we have looked up, or an error that occurred when we looked up
   /// the file.
   ///
   /// \see SeenDirEntries
-  llvm::StringMap<llvm::ErrorOr<FileEntry &>, llvm::BumpPtrAllocator>
-  SeenFileEntries;
+  llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
+                  llvm::BumpPtrAllocator>
+      SeenFileEntries;
 
   /// The canonical names of directories.
   llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames;
@@ -200,6 +238,9 @@
   /// Removes the FileSystemStatCache object from the manager.
   void clearStatCache();
 
+  /// Returns the number of unique real file entries cached by the file manager.
+  size_t getNumUniqueRealFiles() const { return UniqueRealFiles.size(); }
+
   /// Lookup, cache, and verify the specified directory (real or
   /// virtual).
   ///
@@ -215,6 +256,10 @@
   /// Lookup, cache, and verify the specified file (real or
   /// virtual).
   ///
+  /// This function is deprecated and will be removed at some point in the
+  /// future, new clients should use
+  ///  \c getFileRef.
+  ///
   /// This returns a \c std::error_code if there was an error loading the file.
   /// If there is no error, the FileEntry is guaranteed to be non-NULL.
   ///
@@ -225,6 +270,24 @@
   llvm::ErrorOr<const FileEntry *>
   getFile(StringRef Filename, bool OpenFile = false, bool CacheFailure = true);
 
+  /// Lookup, cache, and verify the specified file (real or virtual). Return the
+  /// reference to the file entry together with the exact path that was used to
+  /// access a file by a particular call to getFileRef. If the underlying VFS is
+  /// a redirecting VFS that uses external file names, the returned FileEntryRef
+  /// will use the external name instead of the filename that was passed to this
+  /// method.
+  ///
+  /// This returns a \c std::error_code if there was an error loading the file,
+  /// or a \c FileEntryRef otherwise.
+  ///
+  /// \param OpenFile if true and the file exists, it will be opened.
+  ///
+  /// \param CacheFailure If true and the file does not exist, we'll cache
+  /// the failure to find this file.
+  llvm::ErrorOr<FileEntryRef> getFileRef(StringRef Filename,
+                                         bool OpenFile = false,
+                                         bool CacheFailure = true);
+
   /// Returns the current file system options
   FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
   const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to