diff options
Diffstat (limited to 'lib/Rewrite/Frontend/InclusionRewriter.cpp')
-rw-r--r-- | lib/Rewrite/Frontend/InclusionRewriter.cpp | 71 |
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(); } |