On Friday 16 of March 2012, Lubos Lunak wrote:
> On Friday 16 of March 2012, Chandler Carruth wrote:
> > I've not looked at the patch in detail, but a simple idea: #if 0 block,
> > with a comment explaining why.
>
>  That's a very good idea and it seems to work nicely.
>
>  I've also added commenting out #pragma once, and now the patch should be
> hopefully fully ready. I've also done a LibreOffice build again and this
> time there wasn't a single problem.

 I've still found two minor details, and also made it noticeably faster while 
I was at it. But now it's perfect, honest :).

 The latest version is attached. This time it is a patch and separately the 
new source file (to be put in clang/lib/Rewrite), to make review it easier. I 
also do not intend to make further changes until reviewed.

 The changes needed elsewhere are:

- adding the new option and invoking the functionality, trivial duplication 
of -rewrite-macros

- changes in Lexer class to not access the (null) Preprocessor pointer in raw 
mode, which the code normally uses, but temporarily switches to 
ParsingPreprocessorDirective mode (apparently a use case that's not been 
needed yet)

- addition of MacroExpansionInDirectivesOverride flag to Preprocessor, which 
makes it possible to avoid macro expansion everywhere else except in macro 
directives, which reduces the time to process files to less than a half (and 
to less than with plain -E, making icecream's distributed compilation 
actually faster this way). It could be made even faster if the lexer could be 
switched to mode where it would parse only comments and preprocessor 
directives (nothing else matters in this case), and I expect it would be an 
additional boost to distributed compiles, as this step is the bottleneck, but 
maybe later ;).

- and a test, which of course passes. Moreover, as already said, I've 
successfully compiled LibreOffice using this feature.

-- 
 Lubos Lunak
 [email protected]
//===--- RewriteIncludes.cpp - Rewrite includes into their expansions -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This code rewrites include invocations into their expansions.  This gives you
// a file with all included files merged into it.
//
//===----------------------------------------------------------------------===//

#include "clang/Rewrite/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {

class RewriteIncludes : public PPCallbacks {
  // Information about which #includes were actually performed,
  // created by preprocessor callbacks.
  struct FileChange {
    SourceLocation from;
    FileID id;
    SrcMgr::CharacteristicKind type;
  };
  Preprocessor &PP;
  SourceManager &SM;
  raw_ostream &OS;
  bool DisableLineMarkers;
  bool UseLineDirective;
  std::list< FileChange > FileChanges;
public:
  RewriteIncludes(Preprocessor &pp, raw_ostream &os, bool lineMarkers)
     : PP(pp), SM(PP.getSourceManager()),
       OS(os), DisableLineMarkers(lineMarkers) {
    // If we're in microsoft mode, use normal #line instead of line markers.
    UseLineDirective = PP.getLangOpts().MicrosoftExt;
  }
  bool Process( FileID fileId, SrcMgr::CharacteristicKind type );
private:
  virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
                           SrcMgr::CharacteristicKind FileType,
                           FileID PrevFID);
  virtual void InclusionDirective(SourceLocation HashLoc,
                                  const Token &IncludeTok,
                                  StringRef FileName,
                                  bool IsAngled,
                                  const FileEntry *File,
                                  SourceLocation EndLoc,
                                  StringRef SearchPath,
                                  StringRef RelativePath);
  void WriteLineInfo(const char* filename, int line,
                     SrcMgr::CharacteristicKind type,
                     const char *Extra = NULL, unsigned ExtraLen = 0);
  void OutputContentsUpTo( unsigned writeEnd, unsigned& nextToWrite,
                           const llvm::MemoryBuffer* FromFile,
                           bool EnsureNewline = false );
  PresumedLoc CommentOutDirective( Lexer& DirectivesLex,
                            const Token& StartToken,
                            unsigned& nextToWrite,
                            const llvm::MemoryBuffer* FromFile );
  const FileChange* FindFileChangeLocation(SourceLocation Loc) const;
  StringRef NextIdentifierName(Lexer& RawLex, Token& RawToken);
};

}  // end anonymous namespace

