Add dependencies from imported modules with -MD

Add module dependencies to the dependency files created by -MD/-MMD/etc.
by attaching an ASTReaderListener that will call into the dependency
file generator when a module input file is seen in the serialized AST.

llvm-svn: 203208
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index e07eb52..f10311a 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -269,7 +269,8 @@
   // Handle generating dependencies, if requested.
   const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
   if (!DepOpts.OutputFile.empty())
-    AttachDependencyFileGen(*PP, DepOpts);
+    TheDependencyFileGenerator.reset(
+        DependencyFileGenerator::CreateAndAttachToPreprocessor(*PP, DepOpts));
   if (!DepOpts.DOTOutputFile.empty())
     AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
                              getHeaderSearchOpts().Sysroot);
@@ -1160,6 +1161,9 @@
         ModuleManager->StartTranslationUnit(&getASTConsumer());
     }
 
+    if (TheDependencyFileGenerator)
+      TheDependencyFileGenerator->AttachToASTReader(*ModuleManager);
+
     // Try to load the module file.
     unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
     switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module,
diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp
index 39ccdd7..175a2c9 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -20,6 +20,7 @@
 #include "clang/Lex/LexDiagnostic.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Serialization/ASTReader.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
@@ -28,7 +29,8 @@
 using namespace clang;
 
 namespace {
-class DependencyFileCallback : public PPCallbacks {
+/// Private implementation for DependencyFileGenerator
+class DFGImpl : public PPCallbacks {
   std::vector<std::string> Files;
   llvm::StringSet<> FilesSet;
   const Preprocessor *PP;
@@ -41,12 +43,10 @@
 private:
   bool FileMatchesDepCriteria(const char *Filename,
                               SrcMgr::CharacteristicKind FileType);
-  void AddFilename(StringRef Filename);
   void OutputDependencyFile();
 
 public:
-  DependencyFileCallback(const Preprocessor *_PP,
-                         const DependencyOutputOptions &Opts)
+  DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
     : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
       IncludeSystemHeaders(Opts.IncludeSystemHeaders),
       PhonyTarget(Opts.UsePhonyTargets),
@@ -69,27 +69,54 @@
   virtual void EndOfMainFile() {
     OutputDependencyFile();
   }
+
+  void AddFilename(StringRef Filename);
+  bool includeSystemHeaders() const { return IncludeSystemHeaders; }
+};
+
+class DFGASTReaderListener : public ASTReaderListener {
+  DFGImpl &Parent;
+public:
+  DFGASTReaderListener(DFGImpl &Parent)
+  : Parent(Parent) { }
+  virtual bool needsInputFileVisitation() { return true; }
+  virtual bool needsSystemInputFileVisitation() {
+    return Parent.includeSystemHeaders();
+  }
+  virtual bool visitInputFile(StringRef Filename, bool isSystem);
 };
 }
 
-void clang::AttachDependencyFileGen(Preprocessor &PP,
-                                    const DependencyOutputOptions &Opts) {
+DependencyFileGenerator::DependencyFileGenerator(void *Impl)
+: Impl(Impl) { }
+
+DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor(
+    clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) {
+
   if (Opts.Targets.empty()) {
     PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
-    return;
+    return NULL;
   }
 
   // Disable the "file not found" diagnostic if the -MG option was given.
   if (Opts.AddMissingHeaderDeps)
     PP.SetSuppressIncludeNotFoundError(true);
 
-  PP.addPPCallbacks(new DependencyFileCallback(&PP, Opts));
+  DFGImpl *Callback = new DFGImpl(&PP, Opts);
+  PP.addPPCallbacks(Callback); // PP owns the Callback
+  return new DependencyFileGenerator(Callback);
+}
+
+void DependencyFileGenerator::AttachToASTReader(ASTReader &R) {
+  DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
+  assert(I && "missing implementation");
+  R.addListener(new DFGASTReaderListener(*I));
 }
 
 /// FileMatchesDepCriteria - Determine whether the given Filename should be
 /// considered as a dependency.
-bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
-                                          SrcMgr::CharacteristicKind FileType) {
+bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
+                                     SrcMgr::CharacteristicKind FileType) {
   if (strcmp("<built-in>", Filename) == 0)
     return false;
 
@@ -99,10 +126,10 @@
   return FileType == SrcMgr::C_User;
 }
 
-void DependencyFileCallback::FileChanged(SourceLocation Loc,
-                                         FileChangeReason Reason,
-                                         SrcMgr::CharacteristicKind FileType,
-                                         FileID PrevFID) {
+void DFGImpl::FileChanged(SourceLocation Loc,
+                          FileChangeReason Reason,
+                          SrcMgr::CharacteristicKind FileType,
+                          FileID PrevFID) {
   if (Reason != PPCallbacks::EnterFile)
     return;
 
@@ -130,15 +157,15 @@
   AddFilename(Filename);
 }
 
-void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
-                                                const Token &IncludeTok,
-                                                StringRef FileName,
-                                                bool IsAngled,
-                                                CharSourceRange FilenameRange,
-                                                const FileEntry *File,
-                                                StringRef SearchPath,
-                                                StringRef RelativePath,
-                                                const Module *Imported) {
+void DFGImpl::InclusionDirective(SourceLocation HashLoc,
+                                 const Token &IncludeTok,
+                                 StringRef FileName,
+                                 bool IsAngled,
+                                 CharSourceRange FilenameRange,
+                                 const FileEntry *File,
+                                 StringRef SearchPath,
+                                 StringRef RelativePath,
+                                 const Module *Imported) {
   if (!File) {
     if (AddMissingHeaderDeps)
       AddFilename(FileName);
@@ -147,7 +174,7 @@
   }
 }
 
-void DependencyFileCallback::AddFilename(StringRef Filename) {
+void DFGImpl::AddFilename(StringRef Filename) {
   if (FilesSet.insert(Filename))
     Files.push_back(Filename);
 }
@@ -164,7 +191,7 @@
   }
 }
 
-void DependencyFileCallback::OutputDependencyFile() {
+void DFGImpl::OutputDependencyFile() {
   if (SeenMissingHeader) {
     llvm::sys::fs::remove(OutputFile);
     return;
@@ -234,3 +261,10 @@
   }
 }
 
+bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
+                                          bool IsSystem) {
+  assert(!IsSystem || needsSystemInputFileVisitation());
+  Parent.AddFilename(Filename);
+  return true;
+}
+