Coverage Report

Created: 2020-11-24 06:42

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