summaryrefslogtreecommitdiffstats
path: root/lib/Rewrite/Frontend/InclusionRewriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Rewrite/Frontend/InclusionRewriter.cpp')
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp71
1 files changed, 63 insertions, 8 deletions
diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp
index 878be84..71ceb5f 100644
--- a/lib/Rewrite/Frontend/InclusionRewriter.cpp
+++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -39,6 +40,7 @@ class InclusionRewriter : public PPCallbacks {
Preprocessor &PP; ///< Used to find inclusion directives.
SourceManager &SM; ///< Used to read and manage source files.
raw_ostream &OS; ///< The destination stream for rewritten contents.
+ const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines.
bool ShowLineMarkers; ///< Show #line markers.
bool UseLineDirective; ///< Use of line directives or line markers.
typedef std::map<unsigned, FileChange> FileChangeMap;
@@ -49,6 +51,9 @@ class InclusionRewriter : public PPCallbacks {
public:
InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers);
bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
+ void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
+ PredefinesBuffer = Buf;
+ }
private:
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -88,7 +93,7 @@ private:
/// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers)
- : PP(PP), SM(PP.getSourceManager()), OS(OS),
+ : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(0),
ShowLineMarkers(ShowLineMarkers),
LastInsertedFileChange(FileChanges.end()) {
// If we're in microsoft mode, use normal #line instead of line markers.
@@ -105,11 +110,15 @@ void InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
if (!ShowLineMarkers)
return;
if (UseLineDirective) {
- OS << "#line" << ' ' << Line << ' ' << '"' << Filename << '"';
+ OS << "#line" << ' ' << Line << ' ' << '"';
+ OS.write_escaped(Filename);
+ OS << '"';
} else {
// Use GNU linemarkers as described here:
// http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
- OS << '#' << ' ' << Line << ' ' << '"' << Filename << '"';
+ OS << '#' << ' ' << Line << ' ' << '"';
+ OS.write_escaped(Filename);
+ OS << '"';
if (!Extra.empty())
OS << Extra;
if (FileType == SrcMgr::C_System)
@@ -213,6 +222,11 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
bool EnsureNewline) {
if (WriteTo <= WriteFrom)
return;
+ if (&FromFile == PredefinesBuffer) {
+ // Ignore the #defines of the predefines buffer.
+ WriteFrom = WriteTo;
+ return;
+ }
OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom);
// count lines manually, it's faster than getPresumedLoc()
Line += std::count(FromFile.getBufferStart() + WriteFrom,
@@ -328,7 +342,7 @@ bool InclusionRewriter::HandleHasInclude(
return true;
}
-/// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it
+/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
/// and including content of included files recursively.
bool InclusionRewriter::Process(FileID FileId,
SrcMgr::CharacteristicKind FileType)
@@ -353,6 +367,11 @@ bool InclusionRewriter::Process(FileID FileId,
unsigned NextToWrite = 0;
int Line = 1; // The current input file line number.
+ // Ignore UTF-8 BOM, otherwise it'd end up somewhere else than the start
+ // of the resulting file.
+ if (FromFile.getBuffer().startswith("\xEF\xBB\xBF"))
+ NextToWrite = 3;
+
Token RawToken;
RawLex.LexFromRawLexer(RawToken);
@@ -365,7 +384,7 @@ bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
if (RawToken.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawToken);
- if (RawToken.is(tok::identifier) || RawToken.is(tok::kw_if)) {
+ if (RawToken.getIdentifierInfo() != NULL) {
switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_include_next:
@@ -412,7 +431,9 @@ bool InclusionRewriter::Process(FileID FileId,
break;
}
case tok::pp_if:
- case tok::pp_elif:
+ case tok::pp_elif: {
+ bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() ==
+ tok::pp_elif);
// Rewrite special builtin macros to avoid pulling in host details.
do {
// Walk over the directive.
@@ -453,8 +474,33 @@ bool InclusionRewriter::Process(FileID FileId,
OS << "*/";
}
} while (RawToken.isNot(tok::eod));
-
+ if (elif) {
+ OutputContentUpTo(FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) +
+ RawToken.getLength(),
+ EOL, Line, /*EnsureNewLine*/ true);
+ WriteLineInfo(FileName, Line, FileType, EOL);
+ }
break;
+ }
+ case tok::pp_endif:
+ case tok::pp_else: {
+ // We surround every #include by #if 0 to comment it out, but that
+ // changes line numbers. These are fixed up right after that, but
+ // the whole #include could be inside a preprocessor conditional
+ // that is not processed. So it is necessary to fix the line
+ // numbers one the next line after each #else/#endif as well.
+ RawLex.SetKeepWhitespaceMode(true);
+ do {
+ RawLex.LexFromRawLexer(RawToken);
+ } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof));
+ OutputContentUpTo(
+ FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) + RawToken.getLength(),
+ EOL, Line, /*EnsureNewLine*/ true);
+ WriteLineInfo(FileName, Line, FileType, EOL);
+ RawLex.SetKeepWhitespaceMode(false);
+ }
default:
break;
}
@@ -464,7 +510,7 @@ bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
}
OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(SM.getLocForEndOfFile(FileId)) + 1, EOL, Line,
+ SM.getFileOffset(SM.getLocForEndOfFile(FileId)), EOL, Line,
/*EnsureNewline*/true);
return true;
}
@@ -476,6 +522,13 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS,
Opts.ShowLineMarkers);
PP.addPPCallbacks(Rewrite);
+ // Ignore all pragmas, otherwise there will be warnings about unknown pragmas
+ // (because there's nothing to handle them).
+ PP.AddPragmaHandler(new EmptyPragmaHandler());
+ // Ignore also all pragma in all namespaces created
+ // in Preprocessor::RegisterBuiltinPragmas().
+ PP.AddPragmaHandler("GCC", new EmptyPragmaHandler());
+ PP.AddPragmaHandler("clang", new EmptyPragmaHandler());
// First let the preprocessor process the entire file and call callbacks.
// Callbacks will record which #include's were actually performed.
@@ -490,6 +543,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
+ Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
+ Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User);
OS->flush();
}
OpenPOWER on IntegriCloud