1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

[FileCheck] Annotate input dump (4/7)

This patch implements input annotations for diagnostics that report
unexpected matches for CHECK-NOT.  Like wrong-line matches for
CHECK-NEXT, CHECK-SAME, and CHECK-EMPTY, these annotations mark match
ranges using red `!~~` to indicate bad matches that are errors.

For example:

```
$ FileCheck -dump-input=help
The following description was requested by -dump-input=help to
explain the input annotations printed by -dump-input=always and
-dump-input=fail:

  - L:     labels line number L of the input file
  - T:L    labels the only match result for a pattern of type T from line L of
           the check file
  - T:L'N  labels the Nth match result for a pattern of type T from line L of
           the check file
  - !~~    marks bad match, such as:
           - CHECK-NEXT on same line as previous match (error)
           - CHECK-NOT found (error)
  - X~~    marks search range when no match is found, such as:
           - CHECK-NEXT not found (error)
  - ?      marks fuzzy match when no match is found
  - colors error, fuzzy match

If you are not seeing color above or in input dumps, try: -color

$ FileCheck -v -dump-input=always check3 < input3 |& sed -n '/^<<<</,$p'
<<<<<<
       1: abc foobar def
not:2         !~~~~~     error: no match expected
>>>>>>

$ cat check3
CHECK:     abc
CHECK-NOT: foobar
CHECK:     def

$ cat input3
abc foobar def
```

Reviewed By: george.karpenkov, probinson

Differential Revision: https://reviews.llvm.org/D53896

llvm-svn: 349421
This commit is contained in:
Joel E. Denny 2018-12-18 00:02:47 +00:00
parent dac11cd74f
commit 3ef7d597d8
4 changed files with 77 additions and 19 deletions

View File

@ -163,6 +163,8 @@ struct FileCheckDiag {
/// example, there might be a fuzzy match after a fail.
enum MatchType {
// TODO: More members will appear with later patches in this series.
/// Indicates the final match for an excluded pattern.
MatchFinalButExcluded,
/// Indicates the final match for an expected pattern, but the match is on
/// the wrong line.
MatchFinalButWrongLine,
@ -210,7 +212,8 @@ struct FileCheckString {
bool CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const FileCheckPattern *> &NotStrings,
StringMap<StringRef> &VariableTable,
const FileCheckRequest &Req) const;
const FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) const;
size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
std::vector<const FileCheckPattern *> &NotStrings,
StringMap<StringRef> &VariableTable,

View File

@ -896,16 +896,18 @@ static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
int MatchedCount, StringRef Buffer,
StringMap<StringRef> &VariableTable, size_t MatchPos,
size_t MatchLen, const FileCheckRequest &Req) {
size_t MatchLen, const FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) {
if (ExpectedMatch) {
if (!Req.Verbose)
return;
if (!Req.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);
SMRange MatchRange = ProcessMatchResult(
ExpectedMatch ? FileCheckDiag::MatchTypeCount
: FileCheckDiag::MatchFinalButExcluded,
SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);
std::string Message = formatv("{0}: {1} string found in input",
Pat.getCheckTy().getDescription(Prefix),
(ExpectedMatch ? "expected" : "excluded"))
@ -915,17 +917,19 @@ static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
SM.PrintMessage(
Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
SM.PrintMessage(MatchStart, SourceMgr::DK_Note, "found here", {MatchRange});
SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
{MatchRange});
Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange);
}
static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
const FileCheckString &CheckStr, int MatchedCount,
StringRef Buffer, StringMap<StringRef> &VariableTable,
size_t MatchPos, size_t MatchLen,
FileCheckRequest &Req) {
size_t MatchPos, size_t MatchLen, FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) {
PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
MatchedCount, Buffer, VariableTable, MatchPos, MatchLen, Req);
MatchedCount, Buffer, VariableTable, MatchPos, MatchLen, Req,
Diags);
}
static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
@ -1036,7 +1040,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
return StringRef::npos;
}
PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos,
CurrentMatchLen, Req);
CurrentMatchLen, Req, Diags);
// move start point after the match
LastMatchEnd += MatchPos + CurrentMatchLen;
@ -1071,7 +1075,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
// If this match had "not strings", verify that they don't exist in the
// skipped region.
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req))
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags))
return StringRef::npos;
}
@ -1154,10 +1158,11 @@ bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
}
/// Verify there's no "not strings" in the given buffer.
bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const FileCheckPattern *> &NotStrings,
StringMap<StringRef> &VariableTable,
const FileCheckRequest &Req) const {
bool FileCheckString::CheckNot(
const SourceMgr &SM, StringRef Buffer,
const std::vector<const FileCheckPattern *> &NotStrings,
StringMap<StringRef> &VariableTable, const FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) const {
for (const FileCheckPattern *Pat : NotStrings) {
assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
@ -1171,7 +1176,7 @@ bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
}
PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, VariableTable,
Pos, MatchLen, Req);
Pos, MatchLen, Req, Diags);
return true;
}
@ -1236,7 +1241,7 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
MatchPos += MatchPosBuf;
if (Req.VerboseVerbose)
PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
VariableTable, MatchPos, MatchLen, Req);
VariableTable, MatchPos, MatchLen, Req, Diags);
MatchRange M{MatchPos, MatchPos + MatchLen};
if (Req.AllowDeprecatedDagOverlap) {
// We don't need to track all matches in this mode, so we just maintain
@ -1278,7 +1283,7 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
}
if (!Req.VerboseVerbose)
PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, VariableTable,
MatchPos, MatchLen, Req);
MatchPos, MatchLen, Req, Diags);
// Handle the end of a CHECK-DAG group.
if (std::next(PatItr) == PatEnd ||
@ -1289,7 +1294,7 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// region.
StringRef SkippedRegion =
Buffer.slice(StartPos, MatchRanges.begin()->Pos);
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req))
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags))
return StringRef::npos;
// Clear "not strings".
NotStrings.clear();

