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