InclusionRewriter.cpp 24 KB

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