InclusionRewriter.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. //===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This code rewrites include invocations into their expansions. This gives you
  11. // a file with all included files merged into it.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "clang/Rewrite/Frontend/Rewriters.h"
  15. #include "clang/Basic/SourceManager.h"
  16. #include "clang/Frontend/PreprocessorOutputOptions.h"
  17. #include "clang/Lex/HeaderSearch.h"
  18. #include "clang/Lex/Pragma.h"
  19. #include "clang/Lex/Preprocessor.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/Support/raw_ostream.h"
  22. using namespace clang;
  23. using namespace llvm;
  24. namespace {
  25. class InclusionRewriter : public PPCallbacks {
  26. /// Information about which #includes were actually performed,
  27. /// created by preprocessor callbacks.
  28. struct FileChange {
  29. const Module *Mod;
  30. SourceLocation From;
  31. FileID Id;
  32. SrcMgr::CharacteristicKind FileType;
  33. FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) {
  34. }
  35. };
  36. Preprocessor &PP; ///< Used to find inclusion directives.
  37. SourceManager &SM; ///< Used to read and manage source files.
  38. raw_ostream &OS; ///< The destination stream for rewritten contents.
  39. const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines.
  40. bool ShowLineMarkers; ///< Show #line markers.
  41. bool UseLineDirective; ///< Use of line directives or line markers.
  42. typedef std::map<unsigned, FileChange> FileChangeMap;
  43. FileChangeMap FileChanges; ///< Tracks which files were included where.
  44. /// Used transitively for building up the FileChanges mapping over the
  45. /// various \c PPCallbacks callbacks.
  46. FileChangeMap::iterator LastInsertedFileChange;
  47. public:
  48. InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers);
  49. bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
  50. void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
  51. PredefinesBuffer = Buf;
  52. }
  53. private:
  54. void FileChanged(SourceLocation Loc, FileChangeReason Reason,
  55. SrcMgr::CharacteristicKind FileType,
  56. FileID PrevFID) override;
  57. void FileSkipped(const FileEntry &ParentFile, const Token &FilenameTok,
  58. SrcMgr::CharacteristicKind FileType) override;
  59. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  60. StringRef FileName, bool IsAngled,
  61. CharSourceRange FilenameRange, const FileEntry *File,
  62. StringRef SearchPath, StringRef RelativePath,
  63. const Module *Imported) override;
  64. void WriteLineInfo(const char *Filename, int Line,
  65. SrcMgr::CharacteristicKind FileType,
  66. StringRef EOL, StringRef Extra = StringRef());
  67. void WriteImplicitModuleImport(const Module *Mod, StringRef EOL);
  68. void OutputContentUpTo(const MemoryBuffer &FromFile,
  69. unsigned &WriteFrom, unsigned WriteTo,
  70. StringRef EOL, int &lines,
  71. bool EnsureNewline);
  72. void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
  73. const MemoryBuffer &FromFile, StringRef EOL,
  74. unsigned &NextToWrite, int &Lines);
  75. bool HandleHasInclude(FileID FileId, Lexer &RawLex,
  76. const DirectoryLookup *Lookup, Token &Tok,
  77. bool &FileExists);
  78. const FileChange *FindFileChangeLocation(SourceLocation Loc) const;
  79. StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
  80. };
  81. } // end anonymous namespace
  82. /// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
  83. InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
  84. bool ShowLineMarkers)
  85. : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(nullptr),
  86. ShowLineMarkers(ShowLineMarkers),
  87. LastInsertedFileChange(FileChanges.end()) {
  88. // If we're in microsoft mode, use normal #line instead of line markers.
  89. UseLineDirective = PP.getLangOpts().MicrosoftExt;
  90. }
  91. /// Write appropriate line information as either #line directives or GNU line
  92. /// markers depending on what mode we're in, including the \p Filename and
  93. /// \p Line we are located at, using the specified \p EOL line separator, and
  94. /// any \p Extra context specifiers in GNU line directives.
  95. void InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
  96. SrcMgr::CharacteristicKind FileType,
  97. StringRef EOL, StringRef Extra) {
  98. if (!ShowLineMarkers)
  99. return;
  100. if (UseLineDirective) {
  101. OS << "#line" << ' ' << Line << ' ' << '"';
  102. OS.write_escaped(Filename);
  103. OS << '"';
  104. } else {
  105. // Use GNU linemarkers as described here:
  106. // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
  107. OS << '#' << ' ' << Line << ' ' << '"';
  108. OS.write_escaped(Filename);
  109. OS << '"';
  110. if (!Extra.empty())
  111. OS << Extra;
  112. if (FileType == SrcMgr::C_System)
  113. // "`3' This indicates that the following text comes from a system header
  114. // file, so certain warnings should be suppressed."
  115. OS << " 3";
  116. else if (FileType == SrcMgr::C_ExternCSystem)
  117. // as above for `3', plus "`4' This indicates that the following text
  118. // should be treated as being wrapped in an implicit extern "C" block."
  119. OS << " 3 4";
  120. }
  121. OS << EOL;
  122. }
  123. void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod,
  124. StringRef EOL) {
  125. OS << "@import " << Mod->getFullModuleName() << ";"
  126. << " /* clang -frewrite-includes: implicit import */" << EOL;
  127. }
  128. /// FileChanged - Whenever the preprocessor enters or exits a #include file
  129. /// it invokes this handler.
  130. void InclusionRewriter::FileChanged(SourceLocation Loc,
  131. FileChangeReason Reason,
  132. SrcMgr::CharacteristicKind NewFileType,
  133. FileID) {
  134. if (Reason != EnterFile)
  135. return;
  136. if (LastInsertedFileChange == FileChanges.end())
  137. // we didn't reach this file (eg: the main file) via an inclusion directive
  138. return;
  139. LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID();
  140. LastInsertedFileChange->second.FileType = NewFileType;
  141. LastInsertedFileChange = FileChanges.end();
  142. }
  143. /// Called whenever an inclusion is skipped due to canonical header protection
  144. /// macros.
  145. void InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/,
  146. const Token &/*FilenameTok*/,
  147. SrcMgr::CharacteristicKind /*FileType*/) {
  148. assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't "
  149. "found via an inclusion directive, was skipped");
  150. FileChanges.erase(LastInsertedFileChange);
  151. LastInsertedFileChange = FileChanges.end();
  152. }
  153. /// This should be called whenever the preprocessor encounters include
  154. /// directives. It does not say whether the file has been included, but it
  155. /// provides more information about the directive (hash location instead
  156. /// of location inside the included file). It is assumed that the matching
  157. /// FileChanged() or FileSkipped() is called after this.
  158. void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
  159. const Token &/*IncludeTok*/,
  160. StringRef /*FileName*/,
  161. bool /*IsAngled*/,
  162. CharSourceRange /*FilenameRange*/,
  163. const FileEntry * /*File*/,
  164. StringRef /*SearchPath*/,
  165. StringRef /*RelativePath*/,
  166. const Module *Imported) {
  167. assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion "
  168. "directive was found before the previous one was processed");
  169. std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert(
  170. std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported)));
  171. assert(p.second && "Unexpected revisitation of the same include directive");
  172. if (!Imported)
  173. LastInsertedFileChange = p.first;
  174. }
  175. /// Simple lookup for a SourceLocation (specifically one denoting the hash in
  176. /// an inclusion directive) in the map of inclusion information, FileChanges.
  177. const InclusionRewriter::FileChange *
  178. InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const {
  179. FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding());
  180. if (I != FileChanges.end())
  181. return &I->second;
  182. return nullptr;
  183. }
  184. /// Detect the likely line ending style of \p FromFile by examining the first
  185. /// newline found within it.
  186. static StringRef DetectEOL(const MemoryBuffer &FromFile) {
  187. // detect what line endings the file uses, so that added content does not mix
  188. // the style
  189. const char *Pos = strchr(FromFile.getBufferStart(), '\n');
  190. if (!Pos)
  191. return "\n";
  192. if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r')
  193. return "\n\r";
  194. if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r')
  195. return "\r\n";
  196. return "\n";
  197. }
  198. /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at
  199. /// \p WriteTo - 1.
  200. void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
  201. unsigned &WriteFrom, unsigned WriteTo,
  202. StringRef EOL, int &Line,
  203. bool EnsureNewline) {
  204. if (WriteTo <= WriteFrom)
  205. return;
  206. if (&FromFile == PredefinesBuffer) {
  207. // Ignore the #defines of the predefines buffer.
  208. WriteFrom = WriteTo;
  209. return;
  210. }
  211. OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom);
  212. // count lines manually, it's faster than getPresumedLoc()
  213. Line += std::count(FromFile.getBufferStart() + WriteFrom,
  214. FromFile.getBufferStart() + WriteTo, '\n');
  215. if (EnsureNewline) {
  216. char LastChar = FromFile.getBufferStart()[WriteTo - 1];
  217. if (LastChar != '\n' && LastChar != '\r')
  218. OS << EOL;
  219. }
  220. WriteFrom = WriteTo;
  221. }
  222. /// Print characters from \p FromFile starting at \p NextToWrite up until the
  223. /// inclusion directive at \p StartToken, then print out the inclusion
  224. /// inclusion directive disabled by a #if directive, updating \p NextToWrite
  225. /// and \p Line to track the number of source lines visited and the progress
  226. /// through the \p FromFile buffer.
  227. void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
  228. const Token &StartToken,
  229. const MemoryBuffer &FromFile,
  230. StringRef EOL,
  231. unsigned &NextToWrite, int &Line) {
  232. OutputContentUpTo(FromFile, NextToWrite,
  233. SM.getFileOffset(StartToken.getLocation()), EOL, Line, false);
  234. Token DirectiveToken;
  235. do {
  236. DirectiveLex.LexFromRawLexer(DirectiveToken);
  237. } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
  238. if (&FromFile == PredefinesBuffer) {
  239. // OutputContentUpTo() would not output anything anyway.
  240. return;
  241. }
  242. OS << "#if 0 /* expanded by -frewrite-includes */" << EOL;
  243. OutputContentUpTo(FromFile, NextToWrite,
  244. SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(),
  245. EOL, Line, true);
  246. OS << "#endif /* expanded by -frewrite-includes */" << EOL;
  247. }
  248. /// Find the next identifier in the pragma directive specified by \p RawToken.
  249. StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex,
  250. Token &RawToken) {
  251. RawLex.LexFromRawLexer(RawToken);
  252. if (RawToken.is(tok::raw_identifier))
  253. PP.LookUpIdentifierInfo(RawToken);
  254. if (RawToken.is(tok::identifier))
  255. return RawToken.getIdentifierInfo()->getName();
  256. return StringRef();
  257. }
  258. // Expand __has_include and __has_include_next if possible. If there's no
  259. // definitive answer return false.
  260. bool InclusionRewriter::HandleHasInclude(
  261. FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok,
  262. bool &FileExists) {
  263. // Lex the opening paren.
  264. RawLex.LexFromRawLexer(Tok);
  265. if (Tok.isNot(tok::l_paren))
  266. return false;
  267. RawLex.LexFromRawLexer(Tok);
  268. SmallString<128> FilenameBuffer;
  269. StringRef Filename;
  270. // Since the raw lexer doesn't give us angle_literals we have to parse them
  271. // ourselves.
  272. // FIXME: What to do if the file name is a macro?
  273. if (Tok.is(tok::less)) {
  274. RawLex.LexFromRawLexer(Tok);
  275. FilenameBuffer += '<';
  276. do {
  277. if (Tok.is(tok::eod)) // Sanity check.
  278. return false;
  279. if (Tok.is(tok::raw_identifier))
  280. PP.LookUpIdentifierInfo(Tok);
  281. // Get the string piece.
  282. SmallVector<char, 128> TmpBuffer;
  283. bool Invalid = false;
  284. StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid);
  285. if (Invalid)
  286. return false;
  287. FilenameBuffer += TmpName;
  288. RawLex.LexFromRawLexer(Tok);
  289. } while (Tok.isNot(tok::greater));
  290. FilenameBuffer += '>';
  291. Filename = FilenameBuffer;
  292. } else {
  293. if (Tok.isNot(tok::string_literal))
  294. return false;
  295. bool Invalid = false;
  296. Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
  297. if (Invalid)
  298. return false;
  299. }
  300. // Lex the closing paren.
  301. RawLex.LexFromRawLexer(Tok);
  302. if (Tok.isNot(tok::r_paren))
  303. return false;
  304. // Now ask HeaderInfo if it knows about the header.
  305. // FIXME: Subframeworks aren't handled here. Do we care?
  306. bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
  307. const DirectoryLookup *CurDir;
  308. const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId);
  309. SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1>
  310. Includers;
  311. Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
  312. const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
  313. Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr,
  314. nullptr, nullptr, false);
  315. FileExists = File != nullptr;
  316. return true;
  317. }
  318. /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
  319. /// and including content of included files recursively.
  320. bool InclusionRewriter::Process(FileID FileId,
  321. SrcMgr::CharacteristicKind FileType)
  322. {
  323. bool Invalid;
  324. const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid);
  325. if (Invalid) // invalid inclusion
  326. return false;
  327. const char *FileName = FromFile.getBufferIdentifier();
  328. Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts());
  329. RawLex.SetCommentRetentionState(false);
  330. StringRef EOL = DetectEOL(FromFile);
  331. // Per the GNU docs: "1" indicates entering a new file.
  332. if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID())
  333. WriteLineInfo(FileName, 1, FileType, EOL, "");
  334. else
  335. WriteLineInfo(FileName, 1, FileType, EOL, " 1");
  336. if (SM.getFileIDSize(FileId) == 0)
  337. return false;
  338. // The next byte to be copied from the source file, which may be non-zero if
  339. // the lexer handled a BOM.
  340. unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation());
  341. assert(SM.getLineNumber(FileId, NextToWrite) == 1);
  342. int Line = 1; // The current input file line number.
  343. Token RawToken;
  344. RawLex.LexFromRawLexer(RawToken);
  345. // TODO: Consider adding a switch that strips possibly unimportant content,
  346. // such as comments, to reduce the size of repro files.
  347. while (RawToken.isNot(tok::eof)) {
  348. if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) {
  349. RawLex.setParsingPreprocessorDirective(true);
  350. Token HashToken = RawToken;
  351. RawLex.LexFromRawLexer(RawToken);
  352. if (RawToken.is(tok::raw_identifier))
  353. PP.LookUpIdentifierInfo(RawToken);
  354. if (RawToken.getIdentifierInfo() != nullptr) {
  355. switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
  356. case tok::pp_include:
  357. case tok::pp_include_next:
  358. case tok::pp_import: {
  359. CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite,
  360. Line);
  361. if (FileId != PP.getPredefinesFileID())
  362. WriteLineInfo(FileName, Line - 1, FileType, EOL, "");
  363. StringRef LineInfoExtra;
  364. if (const FileChange *Change = FindFileChangeLocation(
  365. HashToken.getLocation())) {
  366. if (Change->Mod) {
  367. WriteImplicitModuleImport(Change->Mod, EOL);
  368. // else now include and recursively process the file
  369. } else if (Process(Change->Id, Change->FileType)) {
  370. // and set lineinfo back to this file, if the nested one was
  371. // actually included
  372. // `2' indicates returning to a file (after having included
  373. // another file.
  374. LineInfoExtra = " 2";
  375. }
  376. }
  377. // fix up lineinfo (since commented out directive changed line
  378. // numbers) for inclusions that were skipped due to header guards
  379. WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra);
  380. break;
  381. }
  382. case tok::pp_pragma: {
  383. StringRef Identifier = NextIdentifierName(RawLex, RawToken);
  384. if (Identifier == "clang" || Identifier == "GCC") {
  385. if (NextIdentifierName(RawLex, RawToken) == "system_header") {
  386. // keep the directive in, commented out
  387. CommentOutDirective(RawLex, HashToken, FromFile, EOL,
  388. NextToWrite, Line);
  389. // update our own type
  390. FileType = SM.getFileCharacteristic(RawToken.getLocation());
  391. WriteLineInfo(FileName, Line, FileType, EOL);
  392. }
  393. } else if (Identifier == "once") {
  394. // keep the directive in, commented out
  395. CommentOutDirective(RawLex, HashToken, FromFile, EOL,
  396. NextToWrite, Line);
  397. WriteLineInfo(FileName, Line, FileType, EOL);
  398. }
  399. break;
  400. }
  401. case tok::pp_if:
  402. case tok::pp_elif: {
  403. bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() ==
  404. tok::pp_elif);
  405. // Rewrite special builtin macros to avoid pulling in host details.
  406. do {
  407. // Walk over the directive.
  408. RawLex.LexFromRawLexer(RawToken);
  409. if (RawToken.is(tok::raw_identifier))
  410. PP.LookUpIdentifierInfo(RawToken);
  411. if (RawToken.is(tok::identifier)) {
  412. bool HasFile;
  413. SourceLocation Loc = RawToken.getLocation();
  414. // Rewrite __has_include(x)
  415. if (RawToken.getIdentifierInfo()->isStr("__has_include")) {
  416. if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken,
  417. HasFile))
  418. continue;
  419. // Rewrite __has_include_next(x)
  420. } else if (RawToken.getIdentifierInfo()->isStr(
  421. "__has_include_next")) {
  422. const DirectoryLookup *Lookup = PP.GetCurDirLookup();
  423. if (Lookup)
  424. ++Lookup;
  425. if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken,
  426. HasFile))
  427. continue;
  428. } else {
  429. continue;
  430. }
  431. // Replace the macro with (0) or (1), followed by the commented
  432. // out macro for reference.
  433. OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
  434. EOL, Line, false);
  435. OS << '(' << (int) HasFile << ")/*";
  436. OutputContentUpTo(FromFile, NextToWrite,
  437. SM.getFileOffset(RawToken.getLocation()) +
  438. RawToken.getLength(),
  439. EOL, Line, false);
  440. OS << "*/";
  441. }
  442. } while (RawToken.isNot(tok::eod));
  443. if (elif) {
  444. OutputContentUpTo(FromFile, NextToWrite,
  445. SM.getFileOffset(RawToken.getLocation()) +
  446. RawToken.getLength(),
  447. EOL, Line, /*EnsureNewLine*/ true);
  448. WriteLineInfo(FileName, Line, FileType, EOL);
  449. }
  450. break;
  451. }
  452. case tok::pp_endif:
  453. case tok::pp_else: {
  454. // We surround every #include by #if 0 to comment it out, but that
  455. // changes line numbers. These are fixed up right after that, but
  456. // the whole #include could be inside a preprocessor conditional
  457. // that is not processed. So it is necessary to fix the line
  458. // numbers one the next line after each #else/#endif as well.
  459. RawLex.SetKeepWhitespaceMode(true);
  460. do {
  461. RawLex.LexFromRawLexer(RawToken);
  462. } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof));
  463. OutputContentUpTo(
  464. FromFile, NextToWrite,
  465. SM.getFileOffset(RawToken.getLocation()) + RawToken.getLength(),
  466. EOL, Line, /*EnsureNewLine*/ true);
  467. WriteLineInfo(FileName, Line, FileType, EOL);
  468. RawLex.SetKeepWhitespaceMode(false);
  469. }
  470. default:
  471. break;
  472. }
  473. }
  474. RawLex.setParsingPreprocessorDirective(false);
  475. }
  476. RawLex.LexFromRawLexer(RawToken);
  477. }
  478. OutputContentUpTo(FromFile, NextToWrite,
  479. SM.getFileOffset(SM.getLocForEndOfFile(FileId)), EOL, Line,
  480. /*EnsureNewline*/true);
  481. return true;
  482. }
  483. /// InclusionRewriterInInput - Implement -frewrite-includes mode.
  484. void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
  485. const PreprocessorOutputOptions &Opts) {
  486. SourceManager &SM = PP.getSourceManager();
  487. InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS,
  488. Opts.ShowLineMarkers);
  489. PP.addPPCallbacks(Rewrite);
  490. PP.IgnorePragmas();
  491. // First let the preprocessor process the entire file and call callbacks.
  492. // Callbacks will record which #include's were actually performed.
  493. PP.EnterMainSourceFile();
  494. Token Tok;
  495. // Only preprocessor directives matter here, so disable macro expansion
  496. // everywhere else as an optimization.
  497. // TODO: It would be even faster if the preprocessor could be switched
  498. // to a mode where it would parse only preprocessor directives and comments,
  499. // nothing else matters for parsing or processing.
  500. PP.SetMacroExpansionOnlyInDirectives();
  501. do {
  502. PP.Lex(Tok);
  503. } while (Tok.isNot(tok::eof));
  504. Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
  505. Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
  506. Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User);
  507. OS->flush();
  508. }