diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -179,6 +179,14 @@
   CompilerInstance(const CompilerInstance &) = delete;
   void operator=(const CompilerInstance &) = delete;
 public:
+  struct EntryStruct {
+    Optional<FileEntryRef> FE;
+    bool IsSystemFile;
+    bool IsTopLevelModuleMap;
+  };
+  llvm::StringMap<std::deque<EntryStruct>> SortedFiles;
+  llvm::StringMap<llvm::BitVector> SearchPathUsage;
+
   explicit CompilerInstance(
       std::shared_ptr<PCHContainerOperations> PCHContainerOps =
           std::make_shared<PCHContainerOperations>(),
diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h
--- a/clang/include/clang/Lex/PreprocessorOptions.h
+++ b/clang/include/clang/Lex/PreprocessorOptions.h
@@ -68,6 +68,8 @@
   std::vector<std::string> Includes;
   std::vector<std::string> MacroIncludes;
 
+  bool ScanningMode = false;
+
   /// Initialize the preprocessor with the compiler and target specific
   /// predefines.
   bool UsePredefines = true;
diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h
--- a/clang/include/clang/Lex/Token.h
+++ b/clang/include/clang/Lex/Token.h
@@ -246,7 +246,7 @@
     Flags &= ~Flag;
   }
 
-  /// Return the internal represtation of the flags.
+  /// Return the internal representation of the flags.
   ///
   /// This is only intended for low-level operations such as writing tokens to
   /// disk.
@@ -254,6 +254,14 @@
     return Flags;
   }
 
+  /// Set the internal representation of the flags.
+  ///
+  /// This is only intended for low-level operations such as writing tokens to
+  /// disk.
+  void setFlags(unsigned Flags) {
+    this->Flags = Flags;
+  }
+
   /// Set a flag to either true or false.
   void setFlagValue(TokenFlags Flag, bool Val) {
     if (Val)
diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -87,9 +87,6 @@
   /// additionally appear in \c FileDeps as a dependency.
   std::string ClangModuleMapFile;
 
-  /// The path to where an implicit build would put the PCM for this module.
-  std::string ImplicitModulePCMPath;
-
   /// A collection of absolute paths to files that this module directly depends
   /// on, not including transitive dependencies.
   llvm::StringSet<> FileDeps;
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1129,6 +1129,406 @@
   return LangOpts.CPlusPlus ? Language::CXX : Language::C;
 }
 