void RewriteIncludes::WriteLineInfo(const char* filename, int line,
                                    SrcMgr::CharacteristicKind type,
                                    const char *Extra,
                                    unsigned ExtraLen) {
  // Emit #line directives or GNU line markers depending on what mode we're in.
  if (UseLineDirective) {
    OS << "#line" << ' ' << line << ' ' << '"' << filename;
    OS << '"';
  } else {
    OS << '#' << ' ' << line << ' ' << '"' << filename << '"';
    if (ExtraLen)
      OS.write(Extra, ExtraLen);
    if (type == SrcMgr::C_System)
      OS.write(" 3", 2);
    else if (type == SrcMgr::C_ExternCSystem)
      OS.write(" 3 4", 4);
  }
  OS << '\n';
}

/// FileChanged - Whenever the preprocessor enters or exits a #include file
/// it invokes this handler.
void RewriteIncludes::FileChanged(SourceLocation Loc,
                                  FileChangeReason Reason,
                                  SrcMgr::CharacteristicKind NewFileType,
                                  FileID) {
  if (Reason == EnterFile) {
    // InclusionDirective() has already been called, add more info
    FileID id = FullSourceLoc(Loc,SM).getFileID();
    if (!FileChanges.empty()) { // there may be internal sort-of includes
        FileChanges.back().id = id;
        FileChanges.back().type = NewFileType;
    }
  }
}

// This should be called whenever the preprocessor encounters include
// directives. It does not say whether the file has been included, but it
// provides more information about the directive (hash location istead
// of location inside the included file. It is assumed that the matching
// FileChanged() is called after this (if at all).
void RewriteIncludes::InclusionDirective(SourceLocation HashLoc,
                                         const Token&,
                                         StringRef,
                                         bool,
                                         const FileEntry*,
                                         SourceLocation,
                                         StringRef,
                                         StringRef) {
  FileChange change;
  change.from = HashLoc;
  FileChanges.push_back( change );
}

const RewriteIncludes::FileChange*
RewriteIncludes::FindFileChangeLocation(SourceLocation Loc) const {
  for (std::list< FileChange >::const_iterator it
       = FileChanges.begin(), end = FileChanges.end();
       it != end; ++it) {
    if (it->from == Loc)
      return &*it;
  }
  return NULL;
}


// Copies next yet written file contents up (and not including writeEnd).
void RewriteIncludes::OutputContentsUpTo(unsigned writeEnd,
                                         unsigned& nextToWrite,
                                         const llvm::MemoryBuffer* FromFile,
                                         bool EnsureNewline ) {
  if ( writeEnd > nextToWrite ) {
    OS.write( FromFile->getBufferStart() + nextToWrite, writeEnd - nextToWrite );
    if (EnsureNewline) {
      char LastChar = FromFile->getBufferStart()[ writeEnd - 1 ];
      if (LastChar != '\n' && LastChar != '\r')
        OS << '\n';
    }
    nextToWrite = writeEnd;
  }
}

PresumedLoc RewriteIncludes::CommentOutDirective( Lexer& DirectiveLex,
                                                  const Token& StartToken,
                                                  unsigned& nextToWrite,
                                                  const llvm::MemoryBuffer* FromFile ) {
  OutputContentsUpTo(SM.getFileOffset(StartToken.getLocation()), nextToWrite, FromFile);
  Token DirectiveToken;
  do {
    DirectiveLex.LexFromRawLexer(DirectiveToken);
  } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
  OS << "#if 0 /* expanded by -rewrite-includes */\n";
  OutputContentsUpTo(SM.getFileOffset(DirectiveToken.getLocation())
    + DirectiveToken.getLength(), nextToWrite, FromFile);
  OS << "#endif /* expanded by -rewrite-includes */\n";
  // return location of EOD (for next line number, otherwise later it might not be exact
  // because of whitespace ignoring)
  assert(SM.getPresumedLoc(DirectiveToken.getLocation()).isValid());
  return SM.getPresumedLoc(DirectiveToken.getLocation());
}

StringRef RewriteIncludes::NextIdentifierName(Lexer& RawLex, Token& RawToken) {
  RawLex.LexFromRawLexer(RawToken);
  if (RawToken.is(tok::raw_identifier))
    PP.LookUpIdentifierInfo(RawToken);
  if (RawToken.is(tok::identifier))
    return RawToken.getIdentifierInfo()->getName();
  return StringRef();
}