View File

@ -234,6 +234,53 @@
; EMP2-NEXT: >>>>>>
; EMP2-NOT: {{.}}
;--------------------------------------------------
; CHECK-NOT
;--------------------------------------------------
; No match (success) and unexpected match (error).
; RUN: echo 'hello' > %t.in
; RUN: echo 'world' >> %t.in
; RUN: echo 'again' >> %t.in
; RUN: echo 'CHECK-NOT: goodbye' > %t.chk
; RUN: echo 'CHECK-NOT: world' >> %t.chk
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefix=NOT
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=NOT,NOT-V
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=NOT,NOT-V,NOT-VV
; NOT: <<<<<<
; NOT-NEXT: 1: hello
; NOT-NEXT: 2: world
; NOT-NEXT: not:2 !~~~~ error: no match expected
; NOT-NEXT: 3: again
; NOT-NEXT: >>>>>>
; NOT-NOT: {{.}}
; Again, but with a CHECK instead of EOF as search range end.
; RUN: echo 'CHECK: ain' >> %t.chk
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefix=NOT2
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=NOT2,NOT2-V
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=NOT2,NOT2-V,NOT2-VV
; NOT2: <<<<<<
; NOT2-NEXT: 1: hello
; NOT2-NEXT: 2: world
; NOT2-NEXT: not:2 !~~~~ error: no match expected
; NOT2-NEXT: 3: again
; NOT2-NEXT: >>>>>>
; NOT2-NOT: {{.}}
;--------------------------------------------------
; CHECK-DAG
;--------------------------------------------------

View File

@ -143,6 +143,8 @@ struct MarkerStyle {
static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
switch (MatchTy) {
case FileCheckDiag::MatchFinalButExcluded:
return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
case FileCheckDiag::MatchFinalButWrongLine:
return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
case FileCheckDiag::MatchNoneButExpected:
@ -182,6 +184,7 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) {
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
OS << " marks bad match, such as:\n"
<< " - CHECK-NEXT on same line as previous match (error)\n"
<< " - CHECK-NOT found (error)\n"
<< " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
OS << " marks search range when no match is found, such as:\n"