+class Translator {
+  CompilerInstance &A;
+  Preprocessor &APP;
+  SourceManager &ASM;
+  FileManager &AFM;
+  HeaderSearch &AHS;
+
+  const CompilerInstance &B;
+  const Preprocessor &BPP;
+  const SourceManager &BSM;
+  const FileManager &BFM;
+  HeaderSearch &BHS;
+
+  llvm::StringSet<> TranslatedModules;
+
+public:
+  Translator(CompilerInstance &A, const CompilerInstance &B)
+      : A(A), APP(A.getPreprocessor()), ASM(A.getSourceManager()),
+        AFM(A.getFileManager()), AHS(A.getPreprocessor().getHeaderSearchInfo()),
+        B(B), BPP(B.getPreprocessor()), BSM(B.getSourceManager()),
+        BFM(B.getFileManager()),
+        BHS(B.getPreprocessor().getHeaderSearchInfo()) {}
+
+  template <class T> Optional<T> translate(const Optional<T> &BO) {
+    if (!BO)
+      return None;
+    return translate(*BO);
+  }
+
+  template <class T> const T *translate(const T *BP) {
+    if (!BP)
+      return nullptr;
+    return &translate(*BP);
+  }
+
+  template <class T> T *translate(T *BP) {
+    if (!BP)
+      return nullptr;
+    return &translate(*BP);
+  }
+
+  template <class T, class U>
+  llvm::PointerUnion<T, U> translate(llvm::PointerUnion<T, U> BPU) {
+    if (!BPU)
+      return nullptr;
+    if (BPU.template is<T>())
+      return translate(BPU.template get<T>());
+    return translate(BPU.template get<U>());
+  }
+
+  template <class T, unsigned N>
+  SmallVector<T, N> translate(const SmallVector<T, N> &BV) {
+    SmallVector<T, N> AV;
+    AV.reserve(BV.size());
+    for (const T &Entry : BV)
+      AV.push_back(translate(Entry));
+    return AV;
+  }
+
+  template <class T, unsigned N>
+  llvm::SmallSetVector<T, N> translate(const llvm::SmallSetVector<T, N>& BSSV) {
+    llvm::SmallSetVector<T, N> ASSV;
+    for (const auto &Entry : BSSV)
+      ASSV.insert(translate(Entry));
+    return ASSV;
+  }
+
+  const FileEntry &translate(const FileEntry &BFE) {
+    if (auto MaybeAFE = AFM.getFile(BFE.getName()))
+      return **MaybeAFE;
+    return *AFM.getVirtualFile(BFE.getName(), BFE.getSize(),
+                               BFE.getModificationTime());
+  }
+
+  FileEntryRef translate(FileEntryRef BFE) {
+    return *AFM.getOptionalFileRef(BFE.getName());
+  }
+
+  const DirectoryEntry &translate(const DirectoryEntry &BDE) {
+    return **AFM.getDirectory(BDE.getName());
+  }
+
+  SourceLocation translate(SourceLocation BLoc) {
+    if (BLoc.isInvalid())
+      return {};
+
+    auto BOffset = BSM.getFileOffset(BLoc);
+    auto AOffset = BOffset;
+
+    auto BFileID = BSM.getFileID(BLoc);
+    auto AFileID = [&]() {
+      if (BFileID == BPP.getPredefinesFileID())
+        return APP.getPredefinesFileID();
+
+      auto BFileCharacteristic = BSM.getFileCharacteristic(BLoc);
+      auto AFileCharacteristic = BFileCharacteristic;
+
+      auto *BFileEntry = BSM.getFileEntryForID(BFileID);
+      auto *AFileEntry = translate(BFileEntry);
+      return ASM.getOrCreateFileID(AFileEntry, AFileCharacteristic);
+    }();
+
+    return ASM.getComposedLoc(AFileID, AOffset);
+  }
+
+  Module::Header translate(const Module::Header &BHeader) {
+    return Module::Header{BHeader.NameAsWritten,
+                          BHeader.PathRelativeToRootModuleDirectory,
+                          translate(BHeader.Entry)};
+  }
+
+  std::vector<Module *> translate(Module::submodule_iterator Begin,
+                                  Module::submodule_iterator End) {
+    std::vector<Module *> ASubModules;
+    for (auto It = Begin; It != End; ++It)
+      ASubModules.push_back(translate(*It));
+    return ASubModules;
+  }
+
+  Module::UnresolvedHeaderDirective
+  translate(const Module::UnresolvedHeaderDirective &BD) {
+    return {BD.Kind, //
+            translate(BD.FileNameLoc),
+            BD.FileName,
+            BD.IsUmbrella,
+            BD.HasBuiltinHeader,
+            BD.Size,
+            BD.ModTime};
+  }
+
+  Module::ExportDecl translate(const Module::ExportDecl &BED) {
+    return {translate(BED.getPointer()), BED.getInt()};
+  }
+
+  ModuleId translate(const ModuleId &BId) {
+    ModuleId Res;
+    for (const auto &Element : BId)
+      Res.push_back({Element.first, translate(Element.second)});
+    return Res;
+  }
+
+  Module::UnresolvedExportDecl
+  translate(const Module::UnresolvedExportDecl &BUED) {
+    return {translate(BUED.ExportLoc), translate(BUED.Id), BUED.Wildcard};
+  }
+
+  Module::LinkLibrary translate(const Module::LinkLibrary &X) {
+    return X;
+  }
+
+  Module::UnresolvedConflict translate(const Module::UnresolvedConflict &X) {
+    return {translate(X.Id), X.Message};
+  }
+
+  Module::Conflict translate(const Module::Conflict &X) {
+    return {translate(X.Other), X.Message};
+  }
+
+  const Module &translate(const Module &BMod) {
+    return translate(const_cast<Module &>(BMod));
+  }
+
+  Module &translate(Module &BMod) {
+    auto &AModMap = AHS.getModuleMap();
+
+    auto [AMod, New] = AModMap.findOrCreateModule(
+        BMod.Name, translate(BMod.Parent),
+        BMod.IsFramework, BMod.IsExplicit);
+
+    if (!TranslatedModules.insert(BMod.Name).second)
+      return *AMod;
+
+    AMod->Kind = BMod.Kind;
+    AMod->Directory = translate(BMod.Directory);
+    AMod->PresumedModuleMapFile = BMod.PresumedModuleMapFile;
+    AMod->DefinitionLoc = translate(BMod.DefinitionLoc);
+    AMod->Umbrella = translate(BMod.Umbrella);
+    AMod->UmbrellaAsWritten = BMod.UmbrellaAsWritten;
+    AMod->UmbrellaRelativeToRootModuleDirectory =
+        BMod.UmbrellaRelativeToRootModuleDirectory;
+    AMod->ExportAsModule = BMod.ExportAsModule;
+
+    for (Module *BSubMod : BMod.submodules())
+      translate(BSubMod);
+
+    for (const FileEntry *BTopHeader : BMod.getTopHeaders(B.getFileManager()))
+      AMod->addTopHeader(translate(BTopHeader));
+
+    // TODO: Propagate VisibilityID to other data structures.
+
+    for (auto Kind : {Module::HK_Normal, Module::HK_Textual, Module::HK_Private,
+                      Module::HK_PrivateTextual, Module::HK_Excluded}) {
+      for (const auto &BH : BMod.Headers[Kind]) {
+        const auto &AH = translate(BH);
+        AModMap.addHeader(AMod, AH, ModuleMap::headerKindToRole(Kind),
+                          BHS.getFileInfo(BH.Entry).isModuleHeader);
+      }
+    }
+
+    AMod->UnresolvedHeaders = translate(BMod.UnresolvedHeaders);
+    AMod->MissingHeaders = translate(BMod.MissingHeaders);
+    AMod->Requirements = BMod.Requirements;
+    AMod->ShadowingModule = translate(BMod.ShadowingModule);
+    AMod->IsUnimportable = BMod.IsUnimportable;
+    AMod->HasIncompatibleModuleFile = BMod.HasIncompatibleModuleFile;
+    AMod->IsAvailable = BMod.IsAvailable;
+    AMod->IsFromModuleFile = BMod.IsFromModuleFile;
+    AMod->IsFramework = BMod.IsFramework;
+    AMod->IsExplicit = BMod.IsExplicit;
+    AMod->IsSystem = BMod.IsSystem;
+    AMod->IsExternC = BMod.IsExternC;
+    // This is being dropped by PCM files and propagating it triggers asserts.
+    // AMod->IsInferred = BMod.IsInferred;
+    AMod->InferSubmodules = BMod.InferSubmodules;
+    AMod->InferExplicitSubmodules = BMod.InferExplicitSubmodules;
+    AMod->InferExportWildcard = BMod.InferExportWildcard;
+    AMod->ConfigMacrosExhaustive = BMod.ConfigMacrosExhaustive;
+    AMod->NoUndeclaredIncludes = BMod.NoUndeclaredIncludes;
+    AMod->ModuleMapIsPrivate = BMod.ModuleMapIsPrivate;
+    AMod->NameVisibility = BMod.NameVisibility;
+    AMod->InferredSubmoduleLoc = translate(BMod.InferredSubmoduleLoc);
+    AMod->Imports = translate(BMod.Imports);
+    AMod->Exports = translate(BMod.Exports);
+    AMod->UnresolvedExports = translate(BMod.UnresolvedExports);
+    AMod->DirectUses = translate(BMod.DirectUses);
+    AMod->UnresolvedDirectUses = translate(BMod.UnresolvedDirectUses);
+    AMod->UndeclaredUses = translate(BMod.UndeclaredUses);
+    AMod->LinkLibraries = translate(BMod.LinkLibraries);
+    AMod->UseExportAsModuleLinkName = BMod.UseExportAsModuleLinkName;
+    AMod->ConfigMacros = BMod.ConfigMacros;
+    AMod->UnresolvedConflicts = BMod.UnresolvedConflicts;
+    AMod->Conflicts = BMod.Conflicts;
+
+    return *AMod;
+  }
+
+  void translateModule(StringRef BName) {
+    translate(B.getPreprocessor().getHeaderSearchInfo().lookupModule(BName));
+  }
+
+  IdentifierInfo &translate(IdentifierInfo &BII) {
+    auto &AII = APP.getIdentifierTable().getOwn(BII.getName());
+
+    AII.setOutOfDate(false);
+
+    // TODO: Check if is interesting.
+
+    if (BII.hasRevertedTokenIDToIdentifier() &&
+        BII.getTokenID() != tok::TokenKind::identifier)
+      AII.revertTokenIDToIdentifier();
+    AII.setObjCOrBuiltinID(BII.getObjCOrBuiltinID());
+    AII.setIsPoisoned(BII.isPoisoned());
+
+    AII.setObjCKeywordID(BII.getObjCKeywordID());
+    AII.setHasMacroDefinition(BII.hasMacroDefinition());
+
+    return AII;
+  }
+
+  Token translate(const Token &BTok) {
+    Token ATok;
+    ATok.startToken();
+    ATok.setLocation(translate(BTok.getLocation()));
+    ATok.setLength(BTok.getLength());
+    ATok.setIdentifierInfo(translate(BTok.getIdentifierInfo()));
+    ATok.setKind(BTok.getKind());
+    ATok.setFlags(BTok.getFlags());
+    return ATok;
+  }
+
+  MacroInfo *translate(MacroInfo *BMI) {
+    auto BLoc = BMI->getDefinitionLoc();
+    auto ALoc = translate(BLoc);
+
+    MacroInfo *AMI = APP.AllocateMacroInfo(ALoc);
+    AMI->setDefinitionEndLoc(BMI->getDefinitionEndLoc());
+    AMI->setIsUsed(BMI->isUsed());
+    AMI->setUsedForHeaderGuard(BMI->isUsedForHeaderGuard());
+
+    if (BMI->isFunctionLike()) {
+      AMI->setIsFunctionLike();
+      if (BMI->isC99Varargs())
+        AMI->setIsC99Varargs();
+      if (BMI->isGNUVarargs())
+        AMI->setIsGNUVarargs();
+      if (BMI->hasCommaPasting())
+        AMI->setHasCommaPasting();
+      std::vector<IdentifierInfo *> AParams;
+      for (const IdentifierInfo *BParam : BMI->params())
+        AParams.push_back(translate(const_cast<IdentifierInfo *>(BParam)));
+      AMI->setParameterList(AParams, APP.getPreprocessorAllocator());
+    }
+
+    // TODO: Complete preprocessing record.
+
+    std::vector<Token> AToks;
+    for (const Token &BTok : BMI->tokens())
+      AToks.push_back(translate(BTok));
+    AMI->setTokens(AToks, APP.getPreprocessorAllocator());
+
+    return AMI;
+  }
+
+  void translatePreprocessor() {
+    for (const auto &Entry : BPP.getIdentifierTable()) {
+      IdentifierInfo *BII = Entry.getValue();
+
+      if (!BII->hadMacroDefinition())
+        continue;
+
+      // Macro directive history is not read for modules.
+
+      IdentifierInfo *BName = BII;
+      IdentifierInfo *AName = translate(BII);
+
+      auto BLeafs = BPP.getLeafModuleMacros(BName);
+      SmallVector<ModuleMacro *, 8> Worklist(BLeafs.begin(), BLeafs.end());
+      llvm::DenseMap<ModuleMacro *, unsigned> Visits;
+      while (!Worklist.empty()) {
+        auto *BMacro = Worklist.pop_back_val();
+
+        auto *AModule = translate(BMacro->getOwningModule());
+        auto *AMacroInfo = translate(BMacro->getMacroInfo());
+
+        std::vector<ModuleMacro *> AOverrides;
+        for (auto *BOverride : BMacro->overrides()) {
+          auto *AOverrideModule = translate(BOverride->getOwningModule());
+          AOverrides.push_back(APP.getModuleMacro(AOverrideModule, AName));
+        }
+
+        bool Inserted = false;
+        APP.addModuleMacro(AModule, AName, AMacroInfo, AOverrides, Inserted);
+
+        // Enqueue overridden macros once we've visited all their ancestors.
+        for (auto *BModuleMacro : BMacro->overrides())
+          if (++Visits[BModuleMacro] == BModuleMacro->getNumOverridingMacros())
+            Worklist.push_back(BModuleMacro);
+      }
+    }
+  }
+};
+
+static std::set<const FileEntry *>
+GetAffectingModuleMaps(const HeaderSearch &HS, Module *RootModule) {
+  std::set<const FileEntry *> ModuleMaps{};
+  std::set<const Module *> ProcessedModules;
+  SmallVector<const Module *> ModulesToProcess{RootModule};
+
+  SmallVector<const FileEntry *, 16> FilesByUID;
+  HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
+
+  if (FilesByUID.size() > HS.header_file_size())
+    FilesByUID.resize(HS.header_file_size());
+
+  for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
+    const FileEntry *File = FilesByUID[UID];
+    if (!File)
+      continue;
+
+    const HeaderFileInfo *HFI =
+        HS.getExistingFileInfo(File, /*WantExternal*/ false);
+    if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader))
+      continue;
+
+    for (const auto &KH : HS.findAllModulesForHeader(File)) {
+      if (!KH.getModule())
+        continue;
+      ModulesToProcess.push_back(KH.getModule());
+    }
+  }
+
+  while (!ModulesToProcess.empty()) {
+    auto *CurrentModule = ModulesToProcess.pop_back_val();
+    ProcessedModules.insert(CurrentModule);
+
+    Optional<FileEntryRef> ModuleMapFile =
+        HS.getModuleMap().getModuleMapFileForUniquing(CurrentModule);
+    if (!ModuleMapFile) {
+      continue;
+    }
+
+    ModuleMaps.insert(*ModuleMapFile);
+
+    for (auto *ImportedModule : (CurrentModule)->Imports) {
+      if (!ImportedModule ||
+          ProcessedModules.find(ImportedModule) != ProcessedModules.end()) {
+        continue;
+      }
+      ModulesToProcess.push_back(ImportedModule);
+    }
+
+    for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses)
+      if (UndeclaredModule &&
+          ProcessedModules.find(UndeclaredModule) == ProcessedModules.end())
+        ModulesToProcess.push_back(UndeclaredModule);
+  }
+
+  return ModuleMaps;
+}
+
 /// Compile a module file for the given module, using the options
 /// provided by the importing compiler instance. Returns true if the module
 /// was built without errors.
