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
--- /dev/null
+; 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: {{.}}
"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;
//===----------------------------------------------------------------------===//
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());
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;
}
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()) {
}
}
- 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
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;
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.
"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.
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
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");
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;
}
// 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.
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) {
return 2;
}
+ if (VerboseVerbose)
+ Verbose = true;
+
SourceMgr SM;
// Read the expected strings from the check file.