@@ -72,6 +72,9 @@ struct ExpectedDiagnosticInfo {
7272 // This specifies the full range of the "expected-foo {{}}" specifier.
7373 const char *ExpectedStart, *ExpectedEnd = nullptr ;
7474
75+ // This specifies the full range of the classification string.
76+ const char *ClassificationStart, *ClassificationEnd = nullptr ;
77+
7578 DiagnosticKind Classification;
7679
7780 // This is true if a '*' constraint is present to say that the diagnostic
@@ -108,8 +111,11 @@ struct ExpectedDiagnosticInfo {
108111 Optional<ExpectedEducationalNotes> EducationalNotes;
109112
110113 ExpectedDiagnosticInfo (const char *ExpectedStart,
114+ const char *ClassificationStart,
115+ const char *ClassificationEnd,
111116 DiagnosticKind Classification)
112- : ExpectedStart(ExpectedStart), Classification(Classification) {}
117+ : ExpectedStart(ExpectedStart), ClassificationStart(ClassificationStart),
118+ ClassificationEnd (ClassificationEnd), Classification(Classification) {}
113119};
114120
115121static std::string getDiagKindString (DiagnosticKind Kind) {
@@ -139,11 +145,15 @@ renderEducationalNotes(llvm::SmallVectorImpl<std::string> &EducationalNotes) {
139145 return OS.str ();
140146}
141147
142- // / If we find the specified diagnostic in the list, return it.
143- // / Otherwise return CapturedDiagnostics.end().
144- static std::vector<CapturedDiagnosticInfo>::iterator
148+ // / If we find the specified diagnostic in the list, return it with \c true .
149+ // / If we find a near-match that varies only in classification, return it with
150+ // / \c false.
151+ // / Otherwise return \c CapturedDiagnostics.end() with \c false.
152+ static std::tuple<std::vector<CapturedDiagnosticInfo>::iterator, bool >
145153findDiagnostic (std::vector<CapturedDiagnosticInfo> &CapturedDiagnostics,
146154 const ExpectedDiagnosticInfo &Expected, StringRef BufferName) {
155+ auto fallbackI = CapturedDiagnostics.end ();
156+
147157 for (auto I = CapturedDiagnostics.begin (), E = CapturedDiagnostics.end ();
148158 I != E; ++I) {
149159 // Verify the file and line of the diagnostic.
@@ -155,15 +165,22 @@ findDiagnostic(std::vector<CapturedDiagnosticInfo> &CapturedDiagnostics,
155165 continue ;
156166
157167 // Verify the classification and string.
158- if (I->Classification != Expected.Classification ||
159- I->Message .find (Expected.MessageStr ) == StringRef::npos)
168+ if (I->Message .find (Expected.MessageStr ) == StringRef::npos)
160169 continue ;
161170
171+ // Verify the classification and, if incorrect, remember as a second choice.
172+ if (I->Classification != Expected.Classification ) {
173+ if (fallbackI == E && !Expected.MessageStr .empty ())
174+ fallbackI = I;
175+ continue ;
176+ }
177+
162178 // Okay, we found a match, hurray!
163- return I ;
179+ return { I, true } ;
164180 }
165181
166- return CapturedDiagnostics.end ();
182+ // No perfect match; we'll return the fallback or `end()` instead.
183+ return { fallbackI, false };
167184}
168185
169186// / If there are any -verify errors (e.g. differences between expectations
@@ -481,20 +498,22 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
481498 // the next match.
482499 StringRef MatchStart = InputFile.substr (Match);
483500 const char *DiagnosticLoc = MatchStart.data ();
501+ MatchStart = MatchStart.substr (strlen (" expected-" ));
502+ const char *ClassificationStartLoc = MatchStart.data ();
484503
485504 DiagnosticKind ExpectedClassification;
486- if (MatchStart.startswith (" expected- note" )) {
505+ if (MatchStart.startswith (" note" )) {
487506 ExpectedClassification = DiagnosticKind::Note;
488- MatchStart = MatchStart.substr (strlen (" expected- note" ));
489- } else if (MatchStart.startswith (" expected- warning" )) {
507+ MatchStart = MatchStart.substr (strlen (" note" ));
508+ } else if (MatchStart.startswith (" warning" )) {
490509 ExpectedClassification = DiagnosticKind::Warning;
491- MatchStart = MatchStart.substr (strlen (" expected- warning" ));
492- } else if (MatchStart.startswith (" expected- error" )) {
510+ MatchStart = MatchStart.substr (strlen (" warning" ));
511+ } else if (MatchStart.startswith (" error" )) {
493512 ExpectedClassification = DiagnosticKind::Error;
494- MatchStart = MatchStart.substr (strlen (" expected- error" ));
495- } else if (MatchStart.startswith (" expected- remark" )) {
513+ MatchStart = MatchStart.substr (strlen (" error" ));
514+ } else if (MatchStart.startswith (" remark" )) {
496515 ExpectedClassification = DiagnosticKind::Remark;
497- MatchStart = MatchStart.substr (strlen (" expected- remark" ));
516+ MatchStart = MatchStart.substr (strlen (" remark" ));
498517 } else
499518 continue ;
500519
@@ -508,7 +527,9 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
508527 continue ;
509528 }
510529
511- ExpectedDiagnosticInfo Expected (DiagnosticLoc, ExpectedClassification);
530+ ExpectedDiagnosticInfo Expected (DiagnosticLoc, ClassificationStartLoc,
531+ /* ClassificationEndLoc=*/ MatchStart.data (),
532+ ExpectedClassification);
512533 int LineOffset = 0 ;
513534
514535 if (TextStartIdx > 0 && MatchStart[0 ] == ' @' ) {
@@ -750,18 +771,40 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
750771 auto &expected = ExpectedDiagnostics[i];
751772
752773 // Check to see if we had this expected diagnostic.
753- auto FoundDiagnosticIter =
774+ auto FoundDiagnosticInfo =
754775 findDiagnostic (CapturedDiagnostics, expected, BufferName);
776+ auto FoundDiagnosticIter = std::get<0 >(FoundDiagnosticInfo);
755777 if (FoundDiagnosticIter == CapturedDiagnostics.end ()) {
756778 // Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then
757779 // we're ok. Otherwise, leave it in the list.
758780 if (expected.mayAppear )
759781 ExpectedDiagnostics.erase (ExpectedDiagnostics.begin ()+i);
760782 continue ;
761783 }
762-
784+
785+ auto emitFixItsError = [&](const char *location, const Twine &message,
786+ const char *replStartLoc, const char *replEndLoc,
787+ const std::string &replStr) {
788+ llvm::SMFixIt fix (llvm::SMRange (SMLoc::getFromPointer (replStartLoc),
789+ SMLoc::getFromPointer (replEndLoc)),
790+ replStr);
791+ addError (location, message, fix);
792+ };
793+
763794 auto &FoundDiagnostic = *FoundDiagnosticIter;
764795
796+ if (!std::get<1 >(FoundDiagnosticInfo)) {
797+ // Found a diagnostic with the right location and text but the wrong
798+ // classification. We'll emit an error about the mismatch and
799+ // thereafter pretend that the diagnostic fully matched.
800+ auto expectedKind = getDiagKindString (expected.Classification );
801+ auto actualKind = getDiagKindString (FoundDiagnostic.Classification );
802+ emitFixItsError (expected.ClassificationStart ,
803+ llvm::Twine (" expected " ) + expectedKind + " , not " + actualKind,
804+ expected.ClassificationStart , expected.ClassificationEnd ,
805+ actualKind);
806+ }
807+
765808 const char *missedFixitLoc = nullptr ;
766809 // Verify that any expected fix-its are present in the diagnostic.
767810 for (auto fixit : expected.Fixits ) {
@@ -791,15 +834,6 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
791834 actualFixitsStr};
792835 };
793836
794- auto emitFixItsError = [&](const char *location, const Twine &message,
795- const char *replStartLoc, const char *replEndLoc,
796- const std::string &replStr) {
797- llvm::SMFixIt fix (llvm::SMRange (SMLoc::getFromPointer (replStartLoc),
798- SMLoc::getFromPointer (replEndLoc)),
799- replStr);
800- addError (location, message, fix);
801- };
802-
803837 // If we have any expected fixits that didn't get matched, then they are
804838 // wrong. Replace the failed fixit with what actually happened.
805839
0 commit comments