26
26
27
27
using namespace swift ;
28
28
29
+ namespace {
30
+
31
+ struct ExpectedCheckMatchStartParser {
32
+ StringRef MatchStart;
33
+ const char *ClassificationStartLoc = nullptr ;
34
+ std::optional<DiagnosticKind> ExpectedClassification;
35
+
36
+ ExpectedCheckMatchStartParser (StringRef MatchStart)
37
+ : MatchStart(MatchStart) {}
38
+
39
+ bool tryParseClassification () {
40
+ if (MatchStart.startswith (" note" )) {
41
+ ClassificationStartLoc = MatchStart.data ();
42
+ ExpectedClassification = DiagnosticKind::Note;
43
+ MatchStart = MatchStart.substr (strlen (" note" ));
44
+ return true ;
45
+ }
46
+
47
+ if (MatchStart.startswith (" warning" )) {
48
+ ClassificationStartLoc = MatchStart.data ();
49
+ ExpectedClassification = DiagnosticKind::Warning;
50
+ MatchStart = MatchStart.substr (strlen (" warning" ));
51
+ return true ;
52
+ }
53
+
54
+ if (MatchStart.startswith (" error" )) {
55
+ ClassificationStartLoc = MatchStart.data ();
56
+ ExpectedClassification = DiagnosticKind::Error;
57
+ MatchStart = MatchStart.substr (strlen (" error" ));
58
+ return true ;
59
+ }
60
+
61
+ if (MatchStart.startswith (" remark" )) {
62
+ ClassificationStartLoc = MatchStart.data ();
63
+ ExpectedClassification = DiagnosticKind::Remark;
64
+ MatchStart = MatchStart.substr (strlen (" remark" ));
65
+ return true ;
66
+ }
67
+
68
+ return false ;
69
+ }
70
+
71
+ bool parse (ArrayRef<std::string> prefixes) {
72
+ // First try to parse as if we did not have a prefix. We always parse at
73
+ // least expected-*.
74
+ if (tryParseClassification ())
75
+ return true ;
76
+
77
+ // Otherwise, walk our prefixes until we find one that matches and attempt
78
+ // to check for a note, warning, error, or remark.
79
+ //
80
+ // TODO: We could make this more flexible, but this should work in the
81
+ // short term.
82
+ for (auto &p : prefixes) {
83
+ if (MatchStart.starts_with (p)) {
84
+ MatchStart = MatchStart.substr (p.size ());
85
+ return tryParseClassification ();
86
+ }
87
+ }
88
+
89
+ return false ;
90
+ }
91
+ };
92
+
93
+ } // anonymous namespace
94
+
29
95
namespace swift {
96
+
30
97
struct ExpectedFixIt {
31
98
const char *StartLoc, *EndLoc; // The loc of the {{ and }}'s.
32
99
LineColumnRange Range;
33
100
34
101
std::string Text;
35
102
};
103
+
36
104
} // end namespace swift
37
105
38
106
const LineColumnRange &
@@ -460,6 +528,28 @@ static llvm::Optional<LineColumnRange> parseExpectedFixItRange(
460
528
return Range;
461
529
}
462
530
531
+ // / Before we do anything, check if any of our prefixes are prefixes of later
532
+ // / prefixes. In such a case, we will never actually pattern match the later
533
+ // / prefix. In such a case, crash with a nice error message.
534
+ static void validatePrefixList (ArrayRef<std::string> prefixes) {
535
+ // Work backwards through the prefix list.
536
+ while (!prefixes.empty ()) {
537
+ auto target = StringRef (prefixes.front ());
538
+ prefixes = prefixes.drop_front ();
539
+
540
+ for (auto &p : prefixes) {
541
+ if (StringRef (p).starts_with (target)) {
542
+ llvm::errs () << " Error! Found a verifier diagnostic additional prefix "
543
+ " that is a prefix of a later prefix. The later prefix "
544
+ " will never be pattern matched!\n "
545
+ << " First Prefix: " << target << ' \n '
546
+ << " Second Prefix: " << p << ' \n ' ;
547
+ llvm::report_fatal_error (" Standard compiler error!\n " );
548
+ }
549
+ }
550
+ }
551
+ }
552
+
463
553
// / After the file has been processed, check to see if we got all of
464
554
// / the expected diagnostics and check to see if there were any unexpected
465
555
// / ones.
@@ -486,6 +576,10 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
486
576
Errors.push_back (diag);
487
577
};
488
578
579
+ // Validate that earlier prefixes are not prefixes of alter
580
+ // prefixes... otherwise, we will never pattern match the later prefix.
581
+ validatePrefixList (AdditionalExpectedPrefixes);
582
+
489
583
// Scan the memory buffer looking for expected-note/warning/error.
490
584
for (size_t Match = InputFile.find (" expected-" );
491
585
Match != StringRef::npos; Match = InputFile.find (" expected-" , Match+1 )) {
@@ -494,23 +588,21 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
494
588
StringRef MatchStart = InputFile.substr (Match);
495
589
const char *DiagnosticLoc = MatchStart.data ();
496
590
MatchStart = MatchStart.substr (strlen (" expected-" ));
497
- const char *ClassificationStartLoc = MatchStart.data ();
498
591
499
- DiagnosticKind ExpectedClassification;
500
- if (MatchStart.startswith (" note" )) {
501
- ExpectedClassification = DiagnosticKind::Note;
502
- MatchStart = MatchStart.substr (strlen (" note" ));
503
- } else if (MatchStart.startswith (" warning" )) {
504
- ExpectedClassification = DiagnosticKind::Warning;
505
- MatchStart = MatchStart.substr (strlen (" warning" ));
506
- } else if (MatchStart.startswith (" error" )) {
507
- ExpectedClassification = DiagnosticKind::Error;
508
- MatchStart = MatchStart.substr (strlen (" error" ));
509
- } else if (MatchStart.startswith (" remark" )) {
510
- ExpectedClassification = DiagnosticKind::Remark;
511
- MatchStart = MatchStart.substr (strlen (" remark" ));
512
- } else
513
- continue ;
592
+ const char *ClassificationStartLoc = nullptr ;
593
+ std::optional<DiagnosticKind> ExpectedClassification;
594
+ {
595
+ ExpectedCheckMatchStartParser parser (MatchStart);
596
+ // If we fail to parse... continue.
597
+ if (!parser.parse (AdditionalExpectedPrefixes)) {
598
+ continue ;
599
+ }
600
+ MatchStart = parser.MatchStart ;
601
+ ClassificationStartLoc = parser.ClassificationStartLoc ;
602
+ ExpectedClassification = parser.ExpectedClassification ;
603
+ }
604
+ assert (ClassificationStartLoc);
605
+ assert (bool (ExpectedClassification));
514
606
515
607
// Skip any whitespace before the {{.
516
608
MatchStart = MatchStart.substr (MatchStart.find_first_not_of (" \t " ));
@@ -525,7 +617,7 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
525
617
526
618
ExpectedDiagnosticInfo Expected (DiagnosticLoc, ClassificationStartLoc,
527
619
/* ClassificationEndLoc=*/ MatchStart.data (),
528
- ExpectedClassification);
620
+ * ExpectedClassification);
529
621
int LineOffset = 0 ;
530
622
531
623
if (TextStartIdx > 0 && MatchStart[0 ] == ' @' ) {
0 commit comments