@@ -1254,6 +1654,65 @@
       [&]() {
         GenerateModuleFromModuleMapAction Action;
         Instance.ExecuteAction(Action);
+
+        if (!Instance.getPreprocessorOpts().ScanningMode)
+          return;
+
+        Translator T(ImportingInstance, Instance);
+        T.translateModule(ModuleName);
+        T.translatePreprocessor();
+
+        for (const auto &X : Instance.SearchPathUsage)
+          if (!ImportingInstance.SearchPathUsage.count(X.getKey()))
+            ImportingInstance.SearchPathUsage[X.getKey()] = X.getValue();
+
+        auto &HSUsage = ImportingInstance.SearchPathUsage[ModuleName];
+        for (bool Used : Instance.getPreprocessor()
+                             .getHeaderSearchInfo()
+                             .computeUserEntryUsage())
+          HSUsage.push_back(Used);
+
+        for (const auto &X : Instance.SortedFiles)
+          if (!ImportingInstance.SortedFiles.count(X.getKey()))
+            ImportingInstance.SortedFiles[X.getKey()] = X.getValue();
+
+        auto &SortedFiles = ImportingInstance.SortedFiles[ModuleName];
+
+        std::set<const FileEntry *> AffectingModuleMaps =
+            GetAffectingModuleMaps(
+                Instance.getPreprocessor().getHeaderSearchInfo(),
+                Instance.getPreprocessor().getHeaderSearchInfo().lookupModule(
+                    ModuleName));
+
+        SourceManager &SrcMgr = Instance.getPreprocessor().getSourceManager();
+        unsigned N = SrcMgr.local_sloc_entry_size();
+
+        for (unsigned I = 1; I != N; ++I) {
+          const SrcMgr::SLocEntry *SLoc = &SrcMgr.getLocalSLocEntry(I);
+
+          if (!SLoc->isFile())
+            continue;
+          const SrcMgr::FileInfo &File = SLoc->getFile();
+          const SrcMgr::ContentCache *Cache = &File.getContentCache();
+          if (!Cache->OrigEntry)
+            continue;
+
+          if (!isModuleMap(File.getFileCharacteristic()) ||
+              AffectingModuleMaps.empty() ||
+              AffectingModuleMaps.find(Cache->OrigEntry) !=
+                  AffectingModuleMaps.end()) {
+            CompilerInstance::EntryStruct Entry{
+                T.translate(Cache->OrigEntry),
+                isSystem(File.getFileCharacteristic()),
+                isModuleMap(File.getFileCharacteristic()) &&
+                    File.getIncludeLoc().isInvalid()};
+
+            if (Entry.IsSystemFile)
+              SortedFiles.push_back(Entry);
+            else
+              SortedFiles.push_front(Entry);
+          }
+        }
       },
       DesiredStackSize);
 
