On Friday 23 of March 2012, Matt Beaumont-Gay wrote:
> A few general comments:
> - No extra whitespace inside delimiters -- "if (foo)", not "if ( foo
> )", and similarly for [] and <>.
> - Get to know the naming rules in the style guide, and adjust
> capitalization accordingly:
> http://llvm.org/docs/CodingStandards.html#ll_naming
The thing is, I do know about that page and I tried to follow it, so
apparently I can't do it on my own (and the fact that the codebase is
inconsistent on this anyway and I find this style poorly readable is not
helping). What is the command to automatically format the file to fit your
requirements?
> std::list< FileChange > FileChanges;
>
> Prefer std::vector -- no reason to use std::list here.
I've meanwhile confirmed that it should be actually std::map for noticeably
better performance.
> - Use StringRef in preference to passing a char* and length (e.g. in
> WriteLineInfo):
> http://llvm.org/docs/ProgrammersManual.html#string_apis
> if (type == SrcMgr::C_System)
> OS.write(" 3", 2);
> else if (type == SrcMgr::C_ExternCSystem)
> OS.write(" 3 4", 4);
>
> Why OS.write and not operator<< here?
Because I reused code from PrintPreprocessedOutput.cpp .
> - Lines should be shorter than 80 columns.
> for (std::list< FileChange >::const_iterator it
> = FileChanges.begin(), end = FileChanges.end();
>
> Funny line break here -- prefer breaking after the comma.
You need to pick your poison. C++ code generally does not fit into 80 columns
and look nice at the same time.
> OutputContentsUpTo(SM.getFileOffset(DirectiveToken.getLocation())
> + DirectiveToken.getLength(), nextToWrite, FromFile);
>
> If you have to break a line on one side of a binary operator, prefer
> to break after the operator rather than before.
In addition to the above, why should I do that? The operator makes it obvious
why the previous line continues there.
> // 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).
>
> The second sentence here is speculative. Remove the comment entirely,
> or keep the first sentence with "FIXME:" at the front.
It is not speculative. There's also nothing broken to fix, it is a suggestion
for an alternative mode that would have its advantages and disadvantages.
> // clang sometimes optimizes and does not repeatedly include
> some // files even though it should,
>
> Please elaborate?
Clang does not even bother to perform repeated inclusion of the same file if
it somehow detects it's unnecessary, but the avoided FileChanged() callback
would mean -rewrite-includes would otherwise leave some #include directives
in the result that would be performed the next time.
> // 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.
>
> Technically true, I'm sure, but have you profiled it and found that it
> would actually matter?
I have done some profiling, yes, and lexing is the majority of time. And
scanning only for / and \n simply has to be faster. But that is a possible
improvement for the future and I will not work on this now (although the tone
of your mail sounds like new potential contributors need to have their zeal
thoroughly tested by requiring them to submit something that is perfect, in
case they soon break down from all the nitpicks and run away before making
any further improvements).
Updated version attached.
--
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 IncludeRewriter : 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::map< unsigned, FileChange > FileChanges;
unsigned LastInsertedFileChange;
public:
IncludeRewriter(Preprocessor &pp, raw_ostream &os, bool lineMarkers)
: PP(pp), SM(PP.getSourceManager()),
OS(os), DisableLineMarkers(lineMarkers), LastInsertedFileChange(0) {
// 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* EOL, StringRef Extra = StringRef());
void OutputContentUpTo(unsigned writeEnd, unsigned& NextToWrite,
int& Lines, const char* EOL,
const llvm::MemoryBuffer* FromFile,
bool EnsureNewline = false);
void CommentOutDirective(Lexer& DirectivesLex, const Token& StartToken,
unsigned& NextToWrite, int& Lines,
const char* EOL, const llvm::MemoryBuffer* FromFile);
const FileChange* FindFileChangeLocation(SourceLocation Loc) const;
StringRef NextIdentifierName(Lexer& RawLex, Token& RawToken);
};
} // end anonymous namespace
void IncludeRewriter::WriteLineInfo(const char* filename, int line,
SrcMgr::CharacteristicKind type,
const char* EOL, StringRef Extra) {
// Emit #line directives or GNU line markers depending on what mode we're in.
if (UseLineDirective) {
OS << "#line" << ' ' << line << ' ' << '"' << filename << '"';
} else {
OS << '#' << ' ' << line << ' ' << '"' << filename << '"';
if (!Extra.empty())
OS.write(Extra.data(), Extra.size());
if (type == SrcMgr::C_System)
OS << " 3";
else if (type == SrcMgr::C_ExternCSystem)
OS << " 3 4";
}
OS << EOL;
}
/// FileChanged - Whenever the preprocessor enters or exits a #include file
/// it invokes this handler.
void IncludeRewriter::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 (LastInsertedFileChange != 0) { // there may be e.g. "<built-in>" first
FileChange& ref = FileChanges[ LastInsertedFileChange ];
ref.id = id;
ref.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 IncludeRewriter::InclusionDirective(SourceLocation HashLoc,
const Token&,
StringRef,
bool,
const FileEntry*,
SourceLocation,
StringRef,
StringRef) {
FileChange change;
change.from = HashLoc;
LastInsertedFileChange = HashLoc.getRawEncoding();
FileChanges[ LastInsertedFileChange ] = change;
}
const IncludeRewriter::FileChange*
IncludeRewriter::FindFileChangeLocation(SourceLocation Loc) const {
std::map< unsigned, FileChange >::const_iterator find
= FileChanges.find( Loc.getRawEncoding());
if( find != FileChanges.end())
return &find->second;
return NULL;
}
inline unsigned CountNewLines(const char* pos, int len) {
const char* end = pos + len;
unsigned Lines = 0;
--pos;
while ((pos = static_cast<const char*>(memchr(pos + 1, '\n', end - pos - 1))))
++Lines;
return Lines;
}
static const char* DetectEOL(const llvm::MemoryBuffer* FromFile) {
// detect what line endings the file uses, so that added content does not mix
// the style
const char* pos = strchr(FromFile->getBufferStart(), '\n');
if (pos == NULL)
return "\n";
if (pos + 1 < FromFile->getBufferEnd() && *pos == '\r')
return "\n\r";
if (pos - 1 >= FromFile->getBufferStart() && *pos == '\r')
return "\r\n";
return "\n";
}
/// Copies next yet written file content up (and not including writeEnd).
void IncludeRewriter::OutputContentUpTo(unsigned writeEnd,
unsigned& NextToWrite,
int& Lines, const char* EOL,
const llvm::MemoryBuffer* FromFile,
bool EnsureNewline) {
if (writeEnd > NextToWrite) {
OS.write(FromFile->getBufferStart() + NextToWrite, writeEnd - NextToWrite);
// count lines manually, it's faster than getPresumedLoc()
Lines += CountNewLines(FromFile->getBufferStart() + NextToWrite,
writeEnd - NextToWrite);
if (EnsureNewline) {
char LastChar = FromFile->getBufferStart()[ writeEnd - 1 ];
if (LastChar != '\n' && LastChar != '\r')
OS << EOL;
}
NextToWrite = writeEnd;
}
}
void IncludeRewriter::CommentOutDirective(Lexer& DirectiveLex,
const Token& StartToken,
unsigned& NextToWrite, int& Lines,
const char* EOL,
const llvm::MemoryBuffer* FromFile) {
OutputContentUpTo(SM.getFileOffset(StartToken.getLocation()), NextToWrite,
Lines, EOL, FromFile);
Token DirectiveToken;
do {
DirectiveLex.LexFromRawLexer(DirectiveToken);
} while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
OS << "#if 0 /* expanded by -rewrite-includes */" << EOL;
OutputContentUpTo(SM.getFileOffset(DirectiveToken.getLocation())
+ DirectiveToken.getLength(), NextToWrite, Lines, EOL, FromFile);
OS << "#endif /* expanded by -rewrite-includes */" << EOL;
}
StringRef IncludeRewriter::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 IncludeRewriter::Process( FileID fileId, SrcMgr::CharacteristicKind type )
{
bool Invalid;
const char* FileName = SM.getBufferName(SM.getLocForStartOfFile(fileId),
&Invalid);
if (Invalid)
return false;
// Use a raw lexer to analyze the input file, incrementally copying parts of
// it and including content of included files recursively.
const llvm::MemoryBuffer *FromFile = SM.getBuffer( fileId );
Lexer RawLex(fileId, FromFile, PP.getSourceManager(), PP.getLangOpts());
RawLex.SetCommentRetentionState(false);
const char* EOL = DetectEOL(FromFile);
WriteLineInfo( FileName, 1, type, EOL, StringRef(" 1", 2 ));
if (SM.getFileIDSize(fileId) == 0)
return true;
// file position from which the content has not yet been copied to the output
unsigned NextToWrite = 0;
int Lines = 1; // current input file line number
Token RawToken;
RawLex.LexFromRawLexer(RawToken);
// It might be beneficial to have a switch that will remove content of lines
// that are irrevelant for compile, i.e. comments. Comments are actually
// a significant part 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
CommentOutDirective(RawLex, HashToken, NextToWrite, Lines, EOL,
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(FileName, Lines, type, EOL, StringRef(" 2", 2));
NeedFixup = false;
}
}
if( NeedFixup )
WriteLineInfo(FileName, Lines, type, EOL);
break;
}
case tok::pp_pragma: {
StringRef Identifier = NextIdentifierName(RawLex, RawToken);
if (Identifier == "clang" || Identifier == "GCC" ) {
if (NextIdentifierName(RawLex, RawToken) == "system_header") {
// keep the directive in, commented out
CommentOutDirective(RawLex, HashToken, NextToWrite, Lines,
EOL, FromFile);
// update our own type
type = SM.getFileCharacteristic(RawToken.getLocation());
WriteLineInfo(FileName, Lines, type, EOL);
}
} else if (Identifier == "once") {
// keep the directive in, commented out
CommentOutDirective(RawLex, HashToken, NextToWrite, Lines,
EOL, FromFile);
WriteLineInfo(FileName, Lines, type, EOL);
}
break;
}
default:
break;
}
}
RawLex.setParsingPreprocessorDirective(false);
RawLex.SetCommentRetentionState(false);
}
RawLex.LexFromRawLexer(RawToken);
}
OutputContentUpTo(SM.getFileOffset(SM.getLocForEndOfFile(fileId)) + 1,
NextToWrite, Lines, EOL, FromFile, true);
return true;
}
/// RewriteIncludesInInput - Implement -rewrite-includes mode.
void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
const PreprocessorOutputOptions &Opts) {
SourceManager &SM = PP.getSourceManager();
IncludeRewriter* Rewrite = new IncludeRewriter(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..75579d3 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,12 @@ 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/Inputs/rewrite-includes1.h b/test/Frontend/Inputs/rewrite-includes1.h
new file mode 100644
index 0000000..1b6c80d
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes1.h
@@ -0,0 +1,3 @@
+#pragma clang system_header
+included_line1
+#include "rewrite-includes2.h"
diff --git a/test/Frontend/Inputs/rewrite-includes2.h b/test/Frontend/Inputs/rewrite-includes2.h
new file mode 100644
index 0000000..1114e51
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes2.h
@@ -0,0 +1 @@
+included_line2
diff --git a/test/Frontend/Inputs/rewrite-includes3.h b/test/Frontend/Inputs/rewrite-includes3.h
new file mode 100644
index 0000000..3757bc8
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes3.h
@@ -0,0 +1 @@
+included_line3
diff --git a/test/Frontend/Inputs/rewrite-includes4.h b/test/Frontend/Inputs/rewrite-includes4.h
new file mode 100644
index 0000000..b4e25d2
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes4.h
@@ -0,0 +1 @@
+included_line4
diff --git a/test/Frontend/Inputs/rewrite-includes5.h b/test/Frontend/Inputs/rewrite-includes5.h
new file mode 100644
index 0000000..934bf41
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes5.h
@@ -0,0 +1 @@
+included_line5
diff --git a/test/Frontend/Inputs/rewrite-includes6.h b/test/Frontend/Inputs/rewrite-includes6.h
new file mode 100644
index 0000000..c18e501
--- /dev/null
+++ b/test/Frontend/Inputs/rewrite-includes6.h
@@ -0,0 +1,2 @@
+#pragma once
+included_line6
diff --git a/test/Frontend/rewrite-includes.c b/test/Frontend/rewrite-includes.c
new file mode 100644
index 0000000..fbe901f
--- /dev/null
+++ b/test/Frontend/rewrite-includes.c
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -verify -rewrite-includes -DFIRST -I %S/Inputs %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 "{{.*}}/Inputs/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: {{^}}# 2 "{{.*}}/Inputs/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 "{{.*}}/Inputs/rewrite-includes2.h" 1 3{{$}}
+// CHECK-NEXT: {{^}}included_line2{{$}}
+// CHECK-NEXT: {{^}}# 4 "{{.*}}/Inputs/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 "{{.*}}/Inputs/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 "{{.*}}/Inputs/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 "{{.*}}/Inputs/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 "{{.*}}/Inputs/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{{$}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits