Coverage Report

Created: 2022-01-25 06:29

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