@@ -1364,6 +1823,10 @@
                                       SourceLocation ModuleNameLoc,
                                       Module *Module, StringRef ModuleFileName,
                                       bool *OutOfDate) {
+  // Do not attempt to read the AST file.
+  if (ImportingInstance.getPreprocessorOpts().ScanningMode)
+    return true;
+
   DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics();
 
   unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing;
@@ -2092,7 +2555,7 @@
   // Make the named module visible, if it's not already part of the module
   // we are parsing.
   if (ModuleName != getLangOpts().CurrentModule) {
-    if (!Module->IsFromModuleFile && !MapPrivateSubModToTopLevel) {
+    if (!getPreprocessorOpts().ScanningMode && !Module->IsFromModuleFile && !MapPrivateSubModToTopLevel) {
       // We have an umbrella header or directory that doesn't actually include
       // all of the headers within the directory it covers. Complain about
       // this missing submodule and recover by forgetting that we ever saw
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -120,6 +120,9 @@
 
 std::unique_ptr<ASTConsumer>
 GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+  if (CI.getPreprocessorOpts().ScanningMode)
+    return std::make_unique<ASTConsumer>();
+
   std::string Sysroot;
   if (!ComputeASTConsumerArguments(CI, /*ref*/ Sysroot))
     return nullptr;
@@ -185,6 +188,9 @@
 std::unique_ptr<ASTConsumer>
 GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
                                         StringRef InFile) {
+  if (CI.getPreprocessorOpts().ScanningMode)
+    return std::make_unique<ASTConsumer>();
+
   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
   if (!OS)
     return nullptr;
diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp
--- a/clang/lib/Serialization/GeneratePCH.cpp
+++ b/clang/lib/Serialization/GeneratePCH.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Sema/SemaConsumer.h"
 #include "clang/Serialization/ASTWriter.h"
 #include "llvm/Bitstream/BitstreamWriter.h"
@@ -39,6 +40,10 @@
 }
 
 void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+  // Do not attempt to write the AST file.
+  if (PP.getPreprocessorOpts().ScanningMode)
+    return;
+
   // Don't create a PCH if there were fatal failures during module loading.
   if (PP.getModuleLoader().HadFatalFailure)
     return;
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
-#include "llvm/Support/TargetSelect.h"
 
 using namespace clang;
 using namespace tooling;
@@ -17,10 +16,4 @@
     ScanningMode Mode, ScanningOutputFormat Format, bool OptimizeArgs,
     bool EagerLoadModules)
     : Mode(Mode), Format(Format), OptimizeArgs(OptimizeArgs),
-      EagerLoadModules(EagerLoadModules) {
-  // Initialize targets for object file support.
-  llvm::InitializeAllTargets();
-  llvm::InitializeAllTargetMCs();
-  llvm::InitializeAllAsmPrinters();
-  llvm::InitializeAllAsmParsers();
-}
+      EagerLoadModules(EagerLoadModules) {}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -178,6 +178,9 @@
     CompilerInstance &ScanInstance = *ScanInstanceStorage;
     ScanInstance.setInvocation(std::move(Invocation));
 
+    ScanInstance.getFrontendOpts().BuildingImplicitModuleUsesLock = false;
+    ScanInstance.getPreprocessorOpts().ScanningMode = true;
+
     // Create the compiler's actual diagnostics engine.
     sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
     ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -19,24 +19,22 @@
 using namespace tooling;
 using namespace dependencies;
 
-static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts,
-                                     ASTReader &Reader,
-                                     const serialization::ModuleFile &MF) {
+static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, const Module *M,
+                                     CompilerInstance &CI) {
   // Only preserve search paths that were used during the dependency scan.
   std::vector<HeaderSearchOptions::Entry> Entries = Opts.UserEntries;
   Opts.UserEntries.clear();
 
   llvm::BitVector SearchPathUsage(Entries.size());
-  llvm::DenseSet<const serialization::ModuleFile *> Visited;
-  std::function<void(const serialization::ModuleFile *)> VisitMF =
-      [&](const serialization::ModuleFile *MF) {
-        SearchPathUsage |= MF->SearchPathUsage;
-        Visited.insert(MF);
-        for (const serialization::ModuleFile *Import : MF->Imports)
-          if (!Visited.contains(Import))
-            VisitMF(Import);
-      };
-  VisitMF(&MF);
+  llvm::DenseSet<const Module *> Visited;
+  std::function<void(const Module *)> VisitM = [&](const Module *M) {
+    SearchPathUsage |= CI.SearchPathUsage[M->getTopLevelModuleName()];
+    Visited.insert(M);
+    for (const Module *Import : M->Imports)
+      if (!Visited.contains(Import))
+        VisitM(Import);
+  };
+  VisitM(M);
 
   for (auto Idx : SearchPathUsage.set_bits())
     Opts.UserEntries.push_back(Entries[Idx]);
@@ -380,7 +378,7 @@
     // -fmodule-name is used to compile a translation unit that imports this
     // module. In that case it can be skipped. The appropriate header
     // dependencies will still be reported as expected.
-    if (!M->getASTFile())
+    if (M->getFullModuleName() == MDC.ScanInstance.getLangOpts().ModuleName)
       continue;
     handleTopLevelModule(M);
   }
@@ -410,7 +408,6 @@
 
   MD.ID.ModuleName = M->getFullModuleName();
   MD.ImportedByMainFile = DirectModularDeps.contains(M);
-  MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
   MD.IsSystem = M->IsSystem;
 
   ModuleMap &ModMapInfo =
@@ -424,40 +421,37 @@
     MD.ClangModuleMapFile = std::string(Path);
   }
 