bool RewriteIncludes::Process( FileID fileId,
                                        SrcMgr::CharacteristicKind type )
{
  PresumedLoc start = SM.getPresumedLoc(SM.getLocForStartOfFile(fileId));
  if( start.isInvalid())
    return false;

  // Use a raw lexer to analyze the input file, incrementally copying parts of
  // it and including contents of included files recursively.
  const llvm::MemoryBuffer *FromFile = SM.getBuffer( fileId );
  Lexer RawLex(fileId, FromFile, PP.getSourceManager(), PP.getLangOpts());
  RawLex.SetCommentRetentionState(false);

  WriteLineInfo( start.getFilename(), start.getLine(), type, " 1", 2 );

  if (SM.getFileIDSize(fileId) == 0)
    return true;

  // position in file from which the contents have not yet been copied to the output
  unsigned nextToWrite = 0;

  Token RawToken;
  RawLex.LexFromRawLexer(RawToken);

// It might be beneficial to have a switch that will remove contents of lines
// that are irrevelant for compile, i.e. comments. Comments are actually
// the majority of the resulting file and cleaning up such lines would
// significantly reduce the size of the resulting file without having any
// effect on any following usage (with the exception of human inspection).
  while (RawToken.isNot(tok::eof)) {
    if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) {
      RawLex.setParsingPreprocessorDirective( true );
      Token HashToken = RawToken;
      RawLex.LexFromRawLexer(RawToken);
      if (RawToken.is(tok::raw_identifier))
        PP.LookUpIdentifierInfo(RawToken);
      if (RawToken.is(tok::identifier)) {
        switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
          case tok::pp_include:
          case tok::pp_include_next:
          case tok::pp_import: {
            // keep the directive in, commented out
            // clang sometimes optimizes and does not repeatedly include some
            // files even though it should, so all includes need to be commented
            PresumedLoc EODPos = CommentOutDirective(RawLex, HashToken,
              nextToWrite, FromFile);
            // fix up lineinfo, commenting out added lines
            bool NeedFixup = true;
            if (const FileChange* change = FindFileChangeLocation(
                HashToken.getLocation())) {
              // now include and recursively process the file
              if( Process( change->id, change->type )) {
                // and set lineinfo back to this file, if the nested one was actually included
                WriteLineInfo( EODPos.getFilename(), EODPos.getLine() + 1,
                  type, " 2", 2);
                NeedFixup = false;
              }
            }
            if( NeedFixup )
              WriteLineInfo(EODPos.getFilename(), EODPos.getLine() + 1, type);
            break;
          }
          case tok::pp_pragma: {
            StringRef I = NextIdentifierName(RawLex, RawToken);
            if (I == "clang" || I == "GCC" ) {
              if (NextIdentifierName(RawLex, RawToken) == "system_header") {
                // keep the directive in, commented out
                PresumedLoc EODPos = CommentOutDirective(RawLex, HashToken,
                  nextToWrite, FromFile);
                // update our own type
                type = SM.getFileCharacteristic(RawToken.getLocation());
                WriteLineInfo(EODPos.getFilename(), EODPos.getLine() + 1, type);
              }
            } else if (I == "once") {
              // keep the directive in, commented out
              PresumedLoc EODPos = CommentOutDirective(RawLex, HashToken,
                nextToWrite, FromFile);
              WriteLineInfo(EODPos.getFilename(), EODPos.getLine() + 1, type);
            }
            break;
          }
          default:
            break;
        }
      }
      RawLex.setParsingPreprocessorDirective(false);
      RawLex.SetCommentRetentionState(false);
    }
  RawLex.LexFromRawLexer(RawToken);
  }
  OutputContentsUpTo(SM.getFileOffset(SM.getLocForEndOfFile(fileId)) + 1,
    nextToWrite, FromFile, true);
  return true;
}

/// RewriteIncludesInInput - Implement -rewrite-includes mode.
void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
                                   const PreprocessorOutputOptions &Opts) {
  SourceManager &SM = PP.getSourceManager();
  RewriteIncludes* Rewrite = new RewriteIncludes(PP, *OS, !Opts.ShowLineMarkers);
  PP.addPPCallbacks(Rewrite);

  // First let the preprocessor process the entire file and call callbacks.
  // Callbacks will record which #include's were actually performed.
  PP.EnterMainSourceFile();
  Token Tok;
  // Only preprocessor directives matter here, so disable macro expansion
  // everywhere else as an optimization.
  // It would be even faster if the preprocessor could be switched to a mode
  // where it would parse only preprocessor directives and comments, nothing
  // else matters for parsing or processing.
  PP.SetMacroExpansionOnlyInDirectives();
  do {
    PP.Lex(Tok);
  } while (Tok.isNot(tok::eof));
  Rewrite->Process( SM.getMainFileID(), SrcMgr::C_User );
  OS->flush();
}
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index d32ea0b..fc9e230 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -446,6 +446,8 @@ def rewrite_objc : Flag<"-rewrite-objc">,
   HelpText<"Rewrite ObjC into C (code rewriter example)">;
 def rewrite_macros : Flag<"-rewrite-macros">,
   HelpText<"Expand macros without full preprocessing">;
