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