-  serialization::ModuleFile *MF =
-      MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
-          M->getASTFile());
-  MDC.ScanInstance.getASTReader()->visitInputFiles(
-      *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) {
-        // __inferred_module.map is the result of the way in which an implicit
-        // module build handles inferred modules. It adds an overlay VFS with
-        // this file in the proper directory and relies on the rest of Clang to
-        // handle it like normal. With explicitly built modules we don't need
-        // to play VFS tricks, so replace it with the correct module map.
-        if (IF.getFile()->getName().endswith("__inferred_module.map")) {
-          MDC.addFileDep(MD, ModuleMap->getName());
-          return;
-        }
-        MDC.addFileDep(MD, IF.getFile()->getName());
-      });
+  for (const auto &E : MDC.ScanInstance.SortedFiles[M->getFullModuleName()]) {
+    // __inferred_module.map is the result of the way in which an implicit
+    // module build handles inferred modules. It adds an overlay VFS with
+    // this file in the proper directory and relies on the rest of Clang to
+    // handle it like normal. With explicitly built modules we don't need
+    // to play VFS tricks, so replace it with the correct module map.
+    if (E.FE->getName().endswith("__inferred_module.map")) {
+      MDC.addFileDep(MD, ModuleMap->getName());
+      continue;
+    }
+    MDC.addFileDep(MD, E.FE->getName());
+  }
 
   llvm::DenseSet<const Module *> SeenDeps;
   addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
   addAllSubmoduleDeps(M, MD, SeenDeps);
   addAllAffectingClangModules(M, MD, SeenDeps);
 
