Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- DependencyDirectivesSourceMinimizer.cpp -  -------------------------===//
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
/// \file
10
/// This is the implementation for minimizing header and source files to the
11
/// minimum necessary preprocessor directives for evaluating includes. It
12
/// reduces the source down to #define, #include, #import, @import, and any
13
/// conditional preprocessor logic that contains one of those.
14
///
15
//===----------------------------------------------------------------------===//
16
17
#include "clang/Lex/DependencyDirectivesSourceMinimizer.h"
18
#include "clang/Basic/CharInfo.h"
19
#include "clang/Basic/Diagnostic.h"
20
#include "clang/Lex/LexDiagnostic.h"
21
#include "llvm/ADT/StringSwitch.h"
22
#include "llvm/Support/MemoryBuffer.h"
23
24
using namespace llvm;
25
using namespace clang;
26
using namespace clang::minimize_source_to_dependency_directives;
27
28
namespace {
29
30
struct Minimizer {
31
  /// Minimized output.
32
  SmallVectorImpl<char> &Out;
33
  /// The known tokens encountered during the minimization.
34
  SmallVectorImpl<Token> &Tokens;
35
36
  Minimizer(SmallVectorImpl<char> &Out, SmallVectorImpl<Token> &Tokens,
37
            StringRef Input, DiagnosticsEngine *Diags,
38
            SourceLocation InputSourceLoc)
39
      : Out(Out), Tokens(Tokens), Input(Input), Diags(Diags),
40
85
        InputSourceLoc(InputSourceLoc) {}
41
42
  /// Lex the provided source and emit the minimized output.
43
  ///
44
  /// \returns True on error.
45
  bool minimize();
46
47
private:
48
  struct IdInfo {
49
    const char *Last;
50
    StringRef Name;
51
  };
52
53
  /// Lex an identifier.
54
  ///
55
  /// \pre First points at a valid identifier head.
56
  LLVM_NODISCARD IdInfo lexIdentifier(const char *First, const char *const End);
57
  LLVM_NODISCARD bool isNextIdentifier(StringRef Id, const char *&First,
58
                                       const char *const End);
59
  LLVM_NODISCARD bool minimizeImpl(const char *First, const char *const End);
60
  LLVM_NODISCARD bool lexPPLine(const char *&First, const char *const End);
61
  LLVM_NODISCARD bool lexAt(const char *&First, const char *const End);
62
  LLVM_NODISCARD bool lexDefine(const char *&First, const char *const End);
63
  LLVM_NODISCARD bool lexPragma(const char *&First, const char *const End);
64
  LLVM_NODISCARD bool lexEndif(const char *&First, const char *const End);
65
  LLVM_NODISCARD bool lexDefault(TokenKind Kind, StringRef Directive,
66
                                 const char *&First, const char *const End);
67
197
  Token &makeToken(TokenKind K) {
68
197
    Tokens.emplace_back(K, Out.size());
69
197
    return Tokens.back();
70
197
  }
71
12
  void popToken() {
72
12
    Out.resize(Tokens.back().Offset);
73
12
    Tokens.pop_back();
74
12
  }
75
67
  TokenKind top() const { return Tokens.empty() ? 
pp_none0
: Tokens.back().K; }
76
77
279
  Minimizer &put(char Byte) {
78
279
    Out.push_back(Byte);
79
279
    return *this;
80
279
  }
81
163
  Minimizer &append(StringRef S) { return append(S.begin(), S.end()); }
82
262
  Minimizer &append(const char *First, const char *Last) {
83
262
    Out.append(First, Last);
84
262
    return *this;
85
262
  }
86
87
  void printToNewline(const char *&First, const char *const End);
88
  void printAdjacentModuleNameParts(const char *&First, const char *const End);
89
  LLVM_NODISCARD bool printAtImportBody(const char *&First,
90
                                        const char *const End);
91
  void printDirectiveBody(const char *&First, const char *const End);
92
  void printAdjacentMacroArgs(const char *&First, const char *const End);
93
  LLVM_NODISCARD bool printMacroArgs(const char *&First, const char *const End);
94
95
  /// Reports a diagnostic if the diagnostic engine is provided. Always returns
96
  /// true at the end.
97
  bool reportError(const char *CurPtr, unsigned Err);
98
99
  StringMap<char> SplitIds;
100
  StringRef Input;
101
  DiagnosticsEngine *Diags;
102
  SourceLocation InputSourceLoc;
103
};
104
105
} // end anonymous namespace
106
107
8
bool Minimizer::reportError(const char *CurPtr, unsigned Err) {
108
8
  if (!Diags)
109
5
    return true;
110
3
  assert(CurPtr >= Input.data() && "invalid buffer ptr");
111
3
  Diags->Report(InputSourceLoc.getLocWithOffset(CurPtr - Input.data()), Err);
112
3
  return true;
113
3
}
114
115
738
static void skipOverSpaces(const char *&First, const char *const End) {
116
1.15k
  while (First != End && 
isHorizontalWhitespace(*First)1.14k
)
117
413
    ++First;
118
738
}
119
120
LLVM_NODISCARD static bool isRawStringLiteral(const char *First,
121
16
                                              const char *Current) {
122
16
  assert(First <= Current);
123
16
124
16
  // Check if we can even back up.
125
16
  if (*Current != '"' || 
First == Current11
)
126
13
    return false;
127
3
128
3
  // Check for an "R".
129
3
  --Current;
130
3
  if (*Current != 'R')
131
0
    return false;
132
3
  if (First == Current || 
!isIdentifierBody(*--Current)2
)
133
3
    return true;
134
0
135
0
  // Check for a prefix of "u", "U", or "L".
136
0
  if (*Current == 'u' || *Current == 'U' || *Current == 'L')
137
0
    return First == Current || !isIdentifierBody(*--Current);
138
0
139
0
  // Check for a prefix of "u8".
140
0
  if (*Current != '8' || First == Current || *Current-- != 'u')
141
0
    return false;
142
0
  return First == Current || !isIdentifierBody(*--Current);
143
0
}
144
145
3
static void skipRawString(const char *&First, const char *const End) {
146
3
  assert(First[0] == '"');
147
3
  assert(First[-1] == 'R');
148
3
149
3
  const char *Last = ++First;
150
6
  while (Last != End && *Last != '(')
151
3
    ++Last;
152
3
  if (Last == End) {
153
0
    First = Last; // Hit the end... just give up.
154
0
    return;
155
0
  }
156
3
157
3
  StringRef Terminator(First, Last - First);
158
3
  for (;;) {
159
3
    // Move First to just past the next ")".
160
3
    First = Last;
161
46
    while (First != End && *First != ')')
162
43
      ++First;
163
3
    if (First == End)
164
0
      return;
165
3
    ++First;
166
3
167
3
    // Look ahead for the terminator sequence.
168
3
    Last = First;
169
6
    while (Last != End && size_t(Last - First) < Terminator.size() &&
170
6
           
Terminator[Last - First] == *Last3
)
171
3
      ++Last;
172
3
173
3
    // Check if we hit it (or the end of the file).
174
3
    if (Last == End) {
175
0
      First = Last;
176
0
      return;
177
0
    }
178
3
    if (size_t(Last - First) < Terminator.size())
179
0
      continue;
180
3
    if (*Last != '"')
181
0
      continue;
182
3
    First = Last + 1;
183
3
    return;
184
3
  }
185
3
}
186
187
13
static void skipString(const char *&First, const char *const End) {
188
13
  assert(*First == '\'' || *First == '"');
189
13
  const char Terminator = *First;
190
34
  for (++First; First != End && *First != Terminator; 
++First21
)
191
21
    if (*First == '\\')
192
0
      if (++First == End)
193
0
        return;
194
13
  if (First != End)
195
13
    ++First; // Finish off the string.
196
13
}
197
198
189
static void skipNewline(const char *&First, const char *End) {
199
189
  assert(isVerticalWhitespace(*First));
200
189
  ++First;
201
189
  if (First == End)
202
56
    return;
203
133
204
133
  // Check for "\n\r" and "\r\n".
205
133
  if (LLVM_UNLIKELY(isVerticalWhitespace(*First) && First[-1] != First[0]))
206
133
    
++First6
;
207
133
}
208
209
34
static void skipToNewlineRaw(const char *&First, const char *const End) {
210
38
  for (;;) {
211
38
    if (First == End)
212
0
      return;
213
38
214
38
    if (isVerticalWhitespace(*First))
215
0
      return;
216
38
217
670
    
while (38
!isVerticalWhitespace(*First))
218
632
      if (++First == End)
219
0
        return;
220
38
221
38
    if (First[-1] != '\\')
222
34
      return;
223
4
224
4
    ++First; // Keep going...
225
4
  }
226
34
}
227
228
75
static const char *reverseOverSpaces(const char *First, const char *Last) {
229
75
  assert(First <= Last);
230
114
  while (First != Last && 
isHorizontalWhitespace(Last[-1])113
)
231
39
    --Last;
232
75
  return Last;
233
75
}
234
235
18
static void skipLineComment(const char *&First, const char *const End) {
236
18
  assert(First[0] == '/' && First[1] == '/');
237
18
  First += 2;
238
18
  skipToNewlineRaw(First, End);
239
18
}
240
241
8
static void skipBlockComment(const char *&First, const char *const End) {
242
8
  assert(First[0] == '/' && First[1] == '*');
243
8
  if (End - First < 4) {
244
0
    First = End;
245
0
    return;
246
0
  }
247
67
  
for (First += 3; 8
First != End;
++First59
)
248
67
    if (First[-1] == '*' && 
First[0] == '/'11
) {
249
8
      ++First;
250
8
      return;
251
8
    }
252
8
}
253
254
/// \returns True if the current single quotation mark character is a C++ 14
255
/// digit separator.
256
static bool isQuoteCppDigitSeparator(const char *const Start,
257
                                     const char *const Cur,
258
9
                                     const char *const End) {
259
9
  assert(*Cur == '\'' && "expected quotation character");
260
9
  // skipLine called in places where we don't expect a valid number
261
9
  // body before `start` on the same line, so always return false at the start.
262
9
  if (Start == Cur)
263
0
    return false;
264
9
  // The previous character must be a valid PP number character.
265
9
  // Make sure that the L, u, U, u8 prefixes don't get marked as a
266
9
  // separator though.
267
9
  char Prev = *(Cur - 1);
268
9
  if (Prev == 'L' || 
Prev == 'U'8
||
Prev == 'u'7
)
269
3
    return false;
270
6
  if (Prev == '8' && 
(Cur - 1 != Start)2
&&
*(Cur - 2) == 'u'2
)
271
1
    return false;
272
5
  if (!isPreprocessingNumberBody(Prev))
273
1
    return false;
274
4
  // The next character should be a valid identifier body character.
275
4
  return (Cur + 1) < End && isIdentifierBody(*(Cur + 1));
276
4
}
277
278
182
static void skipLine(const char *&First, const char *const End) {
279
183
  do {
280
183
    assert(First <= End);
281
183
    if (First == End)
282
1
      return;
283
182
284
182
    if (isVerticalWhitespace(*First)) {
285
88
      skipNewline(First, End);
286
88
      return;
287
88
    }
288
94
    const char *Start = First;
289
693
    while (First != End && 
!isVerticalWhitespace(*First)672
) {
290
599
      // Iterate over strings correctly to avoid comments and newlines.
291
599
      if (*First == '"' ||
292
599
          
(592
*First == '\''592
&&
!isQuoteCppDigitSeparator(Start, First, End)9
)) {
293
12
        if (isRawStringLiteral(Start, First))
294
3
          skipRawString(First, End);
295
9
        else
296
9
          skipString(First, End);
297
12
        continue;
298
12
      }
299
587
300
587
      // Iterate over comments correctly.
301
587
      if (*First != '/' || 
End - First < 20
) {
302
587
        ++First;
303
587
        continue;
304
587
      }
305
0
306
0
      if (First[1] == '/') {
307
0
        // "//...".
308
0
        skipLineComment(First, End);
309
0
        continue;
310
0
      }
311
0
312
0
      if (First[1] != '*') {
313
0
        ++First;
314
0
        continue;
315
0
      }
316
0
317
0
      // "/*...*/".
318
0
      skipBlockComment(First, End);
319
0
    }
320
94
    if (First == End)
321
21
      return;
322
73
323
73
    // Skip over the newline.
324
73
    assert(isVerticalWhitespace(*First));
325
73
    skipNewline(First, End);
326
73
  } while (First[-2] == '\\'); // Continue past line-continuations.
327
182
}
328
329
static void skipDirective(StringRef Name, const char *&First,
330
16
                          const char *const End) {
331
16
  if (llvm::StringSwitch<bool>(Name)
332
16
          .Case("warning", true)
333
16
          .Case("error", true)
334
16
          .Default(false))
335
16
    // Do not process quotes or comments.
336
16
    skipToNewlineRaw(First, End);
337
0
  else
338
0
    skipLine(First, End);
339
16
}
340
341
97
void Minimizer::printToNewline(const char *&First, const char *const End) {
342
101
  while (First != End && !isVerticalWhitespace(*First)) {
343
74
    const char *Last = First;
344
362
    do {
345
362
      // Iterate over strings correctly to avoid comments and newlines.
346
362
      if (*Last == '"' || 
*Last == '\''358
) {
347
4
        if (LLVM_UNLIKELY(isRawStringLiteral(First, Last)))
348
4
          
skipRawString(Last, End)0
;
349
4
        else
350
4
          skipString(Last, End);
351
4
        continue;
352
4
      }
353
358
      if (*Last != '/' || 
End - Last < 21
) {
354
357
        ++Last;
355
357
        continue; // Gather the rest up to print verbatim.
356
357
      }
357
1
358
1
      if (Last[1] != '/' && Last[1] != '*') {
359
0
        ++Last;
360
0
        continue;
361
0
      }
362
1
363
1
      // Deal with "//..." and "/*...*/".
364
1
      append(First, reverseOverSpaces(First, Last));
365
1
      First = Last;
366
1
367
1
      if (Last[1] == '/') {
368
0
        skipLineComment(First, End);
369
0
        return;
370
0
      }
371
1
372
1
      put(' ');
373
1
      skipBlockComment(First, End);
374
1
      skipOverSpaces(First, End);
375
1
      Last = First;
376
362
    } while (Last != End && 
!isVerticalWhitespace(*Last)351
);
377
74
378
74
    // Print out the string.
379
74
    if (Last == End || 
Last == First63
||
Last[-1] != '\\'62
) {
380
70
      append(First, reverseOverSpaces(First, Last));
381
70
      return;
382
70
    }
383
4
384
4
    // Print up to the backslash, backing up over spaces.
385
4
    append(First, reverseOverSpaces(First, Last - 1));
386
4
387
4
    First = Last;
388
4
    skipNewline(First, End);
389
4
    skipOverSpaces(First, End);
390
4
  }
391
97
}
392
393
715
static void skipWhitespace(const char *&First, const char *const End) {
394
733
  for (;;) {
395
733
    assert(First <= End);
396
733
    skipOverSpaces(First, End);
397
733
398
733
    if (End - First < 2)
399
45
      return;
400
688
401
688
    if (First[0] == '\\' && 
isVerticalWhitespace(First[1])11
) {
402
11
      skipNewline(++First, End);
403
11
      continue;
404
11
    }
405
677
406
677
    // Check for a non-comment character.
407
677
    if (First[0] != '/')
408
652
      return;
409
25
410
25
    // "// ...".
411
25
    if (First[1] == '/') {
412
18
      skipLineComment(First, End);
413
18
      return;
414
18
    }
415
7
416
7
    // Cannot be a comment.
417
7
    if (First[1] != '*')
418
0
      return;
419
7
420
7
    // "/*...*/".
421
7
    skipBlockComment(First, End);
422
7
  }
423
715
}
424
425
void Minimizer::printAdjacentModuleNameParts(const char *&First,
426
12
                                             const char *const End) {
427
12
  // Skip over parts of the body.
428
12
  const char *Last = First;
429
12
  do
430
18
    ++Last;
431
18
  while (Last != End && (isIdentifierBody(*Last) || 
*Last == '.'13
));
432
12
  append(First, Last);
433
12
  First = Last;
434
12
}
435
436
11
bool Minimizer::printAtImportBody(const char *&First, const char *const End) {
437
27
  for (;;) {
438
27
    skipWhitespace(First, End);
439
27
    if (First == End)
440
2
      return true;
441
25
442
25
    if (isVerticalWhitespace(*First)) {
443
4
      skipNewline(First, End);
444
4
      continue;
445
4
    }
446
21
447
21
    // Found a semicolon.
448
21
    if (*First == ';') {
449
7
      put(*First++).put('\n');
450
7
      return false;
451
7
    }
452
14
453
14
    // Don't handle macro expansions inside @import for now.
454
14
    if (!isIdentifierBody(*First) && 
*First != '.'3
)
455
2
      return true;
456
12
457
12
    printAdjacentModuleNameParts(First, End);
458
12
  }
459
11
}
460
461
97
void Minimizer::printDirectiveBody(const char *&First, const char *const End) {
462
97
  skipWhitespace(First, End); // Skip initial whitespace.
463
97
  printToNewline(First, End);
464
110
  while (Out.back() == ' ')
465
13
    Out.pop_back();
466
97
  put('\n');
467
97
}
468
469
LLVM_NODISCARD static const char *lexRawIdentifier(const char *First,
470
206
                                                   const char *const End) {
471
206
  assert(isIdentifierBody(*First) && "invalid identifer");
472
206
  const char *Last = First + 1;
473
1.11k
  while (Last != End && 
isIdentifierBody(*Last)1.11k
)
474
909
    ++Last;
475
206
  return Last;
476
206
}
477
478
LLVM_NODISCARD static const char *
479
206
getIdentifierContinuation(const char *First, const char *const End) {
480
206
  if (End - First < 3 || 
First[0] != '\\'182
||
!isVerticalWhitespace(First[1])5
)
481
201
    return nullptr;
482
5
483
5
  ++First;
484
5
  skipNewline(First, End);
485
5
  if (First == End)
486
0
    return nullptr;
487
5
  return isIdentifierBody(First[0]) ? 
First3
:
nullptr2
;
488
5
}
489
490
Minimizer::IdInfo Minimizer::lexIdentifier(const char *First,
491
203
                                           const char *const End) {
492
203
  const char *Last = lexRawIdentifier(First, End);
493
203
  const char *Next = getIdentifierContinuation(Last, End);
494
203
  if (LLVM_LIKELY(!Next))
495
203
    
return IdInfo{Last, StringRef(First, Last - First)}200
;
496
3
497
3
  // Slow path, where identifiers are split over lines.
498
3
  SmallVector<char, 64> Id(First, Last);
499
6
  while (Next) {
500
3
    Last = lexRawIdentifier(Next, End);
501
3
    Id.append(Next, Last);
502
3
    Next = getIdentifierContinuation(Last, End);
503
3
  }
504
3
  return IdInfo{
505
3
      Last,
506
3
      SplitIds.try_emplace(StringRef(Id.begin(), Id.size()), 0).first->first()};
507
3
}
508
509
void Minimizer::printAdjacentMacroArgs(const char *&First,
510
12
                                       const char *const End) {
511
12
  // Skip over parts of the body.
512
12
  const char *Last = First;
513
12
  do
514
20
    ++Last;
515
20
  while (Last != End &&
516
20
         (isIdentifierBody(*Last) || *Last == '.' || 
*Last == ','17
));
517
12
  append(First, Last);
518
12
  First = Last;
519
12
}
520
521
14
bool Minimizer::printMacroArgs(const char *&First, const char *const End) {
522
14
  assert(*First == '(');
523
14
  put(*First++);
524
26
  for (;;) {
525
26
    skipWhitespace(First, End);
526
26
    if (First == End)
527
1
      return true;
528
25
529
25
    if (*First == ')') {
530
11
      put(*First++);
531
11
      return false;
532
11
    }
533
14
534
14
    // This is intentionally fairly liberal.
535
14
    if (!(isIdentifierBody(*First) || 
*First == '.'2
||
*First == ','2
))
536
2
      return true;
537
12
538
12
    printAdjacentMacroArgs(First, End);
539
12
  }
540
14
}
541
542
/// Looks for an identifier starting from Last.
543
///
544
/// Updates "First" to just past the next identifier, if any.  Returns true iff
545
/// the identifier matches "Id".
546
bool Minimizer::isNextIdentifier(StringRef Id, const char *&First,
547
20
                                 const char *const End) {
548
20
  skipWhitespace(First, End);
549
20
  if (First == End || !isIdentifierHead(*First))
550
2
    return false;
551
18
552
18
  IdInfo FoundId = lexIdentifier(First, End);
553
18
  First = FoundId.Last;
554
18
  return FoundId.Name == Id;
555
18
}
556
557
11
bool Minimizer::lexAt(const char *&First, const char *const End) {
558
11
  // Handle "@import".
559
11
  const char *ImportLoc = First++;
560
11
  if (!isNextIdentifier("import", First, End)) {
561
0
    skipLine(First, End);
562
0
    return false;
563
0
  }
564
11
  makeToken(decl_at_import);
565
11
  append("@import ");
566
11
  if (printAtImportBody(First, End))
567
4
    return reportError(
568
4
        ImportLoc, diag::err_dep_source_minimizer_missing_sema_after_at_import);
569
7
  skipWhitespace(First, End);
570
7
  if (First == End)
571
2
    return false;
572
5
  if (!isVerticalWhitespace(*First))
573
1
    return reportError(
574
1
        ImportLoc, diag::err_dep_source_minimizer_unexpected_tokens_at_import);
575
4
  skipNewline(First, End);
576
4
  return false;
577
4
}
578
579
43
bool Minimizer::lexDefine(const char *&First, const char *const End) {
580
43
  makeToken(pp_define);
581
43
  append("#define ");
582
43
  skipWhitespace(First, End);
583
43
584
43
  if (!isIdentifierHead(*First))
585
3
    return reportError(First, diag::err_pp_macro_not_identifier);
586
40
587
40
  IdInfo Id = lexIdentifier(First, End);
588
40
  const char *Last = Id.Last;
589
40
  append(Id.Name);
590
40
  if (Last == End)
591
1
    return false;
592
39
  if (*Last == '(') {
593
14
    size_t Size = Out.size();
594
14
    if (printMacroArgs(Last, End)) {
595
3
      // Be robust to bad macro arguments, since they can show up in disabled
596
3
      // code.
597
3
      Out.resize(Size);
598
3
      append("(/* invalid */\n");
599
3
      skipLine(Last, End);
600
3
      return false;
601
3
    }
602
36
  }
603
36
  skipWhitespace(Last, End);
604
36
  if (Last == End)
605
3
    return false;
606
33
  if (!isVerticalWhitespace(*Last))
607
18
    put(' ');
608
33
  printDirectiveBody(Last, End);
609
33
  First = Last;
610
33
  return false;
611
33
}
612
613
8
bool Minimizer::lexPragma(const char *&First, const char *const End) {
614
8
  // #pragma.
615
8
  skipWhitespace(First, End);
616
8
  if (First == End || !isIdentifierHead(*First))
617
0
    return false;
618
8
619
8
  IdInfo FoundId = lexIdentifier(First, End);
620
8
  First = FoundId.Last;
621
8
  if (FoundId.Name == "once") {
622
2
    // #pragma once
623
2
    skipLine(First, End);
624
2
    makeToken(pp_pragma_once);
625
2
    append("#pragma once\n");
626
2
    return false;
627
2
  }
628
6
629
6
  if (FoundId.Name != "clang") {
630
1
    skipLine(First, End);
631
1
    return false;
632
1
  }
633
5
634
5
  // #pragma clang.
635
5
  if (!isNextIdentifier("module", First, End)) {
636
1
    skipLine(First, End);
637
1
    return false;
638
1
  }
639
4
640
4
  // #pragma clang module.
641
4
  if (!isNextIdentifier("import", First, End)) {
642
2
    skipLine(First, End);
643
2
    return false;
644
2
  }
645
2
646
2
  // #pragma clang module import.
647
2
  makeToken(pp_pragma_import);
648
2
  append("#pragma clang module import ");
649
2
  printDirectiveBody(First, End);
650
2
  return false;
651
2
}
652
653
16
bool Minimizer::lexEndif(const char *&First, const char *const End) {
654
16
  // Strip out "#else" if it's empty.
655
16
  if (top() == pp_else)
656
2
    popToken();
657
16
658
16
  // Strip out "#elif" if they're empty.
659
18
  while (top() == pp_elif)
660
2
    popToken();
661
16
662
16
  // If "#if" is empty, strip it and skip the "#endif".
663
16
  if (top() == pp_if || 
top() == pp_ifdef9
||
top() == pp_ifndef8
) {
664
8
    popToken();
665
8
    skipLine(First, End);
666
8
    return false;
667
8
  }
668
8
669
8
  return lexDefault(pp_endif, "endif", First, End);
670
8
}
671
672
bool Minimizer::lexDefault(TokenKind Kind, StringRef Directive,
673
62
                           const char *&First, const char *const End) {
674
62
  makeToken(Kind);
675
62
  put('#').append(Directive).put(' ');
676
62
  printDirectiveBody(First, End);
677
62
  return false;
678
62
}
679
680
314
bool Minimizer::lexPPLine(const char *&First, const char *const End) {
681
314
  assert(First != End);
682
314
683
314
  skipWhitespace(First, End);
684
314
  assert(First <= End);
685
314
  if (First == End)
686
1
    return false;
687
313
688
313
  if (*First != '#' && 
*First != '@'176
) {
689
165
    skipLine(First, End);
690
165
    assert(First <= End);
691
165
    return false;
692
165
  }
693
148
694
148
  // Handle "@import".
695
148
  if (*First == '@')
696
11
    return lexAt(First, End);
697
137
698
137
  // Handle preprocessing directives.
699
137
  ++First; // Skip over '#'.
700
137
  skipWhitespace(First, End);
701
137
702
137
  if (First == End)
703
0
    return reportError(First, diag::err_pp_expected_eol);
704
137
705
137
  if (!isIdentifierHead(*First)) {
706
0
    skipLine(First, End);
707
0
    return false;
708
0
  }
709
137
710
137
  // Figure out the token.
711
137
  IdInfo Id = lexIdentifier(First, End);
712
137
  First = Id.Last;
713
137
  auto Kind = llvm::StringSwitch<TokenKind>(Id.Name)
714
137
                  .Case("include", pp_include)
715
137
                  .Case("__include_macros", pp___include_macros)
716
137
                  .Case("define", pp_define)
717
137
                  .Case("undef", pp_undef)
718
137
                  .Case("import", pp_import)
719
137
                  .Case("include_next", pp_include_next)
720
137
                  .Case("if", pp_if)
721
137
                  .Case("ifdef", pp_ifdef)
722
137
                  .Case("ifndef", pp_ifndef)
723
137
                  .Case("elif", pp_elif)
724
137
                  .Case("else", pp_else)
725
137
                  .Case("endif", pp_endif)
726
137
                  .Case("pragma", pp_pragma_import)
727
137
                  .Default(pp_none);
728
137
  if (Kind == pp_none) {
729
16
    skipDirective(Id.Name, First, End);
730
16
    return false;
731
16
  }
732
121
733
121
  if (Kind == pp_endif)
734
16
    return lexEndif(First, End);
735
105
736
105
  if (Kind == pp_define)
737
43
    return lexDefine(First, End);
738
62
739
62
  if (Kind == pp_pragma_import)
740
8
    return lexPragma(First, End);
741
54
742
54
  // Everything else.
743
54
  return lexDefault(Kind, Id.Name, First, End);
744
54
}
745
746
85
bool Minimizer::minimizeImpl(const char *First, const char *const End) {
747
391
  while (First != End)
748
314
    if (lexPPLine(First, End))
749
8
      return true;
750
85
  
return false77
;
751
85
}
752
753
85
bool Minimizer::minimize() {
754
85
  bool Error = minimizeImpl(Input.begin(), Input.end());
755
85
756
85
  if (!Error) {
757
77
    // Add a trailing newline and an EOF on success.
758
77
    if (!Out.empty() && 
Out.back() != '\n'62
)
759
4
      Out.push_back('\n');
760
77
    makeToken(pp_eof);
761
77
  }
762
85
763
85
  // Null-terminate the output. This way the memory buffer that's passed to
764
85
  // Clang will not have to worry about the terminating '\0'.
765
85
  Out.push_back(0);
766
85
  Out.pop_back();
767
85
  return Error;
768
85
}
769
770
bool clang::minimizeSourceToDependencyDirectives(
771
    StringRef Input, SmallVectorImpl<char> &Output,
772
    SmallVectorImpl<Token> &Tokens, DiagnosticsEngine *Diags,
773
85
    SourceLocation InputSourceLoc) {
774
85
  Output.clear();
775
85
  Tokens.clear();
776
85
  return Minimizer(Output, Tokens, Input, Diags, InputSourceLoc).minimize();
777
85
}