[llvm] r335613 - [FileCheck] Add CHECK-EMPTY directive for checking for blank lines

James Henderson via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 26 08:15:45 PDT 2018


Author: jhenderson
Date: Tue Jun 26 08:15:45 2018
New Revision: 335613

URL: http://llvm.org/viewvc/llvm-project?rev=335613&view=rev
Log:
[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

Added:
    llvm/trunk/test/FileCheck/check-empty-tag.txt
Modified:
    llvm/trunk/docs/CommandGuide/FileCheck.rst
    llvm/trunk/utils/FileCheck/FileCheck.cpp

Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=335613&r1=335612&r2=335613&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)
+++ llvm/trunk/docs/CommandGuide/FileCheck.rst Tue Jun 26 08:15:45 2018
@@ -241,6 +241,25 @@ For example, the following works like yo
 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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

Added: llvm/trunk/test/FileCheck/check-empty-tag.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-empty-tag.txt?rev=335613&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-empty-tag.txt (added)
+++ llvm/trunk/test/FileCheck/check-empty-tag.txt Tue Jun 26 08:15:45 2018
@@ -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
+  
\ No newline at end of file

Modified: llvm/trunk/utils/FileCheck/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=335613&r1=335612&r2=335613&view=diff
==============================================================================
--- llvm/trunk/utils/FileCheck/FileCheck.cpp (original)
+++ llvm/trunk/utils/FileCheck/FileCheck.cpp Tue Jun 26 08:15:45 2018
@@ -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 Pat
       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::Check
   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(St
   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,
 
     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 SourceMg
 
 /// 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 Source
 
   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,




More information about the llvm-commits mailing list