-  MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps(
-      *MF, [&](const FileEntry *FE) {
-        if (FE->getName().endswith("__inferred_module.map"))
-          return;
-        MD.ModuleMapFileDeps.emplace_back(FE->getName());
-      });
+  for (const auto &E : MDC.ScanInstance.SortedFiles[M->getFullModuleName()]) {
+    if (!E.IsTopLevelModuleMap)
+      continue;
+    if (E.FE->getName().endswith("__inferred_module.map"))
+      continue;
+    MD.ModuleMapFileDeps.emplace_back(E.FE->getName());
+  }
 
   CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs(
       MD, [&](CompilerInvocation &BuildInvocation) {
         if (MDC.OptimizeArgs)
-          optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(),
-                                   *MDC.ScanInstance.getASTReader(), *MF);
+          optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), M,
+                                   MDC.ScanInstance);
       });
 
   MDC.associateWithContextHash(CI, MD);
diff --git a/clang/test/ClangScanDeps/modules-basic.c b/clang/test/ClangScanDeps/modules-basic.c
new file mode 100644
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-basic.c
@@ -0,0 +1,104 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- include/module.modulemap
+module m { header "m.h"}
+module x { header "x.h" }
+//--- include/m.h
+#include "x.h"
+#define FOO
+//--- include/x.h
+// empty
+//--- include/t.h
+
+//--- tu.c
+#include "m.h"
+#ifdef FOO
+#include "t.h"
+#endif
+
+//--- cdb.json.template
+[{
+  "file": "DIR/tu.c",
+  "directory": "DIR",
+  "command": "clang -fsyntax-only DIR/tu.c -fmodules -fmodules-cache-path=DIR/cache -fimplicit-module-maps -I DIR/include"
+}]
+
+// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
+
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/result.json
+// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
+
+// CHECK: {
+// CHECK-NEXT:   "modules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       clang-module-deps": [
+// CHECK-NEXT:        {
+// CHECK-NEXT:          "context-hash": "[[X_HASH:.*]]",
+// CHECK-NEXT:          "module-name": "x"
+// CHECK-NEXT:        }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/include/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK-NEXT:         "-cc1",
+// CHECK:              "-o",
+// CHECK-NEXT:         "[[PREFIX]]/cache/{{.*}}/m-{{.*}}.pcm",
+// CHECK:              "-emit-module",
+// CHECK:              "[[PREFIX]]/include/module.modulemap",
+// CHECK:              "-fmodules",
+// CHECK:              "-fmodule-name=m",
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "[[M_HASH:.*]]",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/include/m.h",
+// CHECK-NEXT:         "[[PREFIX]]/include/module.modulemap"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "name": "m"
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/include/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK-NEXT:         "-cc1",
+// CHECK:              "-o",
+// CHECK-NEXT:         "[[PREFIX]]/cache/{{.*}}/x-{{.*}}.pcm",
+// CHECK:              "-emit-module",
+// CHECK:              "[[PREFIX]]/include/module.modulemap",
+// CHECK:              "-fmodules",
+// CHECK:              "-fmodule-name=x",
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "[[X_HASH]]",
+// CHECK-NEXT:        "file-deps": [
+// CHECK-NEXT:          "[[PREFIX]]/include/module.modulemap",
+// CHECK-NEXT:          "[[PREFIX]]/include/x.h"
+// CHECK-NEXT:        ],
+// CHECK-NEXT:       "name": "x"
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "translation-units": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "commands": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "clang-context-hash": "{{.*}}",
+// CHECK-NEXT:           "clang-module-deps": [
+// CHECK-NEXT:             {
+// CHECK-NEXT:               "context-hash": "[[M_HASH]]",
+// CHECK-NEXT:               "module-name": "m"
+// CHECK-NEXT:             }
+// CHECK-NEXT:           ],
+// CHECK-NEXT:           "command-line": [
+// CHECK-NEXT:             "-cc1",
+// CHECK:                  "-fmodule-map-file=[[PREFIX]]/include/module.modulemap",
+// CHECK:                  "-fmodule-file=m=[[PREFIX]]/cache/{{.*}}/m-{{.*}}.pcm",
+// CHECK:                ],
+// CHECK-NEXT:           "executable": "clang",
+// CHECK-NEXT:           "file-deps": [
+// CHECK-NEXT:             "[[PREFIX]]/tu.c",
+// CHECK-NEXT:             "[[PREFIX]]/include/t.h"
+// CHECK-NEXT:           ],
+// CHECK-NEXT:           "input-file": "[[PREFIX]]/tu.c"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ]
+// CHECK-NEXT: }