@@ -70,6 +70,9 @@ struct ExpectedDiagnosticInfo {
7070 // This specifies the full range of the "expected-foo {{}}" specifier.
7171 const char *ExpectedStart, *ExpectedEnd = nullptr ;
7272
73+ // This specifies the full range of the classification string.
74+ const char *ClassificationStart, *ClassificationEnd = nullptr ;
75+
7376 DiagnosticKind Classification;
7477
7578 // This is true if a '*' constraint is present to say that the diagnostic
@@ -106,8 +109,11 @@ struct ExpectedDiagnosticInfo {
106109 Optional<ExpectedEducationalNotes> EducationalNotes;
107110
108111 ExpectedDiagnosticInfo (const char *ExpectedStart,
112+ const char *ClassificationStart,
113+ const char *ClassificationEnd,
109114 DiagnosticKind Classification)
110- : ExpectedStart(ExpectedStart), Classification(Classification) {}
115+ : ExpectedStart(ExpectedStart), ClassificationStart(ClassificationStart),
116+ ClassificationEnd (ClassificationEnd), Classification(Classification) {}
111117};
112118
113119static std::string getDiagKindString (DiagnosticKind Kind) {
@@ -137,11 +143,15 @@ renderEducationalNotes(llvm::SmallVectorImpl<std::string> &EducationalNotes) {
137143 return OS.str ();
138144}
139145
140- // / If we find the specified diagnostic in the list, return it.
141- // / Otherwise return CapturedDiagnostics.end().
142- static std::vector<CapturedDiagnosticInfo>::iterator
146+ // / If we find the specified diagnostic in the list, return it with \c true .
147+ // / If we find a near-match that varies only in classification, return it with
148+ // / \c false.
149+ // / Otherwise return \c CapturedDiagnostics.end() with \c false.
150+ static std::tuple<std::vector<CapturedDiagnosticInfo>::iterator, bool >
143151findDiagnostic (std::vector<CapturedDiagnosticInfo> &CapturedDiagnostics,
144152 const ExpectedDiagnosticInfo &Expected, StringRef BufferName) {
153+ auto fallbackI = CapturedDiagnostics.end ();
154+
145155 for (auto I = CapturedDiagnostics.begin (), E = CapturedDiagnostics.end ();
146156 I != E; ++I) {
147157 // Verify the file and line of the diagnostic.
@@ -153,15 +163,22 @@ findDiagnostic(std::vector<CapturedDiagnosticInfo> &CapturedDiagnostics,
153163 continue ;
154164
155165 // Verify the classification and string.
156- if (I->Classification != Expected.Classification ||
157- I->Message .find (Expected.MessageStr ) == StringRef::npos)
166+ if (I->Message .find (Expected.MessageStr ) == StringRef::npos)
158167 continue ;
159168
169+ // Verify the classification and, if incorrect, remember as a second choice.
170+ if (I->Classification != Expected.Classification ) {
171+ if (fallbackI == E && !Expected.MessageStr .empty ())
172+ fallbackI = I;
173+ continue ;
174+ }
175+
160176 // Okay, we found a match, hurray!
161- return I ;
177+ return { I, true } ;
162178 }
163179
164- return CapturedDiagnostics.end ();
180+ // No perfect match; we'll return the fallback or `end()` instead.
181+ return { fallbackI, false };
165182}
166183
167184// / If there are any -verify errors (e.g. differences between expectations
@@ -372,20 +389,22 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
372389 // the next match.
373390 StringRef MatchStart = InputFile.substr (Match);
374391 const char *DiagnosticLoc = MatchStart.data ();
392+ MatchStart = MatchStart.substr (strlen (" expected-" ));
393+ const char *ClassificationStartLoc = MatchStart.data ();
375394
376395 DiagnosticKind ExpectedClassification;
377- if (MatchStart.startswith (" expected- note" )) {
396+ if (MatchStart.startswith (" note" )) {
378397 ExpectedClassification = DiagnosticKind::Note;
379- MatchStart = MatchStart.substr (strlen (" expected- note" ));
380- } else if (MatchStart.startswith (" expected- warning" )) {
398+ MatchStart = MatchStart.substr (strlen (" note" ));
399+ } else if (MatchStart.startswith (" warning" )) {
381400 ExpectedClassification = DiagnosticKind::Warning;
382- MatchStart = MatchStart.substr (strlen (" expected- warning" ));
383- } else if (MatchStart.startswith (" expected- error" )) {
401+ MatchStart = MatchStart.substr (strlen (" warning" ));
402+ } else if (MatchStart.startswith (" error" )) {
384403 ExpectedClassification = DiagnosticKind::Error;
385- MatchStart = MatchStart.substr (strlen (" expected- error" ));
386- } else if (MatchStart.startswith (" expected- remark" )) {
404+ MatchStart = MatchStart.substr (strlen (" error" ));
405+ } else if (MatchStart.startswith (" remark" )) {
387406 ExpectedClassification = DiagnosticKind::Remark;
388- MatchStart = MatchStart.substr (strlen (" expected- remark" ));
407+ MatchStart = MatchStart.substr (strlen (" remark" ));
389408 } else
390409 continue ;
391410
@@ -399,7 +418,9 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
399418 continue ;
400419 }
401420
402- ExpectedDiagnosticInfo Expected (DiagnosticLoc, ExpectedClassification);
421+ ExpectedDiagnosticInfo Expected (DiagnosticLoc, ClassificationStartLoc,
422+ /* ClassificationEndLoc=*/ MatchStart.data (),
423+ ExpectedClassification);
403424 int LineOffset = 0 ;
404425
405426 if (TextStartIdx > 0 && MatchStart[0 ] == ' @' ) {
@@ -675,18 +696,40 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
675696 auto &expected = ExpectedDiagnostics[i];
676697
677698 // Check to see if we had this expected diagnostic.
678- auto FoundDiagnosticIter =
699+ auto FoundDiagnosticInfo =
679700 findDiagnostic (CapturedDiagnostics, expected, BufferName);
701+ auto FoundDiagnosticIter = std::get<0 >(FoundDiagnosticInfo);
680702 if (FoundDiagnosticIter == CapturedDiagnostics.end ()) {
681703 // Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then
682704 // we're ok. Otherwise, leave it in the list.
683705 if (expected.mayAppear )
684706 ExpectedDiagnostics.erase (ExpectedDiagnostics.begin ()+i);
685707 continue ;
686708 }
687-
709+
710+ auto emitFixItsError = [&](const char *location, const Twine &message,
711+ const char *replStartLoc, const char *replEndLoc,
712+ const std::string &replStr) {
713+ llvm::SMFixIt fix (llvm::SMRange (SMLoc::getFromPointer (replStartLoc),
714+ SMLoc::getFromPointer (replEndLoc)),
715+ replStr);
716+ addError (location, message, fix);
717+ };
718+
688719 auto &FoundDiagnostic = *FoundDiagnosticIter;
689720
721+ if (!std::get<1 >(FoundDiagnosticInfo)) {
722+ // Found a diagnostic with the right location and text but the wrong
723+ // classification. We'll emit an error about the mismatch and
724+ // thereafter pretend that the diagnostic fully matched.
725+ auto expectedKind = getDiagKindString (expected.Classification );
726+ auto actualKind = getDiagKindString (FoundDiagnostic.Classification );
727+ emitFixItsError (expected.ClassificationStart ,
728+ llvm::Twine (" expected " ) + expectedKind + " , not " + actualKind,
729+ expected.ClassificationStart , expected.ClassificationEnd ,
730+ actualKind);
731+ }
732+
690733 const char *missedFixitLoc = nullptr ;
691734 // Verify that any expected fix-its are present in the diagnostic.
692735 for (auto fixit : expected.Fixits ) {
@@ -716,15 +759,6 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
716759 actualFixitsStr};
717760 };
718761
719- auto emitFixItsError = [&](const char *location, const Twine &message,
720- const char *replStartLoc, const char *replEndLoc,
721- const std::string &replStr) {
722- llvm::SMFixIt fix (llvm::SMRange (SMLoc::getFromPointer (replStartLoc),
723- SMLoc::getFromPointer (replEndLoc)),
724- replStr);
725- addError (location, message, fix);
726- };
727-
728762 // If we have any expected fixits that didn't get matched, then they are
729763 // wrong. Replace the failed fixit with what actually happened.
730764
0 commit comments