InclusionRewriter.cpp revision 959dc8475fc20ce8c3fd55021cb9f02a531cddc5
18c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie//===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// 28c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// 38c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// The LLVM Compiler Infrastructure 48c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// 58c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// This file is distributed under the University of Illinois Open Source 68c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// License. See LICENSE.TXT for details. 78c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// 88c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie//===----------------------------------------------------------------------===// 98c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// 108c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// This code rewrites include invocations into their expansions. This gives you 118c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// a file with all included files merged into it. 128c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie// 138c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie//===----------------------------------------------------------------------===// 148c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 15305c613af6cfc40e519c75d9d2c84c6fa9a841c0Ted Kremenek#include "clang/Rewrite/Frontend/Rewriters.h" 168c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie#include "clang/Basic/SourceManager.h" 178c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie#include "clang/Frontend/PreprocessorOutputOptions.h" 1855fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/Lex/Preprocessor.h" 198c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie#include "llvm/Support/raw_ostream.h" 208c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 218c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikieusing namespace clang; 228c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikieusing namespace llvm; 238c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 248c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikienamespace { 258c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 268c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikieclass InclusionRewriter : public PPCallbacks { 278c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie /// Information about which #includes were actually performed, 288c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie /// created by preprocessor callbacks. 298c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie struct FileChange { 308c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SourceLocation From; 318c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileID Id; 328c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind FileType; 338c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileChange(SourceLocation From) : From(From) { 348c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 358c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie }; 3649fdccb4595862828aa5cadc1497d466a8031ddaDmitri Gribenko Preprocessor &PP; ///< Used to find inclusion directives. 3749fdccb4595862828aa5cadc1497d466a8031ddaDmitri Gribenko SourceManager &SM; ///< Used to read and manage source files. 3849fdccb4595862828aa5cadc1497d466a8031ddaDmitri Gribenko raw_ostream &OS; ///< The destination stream for rewritten contents. 3949fdccb4595862828aa5cadc1497d466a8031ddaDmitri Gribenko bool ShowLineMarkers; ///< Show #line markers. 4049fdccb4595862828aa5cadc1497d466a8031ddaDmitri Gribenko bool UseLineDirective; ///< Use of line directives or line markers. 418c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie typedef std::map<unsigned, FileChange> FileChangeMap; 42959dc8475fc20ce8c3fd55021cb9f02a531cddc5Dmitri Gribenko FileChangeMap FileChanges; ///< Tracks which files were included where. 438c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie /// Used transitively for building up the FileChanges mapping over the 448c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie /// various \c PPCallbacks callbacks. 458c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileChangeMap::iterator LastInsertedFileChange; 468c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikiepublic: 478c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers); 488c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); 498c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikieprivate: 508c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, 518c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind FileType, 528c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileID PrevFID); 538c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie virtual void FileSkipped(const FileEntry &ParentFile, 548c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const Token &FilenameTok, 558c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind FileType); 568c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie virtual void InclusionDirective(SourceLocation HashLoc, 578c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const Token &IncludeTok, 588c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef FileName, 598c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool IsAngled, 60da313592441db36cf4b06be97c4bcc238ee6fa9cArgyrios Kyrtzidis CharSourceRange FilenameRange, 618c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const FileEntry *File, 628c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef SearchPath, 63f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis StringRef RelativePath, 64f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis const Module *Imported); 658c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie void WriteLineInfo(const char *Filename, int Line, 668c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind FileType, 678c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef EOL, StringRef Extra = StringRef()); 688c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie void OutputContentUpTo(const MemoryBuffer &FromFile, 698c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie unsigned &WriteFrom, unsigned WriteTo, 708c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef EOL, int &lines, 718c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool EnsureNewline = false); 728c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 738c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const MemoryBuffer &FromFile, StringRef EOL, 748c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie unsigned &NextToWrite, int &Lines); 758c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const FileChange *FindFileChangeLocation(SourceLocation Loc) const; 768c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); 778c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie}; 788c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 798c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} // end anonymous namespace 808c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 818c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Initializes an InclusionRewriter with a \p PP source and \p OS destination. 828c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid BlaikieInclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, 838c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool ShowLineMarkers) 848c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie : PP(PP), SM(PP.getSourceManager()), OS(OS), 858c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie ShowLineMarkers(ShowLineMarkers), 868c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie LastInsertedFileChange(FileChanges.end()) { 878c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // If we're in microsoft mode, use normal #line instead of line markers. 888c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie UseLineDirective = PP.getLangOpts().MicrosoftExt; 898c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 908c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 918c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Write appropriate line information as either #line directives or GNU line 928c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// markers depending on what mode we're in, including the \p Filename and 938c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// \p Line we are located at, using the specified \p EOL line separator, and 948c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// any \p Extra context specifiers in GNU line directives. 958c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid InclusionRewriter::WriteLineInfo(const char *Filename, int Line, 968c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind FileType, 978c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef EOL, StringRef Extra) { 988c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (!ShowLineMarkers) 998c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return; 1008c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (UseLineDirective) { 1018c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << "#line" << ' ' << Line << ' ' << '"' << Filename << '"'; 1028c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } else { 1038c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // Use GNU linemarkers as described here: 1048c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html 1058c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << '#' << ' ' << Line << ' ' << '"' << Filename << '"'; 1068c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (!Extra.empty()) 1078c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << Extra; 1088c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (FileType == SrcMgr::C_System) 1098c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // "`3' This indicates that the following text comes from a system header 1108c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // file, so certain warnings should be suppressed." 1118c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << " 3"; 1128c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie else if (FileType == SrcMgr::C_ExternCSystem) 1138c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // as above for `3', plus "`4' This indicates that the following text 1148c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // should be treated as being wrapped in an implicit extern "C" block." 1158c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << " 3 4"; 1168c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 1178c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << EOL; 1188c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 1198c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 1208c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// FileChanged - Whenever the preprocessor enters or exits a #include file 1218c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// it invokes this handler. 1228c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid InclusionRewriter::FileChanged(SourceLocation Loc, 1238c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileChangeReason Reason, 1248c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind NewFileType, 1258c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileID) { 1268c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (Reason != EnterFile) 1278c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return; 1288c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (LastInsertedFileChange == FileChanges.end()) 1298c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // we didn't reach this file (eg: the main file) via an inclusion directive 1308c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return; 1318c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID(); 1328c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie LastInsertedFileChange->second.FileType = NewFileType; 1338c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie LastInsertedFileChange = FileChanges.end(); 1348c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 1358c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 1368c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Called whenever an inclusion is skipped due to canonical header protection 1378c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// macros. 1388c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/, 1398c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const Token &/*FilenameTok*/, 1408c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind /*FileType*/) { 1418c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't " 1428c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie "found via an inclusion directive, was skipped"); 1438c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileChanges.erase(LastInsertedFileChange); 1448c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie LastInsertedFileChange = FileChanges.end(); 1458c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 1468c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 1478c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// This should be called whenever the preprocessor encounters include 1488c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// directives. It does not say whether the file has been included, but it 1498c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// provides more information about the directive (hash location instead 1508c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// of location inside the included file). It is assumed that the matching 1518c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// FileChanged() or FileSkipped() is called after this. 1528c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid InclusionRewriter::InclusionDirective(SourceLocation HashLoc, 1538c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const Token &/*IncludeTok*/, 1548c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef /*FileName*/, 1558c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool /*IsAngled*/, 156da313592441db36cf4b06be97c4bcc238ee6fa9cArgyrios Kyrtzidis CharSourceRange /*FilenameRange*/, 1578c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const FileEntry * /*File*/, 1588c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef /*SearchPath*/, 159f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis StringRef /*RelativePath*/, 1602ec1d13063fe11730f4a0005ee39299a1145a98aAaron Ballman const Module * /*Imported*/) { 1618c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " 1628c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie "directive was found before the previous one was processed"); 1638c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert( 1648c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc))); 1658c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie assert(p.second && "Unexpected revisitation of the same include directive"); 1668c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie LastInsertedFileChange = p.first; 1678c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 1688c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 1698c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Simple lookup for a SourceLocation (specifically one denoting the hash in 1708c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// an inclusion directive) in the map of inclusion information, FileChanges. 1718c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikieconst InclusionRewriter::FileChange * 1728c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid BlaikieInclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const { 1738c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding()); 1748c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (I != FileChanges.end()) 1758c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return &I->second; 1768c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return NULL; 1778c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 1788c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 1798c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Detect the likely line ending style of \p FromFile by examining the first 1808c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// newline found within it. 1818c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikiestatic StringRef DetectEOL(const MemoryBuffer &FromFile) { 1828c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // detect what line endings the file uses, so that added content does not mix 1838c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // the style 1848c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const char *Pos = strchr(FromFile.getBufferStart(), '\n'); 1858c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (Pos == NULL) 1868c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return "\n"; 1878c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') 1888c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return "\n\r"; 1898c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') 1908c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return "\r\n"; 1918c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return "\n"; 1928c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 1938c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 1948c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 1958c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// \p WriteTo - 1. 1968c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, 1978c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie unsigned &WriteFrom, unsigned WriteTo, 1988c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef EOL, int &Line, 1998c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool EnsureNewline) { 2008c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (WriteTo <= WriteFrom) 2018c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return; 2028c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom); 2038c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // count lines manually, it's faster than getPresumedLoc() 2043159819ed71a2e814175a593147f7637a423ba56Benjamin Kramer Line += std::count(FromFile.getBufferStart() + WriteFrom, 2053159819ed71a2e814175a593147f7637a423ba56Benjamin Kramer FromFile.getBufferStart() + WriteTo, '\n'); 2068c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (EnsureNewline) { 2078c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie char LastChar = FromFile.getBufferStart()[WriteTo - 1]; 2088c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (LastChar != '\n' && LastChar != '\r') 2098c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS << EOL; 2108c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 2118c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie WriteFrom = WriteTo; 2128c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 2138c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2148c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Print characters from \p FromFile starting at \p NextToWrite up until the 2158c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// inclusion directive at \p StartToken, then print out the inclusion 2168c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// inclusion directive disabled by a #if directive, updating \p NextToWrite 2178c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// and \p Line to track the number of source lines visited and the progress 2188c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// through the \p FromFile buffer. 2198c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 2208c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const Token &StartToken, 2218c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const MemoryBuffer &FromFile, 2228c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef EOL, 2238c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie unsigned &NextToWrite, int &Line) { 2248c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OutputContentUpTo(FromFile, NextToWrite, 2258c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SM.getFileOffset(StartToken.getLocation()), EOL, Line); 2268c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Token DirectiveToken; 2278c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie do { 2288c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie DirectiveLex.LexFromRawLexer(DirectiveToken); 2298c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 23060ad16b7e24cdb88c577c107b69da85458000858David Blaikie OS << "#if 0 /* expanded by -frewrite-includes */" << EOL; 2318c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OutputContentUpTo(FromFile, NextToWrite, 2328c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(), 2338c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie EOL, Line); 23460ad16b7e24cdb88c577c107b69da85458000858David Blaikie OS << "#endif /* expanded by -frewrite-includes */" << EOL; 2358c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 2368c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2378c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Find the next identifier in the pragma directive specified by \p RawToken. 2388c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid BlaikieStringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, 2398c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Token &RawToken) { 2408c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.LexFromRawLexer(RawToken); 2418c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (RawToken.is(tok::raw_identifier)) 2428c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie PP.LookUpIdentifierInfo(RawToken); 2438c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (RawToken.is(tok::identifier)) 2448c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return RawToken.getIdentifierInfo()->getName(); 2458c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return StringRef(); 2468c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 2478c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2488c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it 2498c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie/// and including content of included files recursively. 2508c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikiebool InclusionRewriter::Process(FileID FileId, 2518c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SrcMgr::CharacteristicKind FileType) 2528c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie{ 2538c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie bool Invalid; 2548c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); 255bae2b31822e3c2139b5f8fbb127e4c5674cce6dbDavid Blaikie if (Invalid) // invalid inclusion 256bae2b31822e3c2139b5f8fbb127e4c5674cce6dbDavid Blaikie return true; 2578c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const char *FileName = FromFile.getBufferIdentifier(); 2588c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); 2598c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.SetCommentRetentionState(false); 2608c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2618c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef EOL = DetectEOL(FromFile); 2628c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2638c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // Per the GNU docs: "1" indicates the start of a new file. 2648c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie WriteLineInfo(FileName, 1, FileType, EOL, " 1"); 2658c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2668c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (SM.getFileIDSize(FileId) == 0) 2678c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return true; 2688c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2698c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // The next byte to be copied from the source file 2708c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie unsigned NextToWrite = 0; 2718c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie int Line = 1; // The current input file line number. 2728c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2738c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Token RawToken; 2748c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.LexFromRawLexer(RawToken); 2758c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 2768c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // TODO: Consider adding a switch that strips possibly unimportant content, 2778c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // such as comments, to reduce the size of repro files. 2788c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie while (RawToken.isNot(tok::eof)) { 2798c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { 2808c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.setParsingPreprocessorDirective(true); 2818c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Token HashToken = RawToken; 2828c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.LexFromRawLexer(RawToken); 2838c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (RawToken.is(tok::raw_identifier)) 2848c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie PP.LookUpIdentifierInfo(RawToken); 2858c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (RawToken.is(tok::identifier)) { 2868c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { 2878c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie case tok::pp_include: 2888c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie case tok::pp_include_next: 2898c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie case tok::pp_import: { 2908c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, 2918c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Line); 2928c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (const FileChange *Change = FindFileChangeLocation( 2938c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie HashToken.getLocation())) { 2948c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // now include and recursively process the file 2958c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (Process(Change->Id, Change->FileType)) 2968c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // and set lineinfo back to this file, if the nested one was 2978c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // actually included 2988c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // `2' indicates returning to a file (after having included 2998c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // another file. 3008c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie WriteLineInfo(FileName, Line, FileType, EOL, " 2"); 3018c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } else 3028c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // fix up lineinfo (since commented out directive changed line 3038c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // numbers) for inclusions that were skipped due to header guards 3048c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie WriteLineInfo(FileName, Line, FileType, EOL); 3058c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie break; 3068c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3078c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie case tok::pp_pragma: { 3088c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie StringRef Identifier = NextIdentifierName(RawLex, RawToken); 3098c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (Identifier == "clang" || Identifier == "GCC") { 3108c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie if (NextIdentifierName(RawLex, RawToken) == "system_header") { 3118c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // keep the directive in, commented out 3128c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie CommentOutDirective(RawLex, HashToken, FromFile, EOL, 3138c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie NextToWrite, Line); 3148c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // update our own type 3158c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie FileType = SM.getFileCharacteristic(RawToken.getLocation()); 3168c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie WriteLineInfo(FileName, Line, FileType, EOL); 3178c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3188c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } else if (Identifier == "once") { 3198c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // keep the directive in, commented out 3208c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie CommentOutDirective(RawLex, HashToken, FromFile, EOL, 3218c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie NextToWrite, Line); 3228c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie WriteLineInfo(FileName, Line, FileType, EOL); 3238c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3248c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie break; 3258c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3268c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie default: 3278c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie break; 3288c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3298c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3308c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.setParsingPreprocessorDirective(false); 3318c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3328c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie RawLex.LexFromRawLexer(RawToken); 3338c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } 3348c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OutputContentUpTo(FromFile, NextToWrite, 3358c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SM.getFileOffset(SM.getLocForEndOfFile(FileId)) + 1, EOL, Line, 3368c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie /*EnsureNewline*/true); 3378c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie return true; 3388c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 3398c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 34060ad16b7e24cdb88c577c107b69da85458000858David Blaikie/// InclusionRewriterInInput - Implement -frewrite-includes mode. 3418c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikievoid clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, 3428c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie const PreprocessorOutputOptions &Opts) { 3438c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie SourceManager &SM = PP.getSourceManager(); 3448c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS, 3458c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Opts.ShowLineMarkers); 3468c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie PP.addPPCallbacks(Rewrite); 3478c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie 3488c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // First let the preprocessor process the entire file and call callbacks. 3498c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // Callbacks will record which #include's were actually performed. 3508c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie PP.EnterMainSourceFile(); 3518c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Token Tok; 3528c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // Only preprocessor directives matter here, so disable macro expansion 3538c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // everywhere else as an optimization. 3548c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // TODO: It would be even faster if the preprocessor could be switched 3558c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // to a mode where it would parse only preprocessor directives and comments, 3568c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie // nothing else matters for parsing or processing. 3578c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie PP.SetMacroExpansionOnlyInDirectives(); 3588c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie do { 3598c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie PP.Lex(Tok); 3608c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie } while (Tok.isNot(tok::eof)); 3618c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); 3628c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie OS->flush(); 3638c0b3787e7ccc7978b42dfbb84da2b802c743a5dDavid Blaikie} 364