diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst index ac7e81024d19..dfa2fd29515d 100644 --- a/llvm/docs/CommandGuide/FileCheck.rst +++ b/llvm/docs/CommandGuide/FileCheck.rst @@ -95,6 +95,16 @@ OPTIONS Show the version number of this program. +.. option:: -v + + Print directive pattern matches. + +.. option:: -vv + + Print information helpful in diagnosing internal FileCheck issues, such as + discarded overlapping ``CHECK-DAG:`` matches, implicit EOF pattern matches, + and ``CHECK-NOT:`` patterns that do not have matches. Implies ``-v``. + .. option:: --allow-deprecated-dag-overlap Enable overlapping among matches in a group of consecutive ``CHECK-DAG:`` diff --git a/llvm/test/FileCheck/check-empty.txt b/llvm/test/FileCheck/check-empty.txt index 319b411bef6f..1caff2a37148 100644 --- a/llvm/test/FileCheck/check-empty.txt +++ b/llvm/test/FileCheck/check-empty.txt @@ -9,4 +9,4 @@ ; EMPTY-ERR: FileCheck error: '-' is empty. ; EMPTY-ERR-NEXT: FileCheck command line: {{.*}}FileCheck{{.*}}-check-prefix={{.*}}FOO {{.*}}check-empty.txt ; NO-EMPTY-ERR-NOT: FileCheck error: '-' is empty. -; NOT-FOUND: error: expected string not found in input +; NOT-FOUND: error: FOO: expected string not found in input diff --git a/llvm/test/FileCheck/check-label-dag.txt b/llvm/test/FileCheck/check-label-dag.txt index 2f54c3ea94ec..1ce4a8d2b07e 100644 --- a/llvm/test/FileCheck/check-label-dag.txt +++ b/llvm/test/FileCheck/check-label-dag.txt @@ -7,5 +7,5 @@ CHECK-LABEL: {{^}}bar CHECK-DAG: {{^}}foo CHECK-LABEL: {{^}}zed -ERROR: error: expected string not found in input +ERROR: error: CHECK-DAG: expected string not found in input ERROR-NEXT: CHECK-DAG: {{.....}}foo diff --git a/llvm/test/FileCheck/check-multiple-prefixes-nomatch-2.txt b/llvm/test/FileCheck/check-multiple-prefixes-nomatch-2.txt index 605547167e9e..55c521123da7 100644 --- a/llvm/test/FileCheck/check-multiple-prefixes-nomatch-2.txt +++ b/llvm/test/FileCheck/check-multiple-prefixes-nomatch-2.txt @@ -8,5 +8,5 @@ bar ; FOO: fo{{o}} ; BAR: ba{{r}} -; CHECK: {{error: expected string not found in input}} +; CHECK: {{error: FOO: expected string not found in input}} ; CHECK-NEXT: {{F}}OO: fo{{[{][{]o[}][}]}} diff --git a/llvm/test/FileCheck/check-multiple-prefixes-nomatch.txt b/llvm/test/FileCheck/check-multiple-prefixes-nomatch.txt index b1a41321c08d..90a2a3863e57 100644 --- a/llvm/test/FileCheck/check-multiple-prefixes-nomatch.txt +++ b/llvm/test/FileCheck/check-multiple-prefixes-nomatch.txt @@ -8,5 +8,5 @@ foo ; BAR: ba{{z}} ; FOO: fo{{o}} -; CHECK: {{error: expected string not found in input}} +; CHECK: {{error: BAR: expected string not found in input}} ; CHECK-NEXT: {{B}}AR: ba{{[{][{]z[}][}]}} diff --git a/llvm/test/FileCheck/check-not-diaginfo.txt b/llvm/test/FileCheck/check-not-diaginfo.txt index 44a46a3d25dd..de2d13e1f81a 100644 --- a/llvm/test/FileCheck/check-not-diaginfo.txt +++ b/llvm/test/FileCheck/check-not-diaginfo.txt @@ -2,6 +2,9 @@ CHECK-NOT: test -DIAG: CHECK-NOT: pattern specified here +DIAG: error: CHECK-NOT: excluded string found in input +DIAG-NEXT: CHECK-NOT: test +DIAG-NEXT: {{^ \^}} +DIAG-NEXT: note: found here DIAG-NEXT: CHECK-NOT: test DIAG-NEXT: {{^ \^}} diff --git a/llvm/test/FileCheck/defines.txt b/llvm/test/FileCheck/defines.txt index d2219b7ca257..c788124dcbba 100644 --- a/llvm/test/FileCheck/defines.txt +++ b/llvm/test/FileCheck/defines.txt @@ -1,9 +1,18 @@ ; RUN: FileCheck -DVALUE=10 -input-file %s %s ; RUN: not FileCheck -DVALUE=20 -input-file %s %s 2>&1 | FileCheck %s -check-prefix ERRMSG +; +; RUN: not FileCheck -DVALUE=10 -check-prefix NOT -input-file %s %s 2>&1 | FileCheck %s -check-prefix NOT-ERRMSG +; RUN: FileCheck -DVALUE=20 -check-prefix NOT -input-file %s %s Value = 10 ; CHECK: Value = [[VALUE]] +; NOT-NOT: Value = [[VALUE]] -; ERRMSG: defines.txt:5:10: error: expected string not found in input +; ERRMSG: defines.txt:8:10: error: CHECK: expected string not found in input +; ERRMSG: defines.txt:1:1: note: scanning from here ; ERRMSG: defines.txt:1:1: note: with variable "VALUE" equal to "20" -; ERRMSG: defines.txt:4:1: note: possible intended match here +; ERRMSG: defines.txt:7:1: note: possible intended match here + +; NOT-ERRMSG: defines.txt:9:12: error: {{NOT}}-NOT: excluded string found in input +; NOT-ERRMSG: defines.txt:7:1: note: found here +; NOT-ERRMSG: defines.txt:7:1: note: with variable "VALUE" equal to "10" \ No newline at end of file diff --git a/llvm/test/FileCheck/implicit-check-not.txt b/llvm/test/FileCheck/implicit-check-not.txt index 42677362158b..39b758e9a97f 100644 --- a/llvm/test/FileCheck/implicit-check-not.txt +++ b/llvm/test/FileCheck/implicit-check-not.txt @@ -9,36 +9,36 @@ warning: aaa ; CHECK-PASS: warning: aaa -; CHECK-ERROR1: error: CHECK-FAIL1-NOT: string occurred! -; CHECK-ERROR1: command line:1:22: note: CHECK-FAIL1-NOT: pattern specified here +; CHECK-ERROR1: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input ; CHECK-ERROR1-NEXT: -implicit-check-not='warning:' +; CHECK-ERROR1: note: found here ; CHECK-FAIL2: warning: aaa ; CHECK-FAIL3: warning: aaa -; CHECK-ERROR4: error: CHECK-FAIL1-NOT: string occurred! -; CHECK-ERROR4: command line:1:22: note: CHECK-FAIL1-NOT: pattern specified here +; CHECK-ERROR4: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input ; CHECK-ERROR4-NEXT: {{-implicit-check-not='\{\{aaa\|bbb\|ccc\}\}'}} -; CHECK-ERROR5: error: CHECK-FAIL1-NOT: string occurred! -; CHECK-ERROR5: command line:1:22: note: CHECK-FAIL1-NOT: pattern specified here +; CHECK-ERROR4: note: found here +; CHECK-ERROR5: command line:1:22: error: CHECK-FAIL1-NOT: excluded string found in input ; CHECK-ERROR5-NEXT: -implicit-check-not='aaa' +; CHECK-ERROR5: note: found here warning: bbb ; CHECK-PASS: warning: bbb ; CHECK-FAIL1: warning: bbb -; CHECK-ERROR2: error: CHECK-FAIL2-NOT: string occurred! -; CHECK-ERROR2: command line:1:22: note: CHECK-FAIL2-NOT: pattern specified here +; CHECK-ERROR2: command line:1:22: error: CHECK-FAIL2-NOT: excluded string found in input ; CHECK-ERROR2-NEXT: -implicit-check-not='warning:' +; CHECK-ERROR2: note: found here ; CHECK-FAIL3: warning: bbb -; CHECK-ERROR6: error: CHECK-FAIL2-NOT: string occurred! -; CHECK-ERROR6: command line:1:22: note: CHECK-FAIL2-NOT: pattern specified here +; CHECK-ERROR6: command line:1:22: error: CHECK-FAIL2-NOT: excluded string found in input ; CHECK-ERROR6-NEXT: -implicit-check-not='bbb' +; CHECK-ERROR6: note: found here warning: ccc ; CHECK-PASS: warning: ccc ; CHECK-FAIL1: warning: ccc ; CHECK-FAIL2: warning: ccc -; CHECK-ERROR3: error: CHECK-FAIL3-NOT: string occurred! -; CHECK-ERROR3: command line:1:22: note: CHECK-FAIL3-NOT: pattern specified here +; CHECK-ERROR3: command line:1:22: error: CHECK-FAIL3-NOT: excluded string found in input ; CHECK-ERROR3-NEXT: -implicit-check-not='warning:' -; CHECK-ERROR7: error: CHECK-FAIL3-NOT: string occurred! -; CHECK-ERROR7: command line:1:22: note: CHECK-FAIL3-NOT: pattern specified here +; CHECK-ERROR3: note: found here +; CHECK-ERROR7: command line:1:22: error: CHECK-FAIL3-NOT: excluded string found in input ; CHECK-ERROR7-NEXT: -implicit-check-not='ccc' +; CHECK-ERROR7: note: found here diff --git a/llvm/test/FileCheck/match-full-lines.txt b/llvm/test/FileCheck/match-full-lines.txt index d6b10a5e3a9b..1d6a965cd3ea 100644 --- a/llvm/test/FileCheck/match-full-lines.txt +++ b/llvm/test/FileCheck/match-full-lines.txt @@ -26,28 +26,28 @@ Label 66 // CHECK:a line // CHECK:trailing whitespace // CHECK:trailing more whitespace -// ERROR-STRICT:error: expected string not found in input +// ERROR-STRICT:error: {{C}}HECK: expected string not found in input // ERROR-STRICT:// {{C}}HECK:trailing whitespace // CHECK-LABEL:Label 2 // CHECK:a line // CHECK-NEXT:leading whitespace // CHECK-NEXT: leading more whitespace -// ERROR-STRICT:error: expected string not found in input +// ERROR-STRICT:error: {{C}}HECK-NEXT: expected string not found in input // ERROR-STRICT:// {{C}}HECK-NEXT:leading whitespace // CHECK-LABEL:Label 3 // CHECK:line -// ERROR:error: expected string not found in input +// ERROR:error: {{C}}HECK: expected string not found in input // ERROR:// {{C}}HECK:line // CHECK-LABEL:Label 4 // CHECK:a line // CHECK-NOT:random -// ERROR:error: {{C}}HECK-NOT: string occurred! +// ERROR:error: {{C}}HECK-NOT: excluded string found in input // ERROR:a random thing // CHECK-LABEL:Label 5 // CHECK-LABEL:Label 6 -// ERROR:error: expected string not found in input +// ERROR:error: {{C}}HECK-LABEL: expected string not found in input // ERROR:{{C}}HECK-LABEL:Label 6 diff --git a/llvm/test/FileCheck/verbose.txt b/llvm/test/FileCheck/verbose.txt new file mode 100644 index 000000000000..e6eec5e5462f --- /dev/null +++ b/llvm/test/FileCheck/verbose.txt @@ -0,0 +1,115 @@ +; RUN: FileCheck -input-file %s %s 2>&1 | FileCheck -check-prefix QUIET --allow-empty %s +; RUN: FileCheck -v -input-file %s %s 2>&1 | FileCheck -check-prefix V %s +; RUN: FileCheck -vv -input-file %s %s 2>&1 | FileCheck -check-prefixes V,VV %s + +foo +bar +CHECK: foo +CHECK-NOT: raboof +CHECK-NEXT: bar + +V: verbose.txt:[[@LINE-4]]:8: remark: {{C}}HECK: expected string found in input +V-NEXT: {{C}}HECK: foo{{$}} +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-9]]:1: note: found here +V-NEXT: {{^}}foo{{$}} +V-NEXT: {{^}}^~~{{$}} + +V-NEXT: verbose.txt:[[@LINE-9]]:13: remark: {{C}}HECK-NEXT: expected string found in input +V-NEXT: {{C}}HECK-NEXT: bar{{$}} +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-15]]:1: note: found here +V-NEXT: {{^}}bar{{$}} +V-NEXT: {{^}}^~~{{$}} + +VV-NEXT: verbose.txt:[[@LINE-17]]:12: remark: {{C}}HECK-NOT: excluded string not found in input +VV-NEXT: {{C}}HECK-NOT: raboof{{$}} +VV-NEXT: {{^ \^$}} +VV-NEXT: verbose.txt:[[@LINE-22]]:1: note: scanning from here +VV-NEXT: {{^}}bar{{$}} +VV-NEXT: {{^}}^{{$}} + +before empty + +after empty +CHECK: before empty +CHECK-EMPTY: +CHECK-NEXT: after empty + +V: verbose.txt:[[@LINE-4]]:8: remark: {{C}}HECK: expected string found in input +V-NEXT: {{C}}HECK: before empty{{$}} +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-10]]:1: note: found here +V-NEXT: {{^}}before empty{{$}} +V-NEXT: {{^}}^~~~~~~~~~~~{{$}} + +V-NEXT: verbose.txt:[[@LINE-10]]:13: remark: {{C}}HECK-EMPTY: expected string found in input +V-NEXT: {{C}}HECK-EMPTY:{{$}} +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-16]]:1: note: found here +V-EMPTY: +V-NEXT: {{^}}^{{$}} + +V-NEXT: verbose.txt:[[@LINE-16]]:13: remark: {{C}}HECK-NEXT: expected string found in input +V-NEXT: {{C}}HECK-NEXT: after empty{{$}} +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-22]]:1: note: found here +V-NEXT: {{^}}after empty{{$}} +V-NEXT: {{^}}^~~~~~~~~~~{{$}} + +abcdef +abcdef +CHECK-DAG: abcdef +CHECK-DAG: def + +V-NEXT: verbose.txt:[[@LINE-3]]:12: remark: {{C}}HECK-DAG: expected string found in input +V-NEXT: {{C}}HECK-DAG: abcdef +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-8]]:1: note: found here +V-NEXT: {{^}}abcdef{{$}} +V-NEXT: {{^}}^~~~~~{{$}} + +VV-NEXT: verbose.txt:[[@LINE-9]]:12: remark: {{C}}HECK-DAG: expected string found in input +VV-NEXT: {{C}}HECK-DAG: def +VV-NEXT: {{^ \^$}} +VV-NEXT: verbose.txt:[[@LINE-15]]:4: note: found here +VV-NEXT: {{^abcdef$}} +VV-NEXT: {{^ \^~~$}} +VV-NEXT: verbose.txt:[[@LINE-18]]:1: note: match discarded, overlaps earlier DAG match here +VV-NEXT: {{^}}abcdef{{$}} +VV-NEXT: {{^}}^~~~~~{{$}} + +V-NEXT: verbose.txt:[[@LINE-19]]:12: remark: {{C}}HECK-DAG: expected string found in input +V-NEXT: {{C}}HECK-DAG: def +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-24]]:4: note: found here +V-NEXT: {{^abcdef$}} +V-NEXT: {{^ \^~~$}} + +xyz +CHECK: xyz +CHECK-NOT: {{z}}yx + +V: verbose.txt:[[@LINE-3]]:8: remark: {{C}}HECK: expected string found in input +V-NEXT: {{C}}HECK: xyz{{$}} +V-NEXT: {{^ \^$}} +V-NEXT: verbose.txt:[[@LINE-7]]:1: note: found here +V-NEXT: {{^}}xyz{{$}} +V-NEXT: {{^}}^~~{{$}} + +VV-NEXT: verbose.txt:[[@LINE-9]]:19: remark: implicit EOF: expected string found in input +VV-NEXT: {{C}}HECK-NOT: {{[{][{]z[}][}]yx$}} +VV-NEXT: {{^ \^$}} +VV-NEXT: verbose.txt:[[@LINE+13]]:1: note: found here +VV-NOT: {{.}} +VV: {{^\^$}} + +VV-NEXT: verbose.txt:[[@LINE-16]]:12: remark: {{C}}HECK-NOT: excluded string not found in input +VV-NEXT: {{C}}HECK-NOT: {{[{][{]z[}][}]yx$}} +VV-NEXT: {{^ \^$}} +VV-NEXT: verbose.txt:[[@LINE-20]]:1: note: scanning from here +VV-NEXT: {{^C}}HECK: xyz{{$}} +VV-NEXT: {{^\^$}} + +QUIET-NOT: {{.}} +V-NOT: {{.}} diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp index cd3175f13f02..4efe535cecf1 100644 --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -90,6 +90,14 @@ static cl::opt AllowDeprecatedDagOverlap( "provided for convenience as old tests are migrated to the new\n" "non-overlapping CHECK-DAG implementation.\n")); +static cl::opt Verbose("v", cl::init(false), + cl::desc("Print directive pattern matches.\n")); + +static cl::opt VerboseVerbose( + "vv", cl::init(false), + cl::desc("Print information helpful in diagnosing internal FileCheck\n" + "issues. Implies -v.\n")); + typedef cl::list::const_iterator prefix_iterator; //===----------------------------------------------------------------------===// @@ -154,8 +162,11 @@ public: unsigned LineNumber); size_t Match(StringRef Buffer, size_t &MatchLen, StringMap &VariableTable) const; - void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer, - const StringMap &VariableTable) const; + void PrintVariableUses(const SourceMgr &SM, StringRef Buffer, + const StringMap &VariableTable, + SMRange MatchRange = None) const; + void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer, + const StringMap &VariableTable) const; bool hasVariable() const { return !(VariableUses.empty() && VariableDefs.empty()); @@ -484,8 +495,12 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen, VariableTable[VariableDef.first] = MatchInfo[VariableDef.second]; } - MatchLen = FullMatch.size(); - return FullMatch.data() - Buffer.data(); + // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after + // the required preceding newline, which is consumed by the pattern in the + // case of CHECK-EMPTY but not CHECK-NEXT. + size_t MatchStartSkip = CheckTy == Check::CheckEmpty; + MatchLen = FullMatch.size() - MatchStartSkip; + return FullMatch.data() - Buffer.data() + MatchStartSkip; } @@ -511,11 +526,9 @@ Pattern::ComputeMatchDistance(StringRef Buffer, return BufferPrefix.edit_distance(ExampleString); } -/// Prints additional information about a failure to match involving this -/// pattern. -void Pattern::PrintFailureInfo( - const SourceMgr &SM, StringRef Buffer, - const StringMap &VariableTable) const { +void Pattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer, + const StringMap &VariableTable, + SMRange MatchRange) const { // If this was a regular expression using variables, print the current // variable values. if (!VariableUses.empty()) { @@ -547,11 +560,19 @@ void Pattern::PrintFailureInfo( } } - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, - OS.str()); + if (MatchRange.isValid()) + SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(), + {MatchRange}); + else + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), + SourceMgr::DK_Note, OS.str()); } } +} +void Pattern::PrintFuzzyMatch( + const SourceMgr &SM, StringRef Buffer, + const StringMap &VariableTable) const { // Attempt to find the closest/best fuzzy match. Usually an error happens // because some string in the output didn't exactly match. In these cases, we // would like to show the user a best guess at what "should have" matched, to @@ -741,6 +762,33 @@ static size_t CheckTypeSize(Check::CheckType Ty) { llvm_unreachable("Bad check type"); } +// Get a description of the type. +static std::string CheckTypeName(StringRef Prefix, Check::CheckType Ty) { + switch (Ty) { + case Check::CheckNone: + return "invalid"; + case Check::CheckPlain: + return Prefix; + case Check::CheckNext: + return Prefix.str() + "-NEXT"; + case Check::CheckSame: + return Prefix.str() + "-SAME"; + case Check::CheckNot: + return Prefix.str() + "-NOT"; + case Check::CheckDAG: + return Prefix.str() + "-DAG"; + case Check::CheckLabel: + return Prefix.str() + "-LABEL"; + case Check::CheckEmpty: + return Prefix.str() + "-EMPTY"; + case Check::CheckEOF: + return "implicit EOF"; + case Check::CheckBadNot: + return "bad NOT"; + } + llvm_unreachable("unknown CheckType"); +} + static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { if (Buffer.size() <= Prefix.size()) return Check::CheckNone; @@ -990,12 +1038,49 @@ static bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, return false; } -static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat, - StringRef Buffer, - StringMap &VariableTable) { +static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, + StringRef Prefix, SMLoc Loc, const Pattern &Pat, + StringRef Buffer, StringMap &VariableTable, + size_t MatchPos, size_t MatchLen) { + if (ExpectedMatch) { + if (!Verbose) + return; + if (!VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF) + return; + } + SMLoc MatchStart = SMLoc::getFromPointer(Buffer.data() + MatchPos); + SMLoc MatchEnd = SMLoc::getFromPointer(Buffer.data() + MatchPos + MatchLen); + SMRange MatchRange(MatchStart, MatchEnd); + SM.PrintMessage( + Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, + CheckTypeName(Prefix, Pat.getCheckTy()) + ": " + + (ExpectedMatch ? "expected" : "excluded") + + " string found in input"); + SM.PrintMessage(MatchStart, SourceMgr::DK_Note, "found here", {MatchRange}); + Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange); +} + +static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, + const CheckString &CheckStr, StringRef Buffer, + StringMap &VariableTable, size_t MatchPos, + size_t MatchLen) { + PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, + Buffer, VariableTable, MatchPos, MatchLen); +} + +static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, + StringRef Prefix, SMLoc Loc, const Pattern &Pat, + StringRef Buffer, + StringMap &VariableTable) { + if (!ExpectedMatch && !VerboseVerbose) + return; + // Otherwise, we have an error, emit an error message. - SM.PrintMessage(Loc, SourceMgr::DK_Error, - "expected string not found in input"); + SM.PrintMessage(Loc, + ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, + CheckTypeName(Prefix, Pat.getCheckTy()) + ": " + + (ExpectedMatch ? "expected" : "excluded") + + " string not found in input"); // Print the "scanning from here" line. If the current position is at the // end of a line, advance to the start of the next line. @@ -1005,13 +1090,16 @@ static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat, "scanning from here"); // Allow the pattern to print additional information if desired. - Pat.PrintFailureInfo(SM, Buffer, VariableTable); + Pat.PrintVariableUses(SM, Buffer, VariableTable); + if (ExpectedMatch) + Pat.PrintFuzzyMatch(SM, Buffer, VariableTable); } -static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr, - StringRef Buffer, - StringMap &VariableTable) { - PrintCheckFailed(SM, CheckStr.Loc, CheckStr.Pat, Buffer, VariableTable); +static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, + const CheckString &CheckStr, StringRef Buffer, + StringMap &VariableTable) { + PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, + Buffer, VariableTable); } /// Count the number of newlines in the specified range. @@ -1059,9 +1147,10 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, StringRef MatchBuffer = Buffer.substr(LastPos); size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable); if (MatchPos == StringRef::npos) { - PrintCheckFailed(SM, *this, MatchBuffer, VariableTable); + PrintNoMatch(true, SM, *this, MatchBuffer, VariableTable); return StringRef::npos; } + PrintMatch(true, SM, *this, MatchBuffer, VariableTable, MatchPos, MatchLen); // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT // or CHECK-NOT @@ -1107,11 +1196,6 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { const char *FirstNewLine = nullptr; unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); - // For CHECK-EMPTY, the preceding new line is consumed by the pattern, so - // this needs to be re-added. - if (Pat.getCheckTy() == Check::CheckEmpty) - ++NumNewLines; - if (NumNewLines == 0) { SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckName + ": is on the same line as previous match"); @@ -1177,13 +1261,15 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, size_t MatchLen = 0; size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); - if (Pos == StringRef::npos) + if (Pos == StringRef::npos) { + PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer, + VariableTable); continue; + } + + PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer, VariableTable, + Pos, MatchLen); - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Pos), - SourceMgr::DK_Error, Prefix + "-NOT: string occurred!"); - SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note, - Prefix + "-NOT: pattern specified here"); return true; } @@ -1230,11 +1316,15 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // With a group of CHECK-DAGs, a single mismatching means the match on // that group of CHECK-DAGs fails immediately. if (MatchPosBuf == StringRef::npos) { - PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable); + PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, MatchBuffer, + VariableTable); return StringRef::npos; } // Re-calc it as the offset relative to the start of the original string. MatchPos += MatchPosBuf; + if (VerboseVerbose) + PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable, + MatchPos, MatchLen); if (AllowDeprecatedDagOverlap) break; // Iterate previous matches until overlapping match or insertion point. @@ -1253,8 +1343,19 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, Matches.insert(MI, M); break; } + if (VerboseVerbose) { + SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos); + SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End); + SMRange OldRange(OldStart, OldEnd); + SM.PrintMessage(OldStart, SourceMgr::DK_Note, + "match discarded, overlaps earlier DAG match here", + {OldRange}); + } MatchPos = MI->End; } + if (!VerboseVerbose) + PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable, + MatchPos, MatchLen); if (!NotStrings.empty()) { if (MatchPos < LastPos) { @@ -1455,6 +1556,9 @@ int main(int argc, char **argv) { return 2; } + if (VerboseVerbose) + Verbose = true; + SourceMgr SM; // Read the expected strings from the check file.