mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[FileCheck] Add CHECK-EMPTY directive for checking for blank lines
Prior to this change, there was no clean way of getting FileCheck to check that a line is completely empty. The expected way of using "CHECK: {{^$}}" does not work because the '^' matches the end of the previous match (this behaviour may be desirable in certain instances). For the same reason, "CHECK-NEXT: {{^$}}" will fail when the previous match was at the end of the line, as the pattern will match there. Using the recommended [[:space:]] to match an explicit new line could also match a space, and thus is not always desired. Literal '\n' matches also do not work. A workaround was suggested in the review, but it is a little clunky. This change adds a new directive that behaves the same as CHECK-NEXT, except that it only matches against empty lines (nothing, not even whitespace, is allowed). As with CHECK-NEXT, it will fail if more than one newline occurs before the next blank line. Example usage: ; test.txt foo bar ; CHECK: foo ; CHECK-EMPTY: ; CHECK-NEXT: bar Differential Revision: https://reviews.llvm.org/D28896 Reviewed by: probinson llvm-svn: 335613
This commit is contained in:
parent
974db97095
commit
de9948f983
@ -241,6 +241,25 @@ For example, the following works like you'd expect:
|
||||
it and the previous directive. A "``CHECK-SAME:``" cannot be the first
|
||||
directive in a file.
|
||||
|
||||
The "CHECK-EMPTY:" directive
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you need to check that the next line has nothing on it, not even whitespace,
|
||||
you can use the "``CHECK-EMPTY:``" directive.
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
foo
|
||||
|
||||
bar
|
||||
; CHECK: foo
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: bar
|
||||
|
||||
Just like "``CHECK-NEXT:``" the directive will fail if there is more than one
|
||||
newline before it finds the next blank line, and it cannot be the first
|
||||
directive in a file.
|
||||
|
||||
The "CHECK-NOT:" directive
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
45
test/FileCheck/check-empty-tag.txt
Normal file
45
test/FileCheck/check-empty-tag.txt
Normal file
@ -0,0 +1,45 @@
|
||||
; basic functionality
|
||||
; RUN: FileCheck %s --input-file %s --check-prefix=CHECK1
|
||||
foo
|
||||
|
||||
bar
|
||||
CHECK1: foo
|
||||
CHECK1-EMPTY:
|
||||
CHECK1-NEXT: bar
|
||||
|
||||
; next line must be blank
|
||||
; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK2A 2>&1 | FileCheck %s --check-prefix=CHECK2B
|
||||
badger
|
||||
CHECK2A: badger
|
||||
CHECK2A-EMPTY:
|
||||
CHECK2B: CHECK2A-EMPTY: is not on the line after the previous match
|
||||
|
||||
; CHECK-EMPTY must have empty pattern
|
||||
; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK3A 2>&1 | FileCheck %s --check-prefix=CHECK3B
|
||||
CHECK3A: foo
|
||||
CHECK3A-EMPTY: this is not empty
|
||||
CHECK3B: found non-empty check string for empty check with prefix 'CHECK3A:'
|
||||
|
||||
; CHECK-EMPTY cannot be the first check
|
||||
; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK4A 2>&1 | FileCheck %s --check-prefix=CHECK4B
|
||||
CHECK4A-EMPTY:
|
||||
CHECK4B: found 'CHECK4A-EMPTY' without previous 'CHECK4A: line
|
||||
|
||||
; CHECK-EMPTY-NOT and CHECK-NOT-EMPTY rejected
|
||||
; RUN: not FileCheck %s --input-file %s --check-prefixes=CHECK5A 2>&1 | FileCheck %s --check-prefix=CHECK5C
|
||||
; RUN: not FileCheck %s --input-file %s --check-prefixes=CHECK5B 2>&1 | FileCheck %s --check-prefix=CHECK5C
|
||||
CHECK5A-EMPTY-NOT:
|
||||
CHECK5B-NOT-EMPTY:
|
||||
CHECK5C: unsupported -NOT combo on prefix 'CHECK5{{A|B}}'
|
||||
|
||||
; whitespace does not count as empty
|
||||
; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK6A --match-full-lines 2>&1 | FileCheck %s --check-prefix=CHECK6B
|
||||
CHECK6A: the next line has spaces
|
||||
CHECK6A-EMPTY:
|
||||
CHECK6B: expected string not found in input
|
||||
|
||||
; ***don't add any further blank lines after this point***
|
||||
; CHECK-EMPTY, like CHECK-NEXT, will report an error if the first matching
|
||||
; line is not the line immediately following the previous check.
|
||||
the next line has spaces
|
||||
|
@ -97,6 +97,7 @@ enum CheckType {
|
||||
CheckNot,
|
||||
CheckDAG,
|
||||
CheckLabel,
|
||||
CheckEmpty,
|
||||
|
||||
/// Indicates the pattern only matches the end of file. This is used for
|
||||
/// trailing CHECK-NOTs.
|
||||
@ -184,12 +185,25 @@ bool Pattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
|
||||
PatternStr = PatternStr.substr(0, PatternStr.size() - 1);
|
||||
|
||||
// Check that there is something on the line.
|
||||
if (PatternStr.empty()) {
|
||||
if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {
|
||||
SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
|
||||
"found empty check string with prefix '" + Prefix + ":'");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {
|
||||
SM.PrintMessage(
|
||||
PatternLoc, SourceMgr::DK_Error,
|
||||
"found non-empty check string for empty check with prefix '" + Prefix +
|
||||
":'");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CheckTy == Check::CheckEmpty) {
|
||||
RegExStr = "(\n$)";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if this is a fixed string, or if it has regex pieces.
|
||||
if (!MatchFullLinesHere &&
|
||||
(PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
|
||||
@ -709,6 +723,9 @@ static size_t CheckTypeSize(Check::CheckType Ty) {
|
||||
case Check::CheckLabel:
|
||||
return sizeof("-LABEL:") - 1;
|
||||
|
||||
case Check::CheckEmpty:
|
||||
return sizeof("-EMPTY:") - 1;
|
||||
|
||||
case Check::CheckEOF:
|
||||
llvm_unreachable("Should not be using EOF size");
|
||||
}
|
||||
@ -745,10 +762,14 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
|
||||
if (Rest.startswith("LABEL:"))
|
||||
return Check::CheckLabel;
|
||||
|
||||
if (Rest.startswith("EMPTY:"))
|
||||
return Check::CheckEmpty;
|
||||
|
||||
// You can't combine -NOT with another suffix.
|
||||
if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
|
||||
Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
|
||||
Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:"))
|
||||
Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
|
||||
Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
|
||||
return Check::CheckBadNot;
|
||||
|
||||
return Check::CheckNone;
|
||||
@ -908,10 +929,13 @@ static bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
|
||||
|
||||
Buffer = Buffer.substr(EOL);
|
||||
|
||||
// Verify that CHECK-NEXT lines have at least one CHECK line before them.
|
||||
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) &&
|
||||
// Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
|
||||
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
|
||||
CheckTy == Check::CheckEmpty) &&
|
||||
CheckStrings.empty()) {
|
||||
StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME";
|
||||
StringRef Type = CheckTy == Check::CheckNext
|
||||
? "NEXT"
|
||||
: CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
|
||||
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
|
||||
SourceMgr::DK_Error,
|
||||
"found '" + UsedPrefix + "-" + Type +
|
||||
@ -1057,22 +1081,32 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
|
||||
|
||||
/// Verify there is a single line in the given buffer.
|
||||
bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
|
||||
if (Pat.getCheckTy() != Check::CheckNext)
|
||||
if (Pat.getCheckTy() != Check::CheckNext &&
|
||||
Pat.getCheckTy() != Check::CheckEmpty)
|
||||
return false;
|
||||
|
||||
Twine CheckName =
|
||||
Prefix +
|
||||
Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");
|
||||
|
||||
// Count the number of newlines between the previous match and this one.
|
||||
assert(Buffer.data() !=
|
||||
SM.getMemoryBuffer(SM.FindBufferContainingLoc(
|
||||
SMLoc::getFromPointer(Buffer.data())))
|
||||
->getBufferStart() &&
|
||||
"CHECK-NEXT can't be the first check in a file");
|
||||
"CHECK-NEXT and CHECK-EMPTY can't be the first check in a file");
|
||||
|
||||
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,
|
||||
Prefix + "-NEXT: is on the same line as previous match");
|
||||
CheckName + ": is on the same line as previous match");
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
|
||||
"'next' match was here");
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
|
||||
@ -1082,8 +1116,8 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
|
||||
|
||||
if (NumNewLines != 1) {
|
||||
SM.PrintMessage(Loc, SourceMgr::DK_Error,
|
||||
Prefix +
|
||||
"-NEXT: is not on the line after the previous match");
|
||||
CheckName +
|
||||
": is not on the line after the previous match");
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
|
||||
"'next' match was here");
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
|
||||
|
Loading…
Reference in New Issue
Block a user