+def rewrite_includes : Flag<"-rewrite-includes">,
+  HelpText<"Expand includes without full preprocessing">;
 def migrate : Flag<"-migrate">,
   HelpText<"Migrate source code">;
 }
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 0ec2f6b..d9b24ba 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -43,6 +43,7 @@ namespace frontend {
     PrintPreamble,          ///< Print the "preamble" of the input file
     PrintPreprocessedInput, ///< -E mode.
     RewriteMacros,          ///< Expand macros but not #includes.
+    RewriteIncludes,        ///< Expand #includes but not macros.
     RewriteObjC,            ///< ObjC->C Rewriter.
     RewriteTest,            ///< Rewriter playground
     RunAnalysis,            ///< Run one or more source code analyses.
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 508c168..6284ccb 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -121,6 +121,13 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
   /// DisableMacroExpansion - True if macro expansion is disabled.
   bool DisableMacroExpansion : 1;
 
+  /// MacroExpansionInDirectivesOverride - Temporarily disables
+  /// DisableMacroExpansion (i.e. enables expansion) when parsing preprocessor
+  /// directives.
+  bool MacroExpansionInDirectivesOverride : 1;
+
+  class ResetMacroExpansionHelper;
+
   /// \brief Whether we have already loaded macros from the external source.
   mutable bool ReadMacrosFromExternalSource : 1;
 
@@ -626,6 +633,11 @@ public:
     while (Result.getKind() == tok::comment);
   }
 
+  /// Disables macro expansion everywhere except for preprocessor directives.
+  void SetMacroExpansionOnlyInDirectives() {
+    DisableMacroExpansion = true;
+    MacroExpansionInDirectivesOverride = true;
+  }
   /// LookAhead - This peeks ahead N tokens and returns that token without
   /// consuming any tokens.  LookAhead(0) returns the next token that would be
   /// returned by Lex(), LookAhead(1) returns the token after it, etc.  This
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index 6e9ecac..ea876d9 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -73,6 +73,11 @@ protected:
   void ExecuteAction();
 };
 
+class RewriteIncludesAction : public PreprocessorFrontendAction {
+protected:
+  void ExecuteAction();
+};
+
 }  // end namespace clang
 
 #endif
diff --git a/include/clang/Rewrite/Rewriters.h b/include/clang/Rewrite/Rewriters.h
index 203b9bc..9704fe3 100644
--- a/include/clang/Rewrite/Rewriters.h
+++ b/include/clang/Rewrite/Rewriters.h
@@ -18,6 +18,7 @@
 
 namespace clang {
 class Preprocessor;
+class PreprocessorOutputOptions;
 
 /// RewriteMacrosInInput - Implement -rewrite-macros mode.
 void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS);
@@ -25,6 +26,9 @@ void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS);
 /// DoRewriteTest - A simple test for the TokenRewriter class.
 void DoRewriteTest(Preprocessor &PP, raw_ostream *OS);
 
+/// RewriteIncludesInInput - Implement -rewrite-includes mode.
+void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts);
+
 }  // end namespace clang
 
 #endif
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 13a9897..e8dc20e 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -455,6 +455,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
   case frontend::PrintPreamble:          return "-print-preamble";
   case frontend::PrintPreprocessedInput: return "-E";
   case frontend::RewriteMacros:          return "-rewrite-macros";
+  case frontend::RewriteIncludes:        return "-rewrite-includes";
   case frontend::RewriteObjC:            return "-rewrite-objc";
   case frontend::RewriteTest:            return "-rewrite-test";
   case frontend::RunAnalysis:            return "-analyze";
@@ -1451,6 +1452,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
       Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
     case OPT_rewrite_macros:
       Opts.ProgramAction = frontend::RewriteMacros; break;
