Frontend: Add basic -H support.
 - I didn't implement the GCC "multiple include guard" detection parts, because
   it doesn't seem useful or obvious.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111983 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 9a22c21..bdb918b 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -556,3 +556,5 @@
   HelpText<"Print macro definitions in -E mode instead of normal output">;
 def dD : Flag<"-dD">,
   HelpText<"Print macro definitions in -E mode in addition to normal output">;
+def H : Flag<"-H">,
+  HelpText<"Show header includes and nesting depth">;
diff --git a/include/clang/Frontend/PreprocessorOutputOptions.h b/include/clang/Frontend/PreprocessorOutputOptions.h
index a712a3d..82517c5 100644
--- a/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -16,19 +16,21 @@
 /// output (e.g., -E).
 class PreprocessorOutputOptions {
 public:
-  unsigned ShowCPP : 1;           ///< Print normal preprocessed output.
-  unsigned ShowMacros : 1;        ///< Print macro definitions.
-  unsigned ShowLineMarkers : 1;   ///< Show #line markers.
-  unsigned ShowComments : 1;      ///< Show comments.
-  unsigned ShowMacroComments : 1; ///< Show comments, even in macros.
+  unsigned ShowCPP : 1;            ///< Print normal preprocessed output.
+  unsigned ShowComments : 1;       ///< Show comments.
+  unsigned ShowHeaderIncludes : 1; ///< Show header inclusions (-H).
+  unsigned ShowLineMarkers : 1;    ///< Show #line markers.
+  unsigned ShowMacroComments : 1;  ///< Show comments, even in macros.
+  unsigned ShowMacros : 1;         ///< Print macro definitions.
 
 public:
   PreprocessorOutputOptions() {
     ShowCPP = 1;
-    ShowMacros = 0;
-    ShowLineMarkers = 1;
     ShowComments = 0;
+    ShowHeaderIncludes = 0;
+    ShowLineMarkers = 1;
     ShowMacroComments = 0;
+    ShowMacros = 0;
   }
 };
 
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 4f839e9..9e7a061 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -962,6 +962,7 @@
   }
 
   Args.AddAllArgs(CmdArgs, options::OPT_v);
+  Args.AddLastArg(CmdArgs, options::OPT_H);
   Args.AddLastArg(CmdArgs, options::OPT_P);
   Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
 
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 86ce315..68e2d84 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -689,6 +689,8 @@
   else if (!Opts.ShowCPP && Opts.ShowMacros)
     Res.push_back("-dM");
 
+  if (Opts.ShowHeaderIncludes)
+    Res.push_back("-H");
   if (!Opts.ShowLineMarkers)
     Res.push_back("-P");
   if (Opts.ShowComments)
@@ -1456,10 +1458,11 @@
                                         ArgList &Args) {
   using namespace cc1options;
   Opts.ShowCPP = !Args.hasArg(OPT_dM);
-  Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
-  Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
   Opts.ShowComments = Args.hasArg(OPT_C);
+  Opts.ShowHeaderIncludes = Args.hasArg(OPT_H);
+  Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
   Opts.ShowMacroComments = Args.hasArg(OPT_CC);
+  Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
 }
 
 static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index e68fd58..cfaf8a2 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -85,6 +85,10 @@
   llvm::raw_ostream &OS;
 private:
   unsigned CurLine;
+
+  /// The current include nesting level, used by header include dumping (-H).
+  unsigned CurrentIncludeDepth;
+
   bool EmittedTokensOnThisLine;
   bool EmittedMacroOnThisLine;
   SrcMgr::CharacteristicKind FileType;
@@ -92,19 +96,22 @@
   bool Initialized;
   bool DisableLineMarkers;
   bool DumpDefines;
+  bool DumpHeaderIncludes;
   bool UseLineDirective;
+  bool HasProcessedPredefines;
 public:
   PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
-                           bool lineMarkers, bool defines)
+                           bool lineMarkers, bool defines, bool headers)
      : PP(pp), SM(PP.getSourceManager()),
        ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
