[FileCheck] Implement -v and -vv for tracing matches
-v prints all directive pattern matches.
-vv additionally prints info that might be noise to users but that can
be helpful to FileCheck developers.
To maximize code reuse and to make diagnostics more consistent, this
patch also adjusts and extends some of the existing diagnostics.
CHECK-NOT failures now report variables uses. Many more diagnostics
now report the check prefix and kind of directive.
Reviewed By: probinson
Differential Revision: https://reviews.llvm.org/D47114
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336967 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/CommandGuide/FileCheck.rst b/docs/CommandGuide/FileCheck.rst
index ac7e810..dfa2fd2 100644
--- a/docs/CommandGuide/FileCheck.rst
+++ b/docs/CommandGuide/FileCheck.rst
@@ -95,6 +95,16 @@
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/test/FileCheck/check-empty.txt b/test/FileCheck/check-empty.txt
index 319b411..1caff2a 100644
--- a/test/FileCheck/check-empty.txt
+++ b/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/test/FileCheck/check-label-dag.txt b/test/FileCheck/check-label-dag.txt
index 2f54c3e..1ce4a8d 100644
--- a/test/FileCheck/check-label-dag.txt
+++ b/test/FileCheck/check-label-dag.txt
@@ -7,5 +7,5 @@
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/test/FileCheck/check-multiple-prefixes-nomatch-2.txt b/test/FileCheck/check-multiple-prefixes-nomatch-2.txt
index 6055471..55c5211 100644
--- a/test/FileCheck/check-multiple-prefixes-nomatch-2.txt
+++ b/test/FileCheck/check-multiple-prefixes-nomatch-2.txt
@@ -8,5 +8,5 @@
; 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/test/FileCheck/check-multiple-prefixes-nomatch.txt b/test/FileCheck/check-multiple-prefixes-nomatch.txt
index b1a4132..90a2a38 100644
--- a/test/FileCheck/check-multiple-prefixes-nomatch.txt
+++ b/test/FileCheck/check-multiple-prefixes-nomatch.txt
@@ -8,5 +8,5 @@
; 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/test/FileCheck/check-not-diaginfo.txt b/test/FileCheck/check-not-diaginfo.txt
index 44a46a3..de2d13e 100644
--- a/test/FileCheck/check-not-diaginfo.txt
+++ b/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/test/FileCheck/defines.txt b/test/FileCheck/defines.txt
index d2219b7..c788124 100644
--- a/test/FileCheck/defines.txt
+++ b/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/test/FileCheck/implicit-check-not.txt b/test/FileCheck/implicit-check-not.txt
index 4267736..39b758e 100644
--- a/test/FileCheck/implicit-check-not.txt
+++ b/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/test/FileCheck/match-full-lines.txt b/test/FileCheck/match-full-lines.txt
index d6b10a5..1d6a965 100644
--- a/test/FileCheck/match-full-lines.txt
+++ b/test/FileCheck/match-full-lines.txt
@@ -26,28 +26,28 @@
// 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/test/FileCheck/verbose.txt b/test/FileCheck/verbose.txt
new file mode 100644
index 0000000..e6eec5e
--- /dev/null
+++ b/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/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index cd3175f..4efe535 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -90,6 +90,14 @@
"provided for convenience as old tests are migrated to the new\n"
"non-overlapping CHECK-DAG implementation.\n"));
+static cl::opt<bool> Verbose("v", cl::init(false),
+ cl::desc("Print directive pattern matches.\n"));
+
+static cl::opt<bool> VerboseVerbose(
+ "vv", cl::init(false),
+ cl::desc("Print information helpful in diagnosing internal FileCheck\n"
+ "issues. Implies -v.\n"));
+
typedef cl::list<std::string>::const_iterator prefix_iterator;
//===----------------------------------------------------------------------===//
@@ -154,8 +162,11 @@
unsigned LineNumber);
size_t Match(StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const;
- void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
- const StringMap<StringRef> &VariableTable) const;
+ void PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable,
+ SMRange MatchRange = None) const;
+ void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable) const;
bool hasVariable() const {
return !(VariableUses.empty() && VariableDefs.empty());
@@ -484,8 +495,12 @@
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 @@
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<StringRef> &VariableTable) const {
+void Pattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
+ const StringMap<StringRef> &VariableTable,
+ SMRange MatchRange) const {
// If this was a regular expression using variables, print the current
// variable values.
if (!VariableUses.empty()) {
@@ -547,11 +560,19 @@
}
}
- 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<StringRef> &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 @@
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 @@
return false;
}
-static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat,
- StringRef Buffer,
- StringMap<StringRef> &VariableTable) {
+static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
+ StringRef Prefix, SMLoc Loc, const Pattern &Pat,
+ StringRef Buffer, StringMap<StringRef> &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<StringRef> &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<StringRef> &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 @@
"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<StringRef> &VariableTable) {
- PrintCheckFailed(SM, CheckStr.Loc, CheckStr.Pat, Buffer, VariableTable);
+static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
+ const CheckString &CheckStr, StringRef Buffer,
+ StringMap<StringRef> &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 @@
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 @@
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 @@
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;
+ }
- 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");
+ PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer, VariableTable,
+ Pos, MatchLen);
+
return true;
}
@@ -1230,11 +1316,15 @@
// 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 @@
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 @@
return 2;
}
+ if (VerboseVerbose)
+ Verbose = true;
+
SourceMgr SM;
// Read the expected strings from the check file.