+    case OPT_rewrite_includes:
+      Opts.ProgramAction = frontend::RewriteIncludes; break;
     case OPT_rewrite_objc:
       Opts.ProgramAction = frontend::RewriteObjC; break;
     case OPT_rewrite_test:
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 07d2b8d..49d0bb8 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -73,6 +73,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
   case PrintPreamble:          return new PrintPreambleAction();
   case PrintPreprocessedInput: return new PrintPreprocessedAction();
   case RewriteMacros:          return new RewriteMacrosAction();
+  case RewriteIncludes:        return new RewriteIncludesAction();
   case RewriteObjC:            return new RewriteObjCAction();
   case RewriteTest:            return new RewriteTestAction();
   case RunAnalysis:            return new ento::AnalysisAction();
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a49ab04..65d96d8 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -2020,7 +2020,7 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
   // directly.
   FormTokenWithChars(Result, CurPtr, tok::comment);
 
-  if (!ParsingPreprocessorDirective)
+  if (!ParsingPreprocessorDirective || LexingRawMode)
     return true;
 
   // If this BCPL-style comment is in a macro definition, transmogrify it into
@@ -2622,7 +2622,8 @@ LexNextToken:
       ParsingPreprocessorDirective = false;
 
       // Restore comment saving mode, in case it was disabled for directive.
