@@ -94,7 +94,8 @@ struct ExpectedDiagnosticInfo {
9494 unsigned LineNo = ~0U ;
9595 Optional<unsigned > ColumnNo;
9696
97- std::vector<ExpectedFixIt> Fixits;
97+ using AlternativeExpectedFixIts = std::vector<ExpectedFixIt>;
98+ std::vector<AlternativeExpectedFixIts> Fixits = {};
9899
99100 // Loc of {{none}}
100101 const char *noneMarkerStartLoc = nullptr ;
@@ -284,34 +285,36 @@ verifyUnknown(SourceManager &SM,
284285
285286// / Return true if the given \p ExpectedFixIt is in the fix-its emitted by
286287// / diagnostic \p D.
287- bool DiagnosticVerifier::checkForFixIt (const ExpectedFixIt &Expected,
288- const CapturedDiagnosticInfo &D ,
289- unsigned BufferID) const {
288+ bool DiagnosticVerifier::checkForFixIt (
289+ const ExpectedDiagnosticInfo::AlternativeExpectedFixIts &ExpectedAlts ,
290+ const CapturedDiagnosticInfo &D, unsigned BufferID) const {
290291 for (auto &ActualFixIt : D.FixIts ) {
291- if (ActualFixIt.getText () != Expected.Text )
292- continue ;
292+ for (auto &Expected : ExpectedAlts) {
293+ if (ActualFixIt.getText () != Expected.Text )
294+ continue ;
293295
294- LineColumnRange ActualRange = ActualFixIt.getLineColumnRange (
295- SM, BufferID,
296- // Don't compute line numbers unless we have to.
297- /* ComputeStartLocLine=*/ Expected.Range .StartLine !=
298- LineColumnRange::NoValue,
299- /* ComputeEndLocLine=*/ Expected.Range .EndLine !=
300- LineColumnRange::NoValue);
296+ LineColumnRange ActualRange = ActualFixIt.getLineColumnRange (
297+ SM, BufferID,
298+ // Don't compute line numbers unless we have to.
299+ /* ComputeStartLocLine=*/ Expected.Range .StartLine !=
300+ LineColumnRange::NoValue,
301+ /* ComputeEndLocLine=*/ Expected.Range .EndLine !=
302+ LineColumnRange::NoValue);
301303
302- if (Expected.Range .StartCol != ActualRange.StartCol ||
303- Expected.Range .EndCol != ActualRange.EndCol ) {
304- continue ;
305- }
306- if (Expected.Range .StartLine != LineColumnRange::NoValue &&
307- Expected.Range .StartLine != ActualRange.StartLine ) {
308- continue ;
309- }
310- if (Expected.Range .EndLine != LineColumnRange::NoValue &&
311- Expected.Range .EndLine != ActualRange.EndLine ) {
312- continue ;
304+ if (Expected.Range .StartCol != ActualRange.StartCol ||
305+ Expected.Range .EndCol != ActualRange.EndCol ) {
306+ continue ;
307+ }
308+ if (Expected.Range .StartLine != LineColumnRange::NoValue &&
309+ Expected.Range .StartLine != ActualRange.StartLine ) {
310+ continue ;
311+ }
312+ if (Expected.Range .EndLine != LineColumnRange::NoValue &&
313+ Expected.Range .EndLine != ActualRange.EndLine ) {
314+ continue ;
315+ }
316+ return true ;
313317 }
314- return true ;
315318 }
316319
317320 return false ;
@@ -521,7 +524,8 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
521524 MatchStart = MatchStart.substr (MatchStart.find_first_not_of (" \t " ));
522525
523526 size_t TextStartIdx = MatchStart.find (" {{" );
524- if (TextStartIdx == StringRef::npos) {
527+ if (TextStartIdx >=
528+ MatchStart.find (" \n " )) { // Either not found, or found beyond next \n
525529 addError (MatchStart.data (),
526530 " expected {{ in expected-warning/note/error line" );
527531 continue ;
@@ -580,7 +584,7 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
580584
581585 unsigned Count = 1 ;
582586 if (TextStartIdx > 0 ) {
583- StringRef CountStr = MatchStart.substr (0 , TextStartIdx).trim ();
587+ StringRef CountStr = MatchStart.substr (0 , TextStartIdx).trim (" \t " );
584588 if (CountStr == " *" ) {
585589 Expected.mayAppear = true ;
586590 } else {
@@ -630,6 +634,7 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
630634
631635
632636 // Scan for fix-its: {{10-14=replacement text}}
637+ bool startNewAlternatives = true ;
633638 StringRef ExtraChecks = MatchStart.substr (End+2 ).ltrim (" \t " );
634639 while (ExtraChecks.startswith (" {{" )) {
635640 // First make sure we have a closing "}}".
@@ -658,7 +663,23 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
658663 }
659664
660665 // Prepare for the next round of checks.
661- ExtraChecks = ExtraChecks.substr (EndIndex + 2 ).ltrim ();
666+ ExtraChecks = ExtraChecks.substr (EndIndex + 2 ).ltrim (" \t " );
667+
668+ // Handle fix-it alternation.
669+ // If two fix-its are separated by `||`, we can match either of the two.
670+ // This is represented by putting them in the same subarray of `Fixits`.
671+ // If they are not separated by `||`, we must match both of them.
672+ // This is represented by putting them in separate subarrays of `Fixits`.
673+ if (startNewAlternatives &&
674+ (Expected.Fixits .empty () || !Expected.Fixits .back ().empty ()))
675+ Expected.Fixits .push_back ({});
676+
677+ if (ExtraChecks.startswith (" ||" )) {
678+ startNewAlternatives = false ;
679+ ExtraChecks = ExtraChecks.substr (2 ).ltrim (" \t " );
680+ } else {
681+ startNewAlternatives = true ;
682+ }
662683
663684 // If this check starts with 'educational-notes=', check for one or more
664685 // educational notes instead of a fix-it.
@@ -747,10 +768,14 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
747768 FixIt.Text += *current++;
748769 }
749770 }
750-
751- Expected.Fixits .push_back (FixIt);
771+
772+ Expected.Fixits .back (). push_back (FixIt);
752773 }
753774
775+ // If there's a trailing empty alternation, remove it.
776+ if (!Expected.Fixits .empty () && Expected.Fixits .back ().empty ())
777+ Expected.Fixits .pop_back ();
778+
754779 Expected.ExpectedEnd = ExtraChecks.data ();
755780
756781 // Don't include trailing whitespace in the expected-foo{{}} range.
@@ -762,7 +787,6 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
762787 ExpectedDiagnostics.push_back (Expected);
763788 }
764789
765-
766790 // Make sure all the expected diagnostics appeared.
767791 std::reverse (ExpectedDiagnostics.begin (), ExpectedDiagnostics.end ());
768792
@@ -807,10 +831,12 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
807831
808832 const char *missedFixitLoc = nullptr ;
809833 // Verify that any expected fix-its are present in the diagnostic.
810- for (auto fixit : expected.Fixits ) {
834+ for (auto fixitAlternates : expected.Fixits ) {
835+ assert (!fixitAlternates.empty () && " an empty alternation survived" );
836+
811837 // If we found it, we're ok.
812- if (!checkForFixIt (fixit , FoundDiagnostic, BufferID)) {
813- missedFixitLoc = fixit .StartLoc ;
838+ if (!checkForFixIt (fixitAlternates , FoundDiagnostic, BufferID)) {
839+ missedFixitLoc = fixitAlternates. front () .StartLoc ;
814840 break ;
815841 }
816842 }
@@ -844,8 +870,8 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
844870 assert (!expected.Fixits .empty () &&
845871 " some fix-its should be expected here" );
846872
847- const char *replStartLoc = expected.Fixits .front ().StartLoc ;
848- const char *replEndLoc = expected.Fixits .back ().EndLoc ;
873+ const char *replStartLoc = expected.Fixits .front ().front (). StartLoc ;
874+ const char *replEndLoc = expected.Fixits .back ().back (). EndLoc ;
849875
850876 std::string message = " expected fix-it not seen" ;
851877 std::string actualFixits;
@@ -886,8 +912,8 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
886912 replEndLoc = expected.noneMarkerStartLoc ;
887913 } else {
888914 message = " unexpected fix-it seen" ;
889- replStartLoc = expected.Fixits .front ().StartLoc ;
890- replEndLoc = expected.Fixits .back ().EndLoc ;
915+ replStartLoc = expected.Fixits .front ().front (). StartLoc ;
916+ replEndLoc = expected.Fixits .back ().back (). EndLoc ;
891917 }
892918
893919 auto phrase = makeActualFixitsPhrase (FoundDiagnostic.FixIts );
0 commit comments