-       DumpDefines(defines) {
-    CurLine = 0;
+       DumpDefines(defines), DumpHeaderIncludes(headers) {
+    CurLine = CurrentIncludeDepth = 0;
     CurFilename += "<uninit>";
     EmittedTokensOnThisLine = false;
     EmittedMacroOnThisLine = false;
     FileType = SrcMgr::C_User;
     Initialized = false;
+    HasProcessedPredefines = false;
 
     // If we're in microsoft mode, use normal #line instead of line markers.
     UseLineDirective = PP.getLangOptions().Microsoft;
@@ -219,7 +226,7 @@
   
   PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc);
   unsigned NewLine = UserLoc.getLine();
-  
+
   if (Reason == PPCallbacks::EnterFile) {
     SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
     if (IncludeLoc.isValid())
@@ -231,16 +238,41 @@
     // directive and emits a bunch of spaces that aren't needed.  Emulate this
     // strange behavior.
   }
+
+  // Adjust the current include depth.
+  if (Reason == PPCallbacks::EnterFile) {
+    ++CurrentIncludeDepth;
+  } else {
+    if (CurrentIncludeDepth)
+      --CurrentIncludeDepth;
+
+    // We track when we are done with the predefines by watching for the first
+    // place where we drop back to a nesting depth of 0.
+    if (CurrentIncludeDepth == 0 && !HasProcessedPredefines)
+      HasProcessedPredefines = true;
+  }
   
   CurLine = NewLine;
 
-  if (DisableLineMarkers) return;
-
   CurFilename.clear();
   CurFilename += UserLoc.getFilename();
   Lexer::Stringify(CurFilename);
   FileType = NewFileType;
 
+  // Dump the header include information, if enabled and we are past the
+  // predefines buffer.
+  if (DumpHeaderIncludes && HasProcessedPredefines &&
+      Reason == PPCallbacks::EnterFile) {
+    llvm::SmallString<256> Msg;
+    llvm::raw_svector_ostream OS(Msg);
+    for (unsigned i = 0; i != CurrentIncludeDepth; ++i)
+      OS << '.';
+    OS << ' ' << CurFilename << '\n';
+    llvm::errs() << OS.str();
+  }
+
+  if (DisableLineMarkers) return;
+  
   if (!Initialized) {
     WriteLineInfo(CurLine);
     Initialized = true;
@@ -529,7 +561,7 @@
 
   PrintPPOutputPPCallbacks *Callbacks =
       new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers,
-                                   Opts.ShowMacros);
+                                   Opts.ShowMacros, Opts.ShowHeaderIncludes);
   PP.AddPragmaHandler(new UnknownPragmaHandler("#pragma", Callbacks));
   PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
                                                       Callbacks));
diff --git a/test/Frontend/Inputs/lit.local.cfg b/test/Frontend/Inputs/lit.local.cfg
new file mode 100644
index 0000000..e6f55ee
--- /dev/null
+++ b/test/Frontend/Inputs/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = []
diff --git a/test/Frontend/Inputs/test.h b/test/Frontend/Inputs/test.h
new file mode 100644
index 0000000..98cc459
--- /dev/null
+++ b/test/Frontend/Inputs/test.h
@@ -0,0 +1 @@
+#include "test2.h"
diff --git a/test/Frontend/Inputs/test2.h b/test/Frontend/Inputs/test2.h
new file mode 100644
index 0000000..6d1a0d4
--- /dev/null
+++ b/test/Frontend/Inputs/test2.h
@@ -0,0 +1 @@
+int x;
diff --git a/test/Frontend/Inputs/test3.h b/test/Frontend/Inputs/test3.h
new file mode 100644
index 0000000..92ff4b8
--- /dev/null
+++ b/test/Frontend/Inputs/test3.h
@@ -0,0 +1 @@
+int y;
diff --git a/test/Frontend/print-header-includes.c b/test/Frontend/print-header-includes.c
new file mode 100644
index 0000000..7773d20
--- /dev/null
+++ b/test/Frontend/print-header-includes.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -include Inputs/test3.h -E -H -o %t.out %s 2> %t.err
+// RUN: FileCheck < %t.err %s
+
+// CHECK-NOT: test3.h
+// CHECK: . {{.*test.h}}
+// CHECK: .. {{.*test2.h}}
+
+#include "Inputs/test.h"