InclusionRewriter.cpp 24 KB

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