-      SetCommentRetentionState(PP->getCommentRetentionState());
+      if (!LexingRawMode)
+        SetCommentRetentionState(PP->getCommentRetentionState());
 
       // Since we consumed a newline, we are back at the start of a line.
       IsAtStartOfLine = true;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 53bb5c3..d69dad5 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -553,6 +553,22 @@ const FileEntry *Preprocessor::LookupFile(
 // Preprocessor Directive Handling.
 //===----------------------------------------------------------------------===//
 
+class Preprocessor::ResetMacroExpansionHelper
+{
+public:
+  ResetMacroExpansionHelper(Preprocessor*pp)
+    : PP(pp), save(pp->DisableMacroExpansion) {
+    if (pp->MacroExpansionInDirectivesOverride)
+      pp->DisableMacroExpansion = false;
+  }
+  ~ResetMacroExpansionHelper() {
+    PP->DisableMacroExpansion = save;
+  }
+private:
+  Preprocessor* PP;
+  bool save;
+};
+
 /// HandleDirective - This callback is invoked when the lexer sees a # token
 /// at the start of a line.  This consumes the directive, modifies the
 /// lexer/preprocessor state, and advances the lexer(s) so that the next token
@@ -604,6 +620,10 @@ void Preprocessor::HandleDirective(Token &Result) {
     Diag(Result, diag::ext_embedded_directive);
   }
 
+  // temporarily enable macro expansion if set so
+  // and reset to previous state when returning from this function
+  ResetMacroExpansionHelper helper(this);
+
 TryAgain:
   switch (Result.getKind()) {
   case tok::eod:
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 6142436..4c98f76 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -133,6 +133,7 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
   
   // Macro expansion is enabled.
   DisableMacroExpansion = false;
+  MacroExpansionInDirectivesOverride = false;
   InMacroArgs = false;
   NumCachedTokenLexers = 0;
   
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index 2a05040..8070ba2 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_library(clangRewrite
   FrontendActions.cpp
   HTMLPrint.cpp
   HTMLRewrite.cpp
+  RewriteIncludes.cpp
   RewriteMacros.cpp
   RewriteModernObjC.cpp
   RewriteObjC.cpp
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index 1753325..e462671 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/FrontendActions.cpp
@@ -181,3 +181,11 @@ void RewriteTestAction::ExecuteAction() {
 
   DoRewriteTest(CI.getPreprocessor(), OS);
 }
+
+void RewriteIncludesAction::ExecuteAction() {
+  CompilerInstance &CI = getCompilerInstance();
+  raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+  if (!OS) return;
+
+  RewriteIncludesInInput(CI.getPreprocessor(), OS, CI.getPreprocessorOutputOpts());
+}
diff --git a/test/Frontend/rewrite-includes.c b/test/Frontend/rewrite-includes.c
new file mode 100644
index 0000000..a165d32
--- /dev/null
+++ b/test/Frontend/rewrite-includes.c
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -verify -rewrite-includes -DFIRST %s -o %t
+// RUN: cat %t | FileCheck -strict-whitespace %s
+// STARTCOMPARE
+#define A(a,b) a ## b
+A(1,2)
+#include "rewrite-includes1.h"
+#ifdef FIRST
+#define HEADER "rewrite-includes3.h"
+#include HEADER
+#else
+#include "rewrite-includes4.h"
+#endif
+#/**/include /**/ "rewrite-includes5.h" /**/ \
+ 
+#include "rewrite-includes6.h" // comment
+ 
+#include "rewrite-includes6.h" /* comment
+                                  continues */
+// ENDCOMPARE
+
+// CHECK: {{^}}// STARTCOMPARE{{$}}
+// CHECK-NEXT: {{^}}#define A(a,b) a ## b{{$}}
+// CHECK-NEXT: {{^}}A(1,2){{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes1.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes1.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#pragma clang system_header{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes1.h" 3{{$}}
+// CHECK-NEXT: {{^}}included_line1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes2.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes2.h" 1 3{{$}}
+// CHECK-NEXT: {{^}}included_line2{{$}}
+// CHECK-NEXT: {{^}}# 3 "{{.*}}rewrite-includes1.h" 2 3{{$}}
+// CHECK-NEXT: {{^}}# 7 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#ifdef FIRST{{$}}
+// CHECK-NEXT: {{^}}#define HEADER "rewrite-includes3.h"{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include HEADER{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes3.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line3{{$}}
+// CHECK-NEXT: {{^}}# 10 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#else{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes4.h"{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 12 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}#endif{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#/**/include /**/ "rewrite-includes5.h" /**/ {{\\}}{{$}}
+// CHECK-NEXT: {{^}} {{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes5.h" 1{{$}}
+// CHECK-NEXT: {{^}}included_line5{{$}}
+// CHECK-NEXT: {{^}}# 15 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" // comment{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 1 "{{.*}}rewrite-includes6.h" 1{{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#pragma once{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 2 "{{.*}}rewrite-includes6.h"{{$}}
+// CHECK-NEXT: {{^}}included_line6{{$}}
+// CHECK-NEXT: {{^}}# 16 "{{.*}}rewrite-includes.c" 2{{$}}
+// CHECK-NEXT: {{^}} {{$}}
+// CHECK-NEXT: {{^}}#if 0 /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}#include "rewrite-includes6.h" /* comment{{$}}
+// CHECK-NEXT: {{^}}                                  continues */{{$}}
+// CHECK-NEXT: {{^}}#endif /* expanded by -rewrite-includes */{{$}}
+// CHECK-NEXT: {{^}}# 19 "{{.*}}rewrite-includes.c"{{$}}
+// CHECK-NEXT: {{^}}// ENDCOMPARE{{$}}
diff --git a/test/Frontend/rewrite-includes1.h b/test/Frontend/rewrite-includes1.h
new file mode 100644
index 0000000..1b6c80d
--- /dev/null
+++ b/test/Frontend/rewrite-includes1.h
@@ -0,0 +1,3 @@
+#pragma clang system_header
+included_line1
+#include "rewrite-includes2.h"
diff --git a/test/Frontend/rewrite-includes2.h b/test/Frontend/rewrite-includes2.h
new file mode 100644
index 0000000..1114e51
--- /dev/null
+++ b/test/Frontend/rewrite-includes2.h
@@ -0,0 +1 @@
+included_line2
diff --git a/test/Frontend/rewrite-includes3.h b/test/Frontend/rewrite-includes3.h
new file mode 100644
index 0000000..3757bc8
--- /dev/null
+++ b/test/Frontend/rewrite-includes3.h
@@ -0,0 +1 @@
+included_line3
diff --git a/test/Frontend/rewrite-includes4.h b/test/Frontend/rewrite-includes4.h
new file mode 100644
index 0000000..b4e25d2
--- /dev/null
+++ b/test/Frontend/rewrite-includes4.h
@@ -0,0 +1 @@
+included_line4
diff --git a/test/Frontend/rewrite-includes5.h b/test/Frontend/rewrite-includes5.h
new file mode 100644
index 0000000..934bf41
--- /dev/null
+++ b/test/Frontend/rewrite-includes5.h
@@ -0,0 +1 @@
+included_line5
diff --git a/test/Frontend/rewrite-includes6.h b/test/Frontend/rewrite-includes6.h
new file mode 100644
index 0000000..c18e501
--- /dev/null
+++ b/test/Frontend/rewrite-includes6.h
@@ -0,0 +1,2 @@
+#pragma once
+included_line6
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to