[llvm] r346722 - [FileCheck] introduce CHECK-COUNT-<num> repetition directive

Fedor Sergeev via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 12 16:46:13 PST 2018


Author: fedor.sergeev
Date: Mon Nov 12 16:46:13 2018
New Revision: 346722

URL: http://llvm.org/viewvc/llvm-project?rev=346722&view=rev
Log:
[FileCheck] introduce CHECK-COUNT-<num> repetition directive

In some cases it is desirable to match the same pattern repeatedly
many times. Currently the only way to do it is to copy the same
check pattern as many times as needed. And that gets pretty unwieldy
when its more than count is big.

Introducing CHECK-COUNT-<num> directive which acts like a plain CHECK
directive yet matches the same pattern exactly <num> times.

Extended FileCheckType to a struct to add Count there.
Changed some parsing routines to handle non-fixed length of directive
(all currently existing directives were fixed-length).

The code is generic enough to allow future support for COUNT in more
than just PlainCheck directives.

See motivating example for this feature in reviews.llvm.org/D54223.

Reviewed By: chandlerc, dblaikie
Differential Revision: https://reviews.llvm.org/D54336

Added:
    llvm/trunk/test/FileCheck/check-count.txt
Modified:
    llvm/trunk/docs/CommandGuide/FileCheck.rst
    llvm/trunk/include/llvm/Support/FileCheck.h
    llvm/trunk/lib/Support/FileCheck.cpp

Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=346722&r1=346721&r2=346722&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)
+++ llvm/trunk/docs/CommandGuide/FileCheck.rst Mon Nov 12 16:46:13 2018
@@ -311,6 +311,29 @@ can be used:
    ; CHECK: ret i8
    }
 
+The "CHECK-COUNT:" directive
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you need to match multiple lines with the same pattern over and over again
+you can repeat a plain ``CHECK:`` as many times as needed. If that looks too
+boring you can instead use a counted check "``CHECK-COUNT-<num>:``", where
+``<num>`` is a positive decimal number. It will match the pattern exactly
+``<num>`` times, no more and no less. If you specified a custom check prefix,
+just use "``<PREFIX>-COUNT-<num>:``" for the same effect.
+Here is a simple example:
+
+.. code-block:: llvm
+
+   Loop at depth 1
+   Loop at depth 1
+   Loop at depth 1
+   Loop at depth 1
+     Loop at depth 2
+       Loop at depth 3
+
+   ; CHECK-COUNT-6: Loop at depth {{[0-9]+}}
+   ; CHECK-NOT:     Loop at depth {{[0-9]+}}
+
 The "CHECK-DAG:" directive
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

Modified: llvm/trunk/include/llvm/Support/FileCheck.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=346722&r1=346721&r2=346722&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileCheck.h (original)
+++ llvm/trunk/include/llvm/Support/FileCheck.h Mon Nov 12 16:46:13 2018
@@ -43,7 +43,8 @@ struct FileCheckRequest {
 //===----------------------------------------------------------------------===//
 
 namespace Check {
-enum FileCheckType {
+
+enum FileCheckKind {
   CheckNone = 0,
   CheckPlain,
   CheckNext,
@@ -58,7 +59,26 @@ enum FileCheckType {
   CheckEOF,
 
   /// Marks when parsing found a -NOT check combined with another CHECK suffix.
-  CheckBadNot
+  CheckBadNot,
+
+  /// Marks when parsing found a -COUNT directive with invalid count value.
+  CheckBadCount
+};
+
+class FileCheckType {
+  FileCheckKind Kind;
+  int Count; //< optional Count for some checks
+
+public:
+  FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}
+  FileCheckType(const FileCheckType &) = default;
+
+  operator FileCheckKind() const { return Kind; }
+
+  int getCount() const { return Count; }
+  FileCheckType &setCount(int C);
+
+  std::string getDescription(StringRef Prefix) const;
 };
 }
 
@@ -113,6 +133,8 @@ public:
 
   Check::FileCheckType getCheckTy() const { return CheckTy; }
 
+  int getCount() const { return CheckTy.getCount(); }
+
 private:
   bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
   void AddBackrefToRegEx(unsigned BackrefNum);

Modified: llvm/trunk/lib/Support/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=346722&r1=346721&r2=346722&view=diff
==============================================================================
--- llvm/trunk/lib/Support/FileCheck.cpp (original)
+++ llvm/trunk/lib/Support/FileCheck.cpp Mon Nov 12 16:46:13 2018
@@ -16,8 +16,12 @@
 
 #include "llvm/Support/FileCheck.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <cstdint>
 #include <list>
 #include <map>
+#include <tuple>
+#include <utility>
 
 using namespace llvm;
 
@@ -531,47 +535,22 @@ static bool IsPartOfWord(char c) {
   return (isalnum(c) || c == '-' || c == '_');
 }
 
-// Get the size of the prefix extension.
-static size_t CheckTypeSize(Check::FileCheckType Ty) {
-  switch (Ty) {
-  case Check::CheckNone:
-  case Check::CheckBadNot:
-    return 0;
-
-  case Check::CheckPlain:
-    return sizeof(":") - 1;
-
-  case Check::CheckNext:
-    return sizeof("-NEXT:") - 1;
-
-  case Check::CheckSame:
-    return sizeof("-SAME:") - 1;
-
-  case Check::CheckNot:
-    return sizeof("-NOT:") - 1;
-
-  case Check::CheckDAG:
-    return sizeof("-DAG:") - 1;
-
-  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");
-  }
-
-  llvm_unreachable("Bad check type");
+Check::FileCheckType &Check::FileCheckType::setCount(int C) {
+  assert(Count > 0 || "zero and negative counts are not supported");
+  assert((C == 1 || Kind == CheckPlain) &&
+         "count supported only for plain CHECK directives");
+  Count = C;
+  return *this;
 }
 
 // Get a description of the type.
-static std::string CheckTypeName(StringRef Prefix, Check::FileCheckType Ty) {
-  switch (Ty) {
+std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
+  switch (Kind) {
   case Check::CheckNone:
     return "invalid";
   case Check::CheckPlain:
+    if (Count > 1)
+      return Prefix.str() + "-COUNT";
     return Prefix;
   case Check::CheckNext:
     return Prefix.str() + "-NEXT";
@@ -589,50 +568,65 @@ static std::string CheckTypeName(StringR
     return "implicit EOF";
   case Check::CheckBadNot:
     return "bad NOT";
+  case Check::CheckBadCount:
+    return "bad COUNT";
   }
   llvm_unreachable("unknown FileCheckType");
 }
 
-static Check::FileCheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
+static std::pair<Check::FileCheckType, StringRef>
+FindCheckType(StringRef Buffer, StringRef Prefix) {
   if (Buffer.size() <= Prefix.size())
-    return Check::CheckNone;
+    return {Check::CheckNone, StringRef()};
 
   char NextChar = Buffer[Prefix.size()];
 
+  StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
   // Verify that the : is present after the prefix.
   if (NextChar == ':')
-    return Check::CheckPlain;
+    return {Check::CheckPlain, Rest};
 
   if (NextChar != '-')
-    return Check::CheckNone;
+    return {Check::CheckNone, StringRef()};
 
-  StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
-  if (Rest.startswith("NEXT:"))
-    return Check::CheckNext;
+  if (Rest.consume_front("COUNT-")) {
+    int64_t Count;
+    if (Rest.consumeInteger(10, Count))
+      // Error happened in parsing integer.
+      return {Check::CheckBadCount, Rest};
+    if (Count <= 0 || Count > INT32_MAX)
+      return {Check::CheckBadCount, Rest};
+    if (!Rest.consume_front(":"))
+      return {Check::CheckBadCount, Rest};
+    return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest};
+  }
 
-  if (Rest.startswith("SAME:"))
-    return Check::CheckSame;
+  if (Rest.consume_front("NEXT:"))
+    return {Check::CheckNext, Rest};
 
-  if (Rest.startswith("NOT:"))
-    return Check::CheckNot;
+  if (Rest.consume_front("SAME:"))
+    return {Check::CheckSame, Rest};
 
-  if (Rest.startswith("DAG:"))
-    return Check::CheckDAG;
+  if (Rest.consume_front("NOT:"))
+    return {Check::CheckNot, Rest};
 
-  if (Rest.startswith("LABEL:"))
-    return Check::CheckLabel;
+  if (Rest.consume_front("DAG:"))
+    return {Check::CheckDAG, Rest};
 
-  if (Rest.startswith("EMPTY:"))
-    return Check::CheckEmpty;
+  if (Rest.consume_front("LABEL:"))
+    return {Check::CheckLabel, Rest};
+
+  if (Rest.consume_front("EMPTY:"))
+    return {Check::CheckEmpty, Rest};
 
   // 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("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
-    return Check::CheckBadNot;
+    return {Check::CheckBadNot, Rest};
 
-  return Check::CheckNone;
+  return {Check::CheckNone, Rest};
 }
 
 // From the given position, find the next character after the word.
@@ -651,8 +645,12 @@ static size_t SkipWord(StringRef Str, si
 /// 2) The found prefix must be followed by a valid check type suffix using \c
 ///    FindCheckType above.
 ///
-/// The first match of the regular expression to satisfy these two is returned,
-/// otherwise an empty StringRef is returned to indicate failure.
+/// Returns a pair of StringRefs into the Buffer, which combines:
+///   - the first match of the regular expression to satisfy these two is
+///   returned,
+///     otherwise an empty StringRef is returned to indicate failure.
+///   - buffer rewound to the location right after parsed suffix, for parsing
+///     to continue from
 ///
 /// If this routine returns a valid prefix, it will also shrink \p Buffer to
 /// start at the beginning of the returned prefix, increment \p LineNumber for
@@ -661,16 +659,16 @@ static size_t SkipWord(StringRef Str, si
 ///
 /// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
 /// is unspecified.
-static StringRef FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
-                                         unsigned &LineNumber,
-                                         Check::FileCheckType &CheckTy) {
+static std::pair<StringRef, StringRef>
+FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
+                        unsigned &LineNumber, Check::FileCheckType &CheckTy) {
   SmallVector<StringRef, 2> Matches;
 
   while (!Buffer.empty()) {
     // Find the first (longest) match using the RE.
     if (!PrefixRE.match(Buffer, &Matches))
       // No match at all, bail.
-      return StringRef();
+      return {StringRef(), StringRef()};
 
     StringRef Prefix = Matches[0];
     Matches.clear();
@@ -690,11 +688,12 @@ static StringRef FindFirstMatchingPrefix
     // intentional and unintentional uses of this feature.
     if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
       // Now extract the type.
-      CheckTy = FindCheckType(Buffer, Prefix);
+      StringRef AfterSuffix;
+      std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);
 
       // If we've found a valid check type for this prefix, we're done.
       if (CheckTy != Check::CheckNone)
-        return Prefix;
+        return {Prefix, AfterSuffix};
     }
 
     // If we didn't successfully find a prefix, we need to skip this invalid
@@ -704,7 +703,7 @@ static StringRef FindFirstMatchingPrefix
   }
 
   // We ran out of buffer while skipping partial matches so give up.
-  return StringRef();
+  return {StringRef(), StringRef()};
 }
 
 /// Read the check file, which specifies the sequence of expected strings.
@@ -742,19 +741,26 @@ bool llvm::FileCheck::ReadCheckFile(Sour
     Check::FileCheckType CheckTy;
 
     // See if a prefix occurs in the memory buffer.
-    StringRef UsedPrefix = FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber,
-                                                   CheckTy);
+    StringRef UsedPrefix;
+    StringRef AfterSuffix;
+    std::tie(UsedPrefix, AfterSuffix) =
+        FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);
     if (UsedPrefix.empty())
       break;
     assert(UsedPrefix.data() == Buffer.data() &&
            "Failed to move Buffer's start forward, or pointed prefix outside "
            "of the buffer!");
+    assert(AfterSuffix.data() >= Buffer.data() &&
+           AfterSuffix.data() < Buffer.data() + Buffer.size() &&
+           "Parsing after suffix doesn't start inside of buffer!");
 
     // Location to use for error messages.
     const char *UsedPrefixStart = UsedPrefix.data();
 
-    // Skip the buffer to the end.
-    Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy));
+    // Skip the buffer to the end of parsed suffix (or just prefix, if no good
+    // suffix was processed).
+    Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())
+                                 : AfterSuffix;
 
     // Complain about useful-looking but unsupported suffixes.
     if (CheckTy == Check::CheckBadNot) {
@@ -763,6 +769,14 @@ bool llvm::FileCheck::ReadCheckFile(Sour
       return true;
     }
 
+    // Complain about invalid count specification.
+    if (CheckTy == Check::CheckBadCount) {
+      SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
+                      "invalid count in -COUNT specification on prefix '" +
+                          UsedPrefix + "'");
+      return true;
+    }
+
     // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
     // leading whitespace.
     if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
@@ -845,9 +859,9 @@ bool llvm::FileCheck::ReadCheckFile(Sour
 
 static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
                        StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
-                       StringRef Buffer, StringMap<StringRef> &VariableTable,
-                       size_t MatchPos, size_t MatchLen,
-                       const FileCheckRequest &Req) {
+                       int MatchedCount, StringRef Buffer,
+                       StringMap<StringRef> &VariableTable, size_t MatchPos,
+                       size_t MatchLen, const FileCheckRequest &Req) {
   if (ExpectedMatch) {
     if (!Req.Verbose)
       return;
@@ -857,37 +871,46 @@ static void PrintMatch(bool ExpectedMatc
   SMLoc MatchStart = SMLoc::getFromPointer(Buffer.data() + MatchPos);
   SMLoc MatchEnd = SMLoc::getFromPointer(Buffer.data() + MatchPos + MatchLen);
   SMRange MatchRange(MatchStart, MatchEnd);
+  std::string Message = formatv("{0}: {1} string found in input",
+                                Pat.getCheckTy().getDescription(Prefix),
+                                (ExpectedMatch ? "expected" : "excluded"))
+                            .str();
+  if (Pat.getCount() > 1)
+    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
+
   SM.PrintMessage(
-      Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error,
-      CheckTypeName(Prefix, Pat.getCheckTy()) + ": " +
-          (ExpectedMatch ? "expected" : "excluded") +
-          " string found in input");
+      Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
   SM.PrintMessage(MatchStart, SourceMgr::DK_Note, "found here", {MatchRange});
   Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange);
 }
 
 static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
-                       const FileCheckString &CheckStr, StringRef Buffer,
-                       StringMap<StringRef> &VariableTable, size_t MatchPos,
-                       size_t MatchLen, FileCheckRequest &Req) {
+                       const FileCheckString &CheckStr, int MatchedCount,
+                       StringRef Buffer, StringMap<StringRef> &VariableTable,
+                       size_t MatchPos, size_t MatchLen,
+                       FileCheckRequest &Req) {
   PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
-             Buffer, VariableTable, MatchPos, MatchLen, Req);
+             MatchedCount, Buffer, VariableTable, MatchPos, MatchLen, Req);
 }
 
 static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
-                         StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
-                         StringRef Buffer,
-                         StringMap<StringRef> &VariableTable,
+                         StringRef Prefix, SMLoc Loc,
+                         const FileCheckPattern &Pat, int MatchedCount,
+                         StringRef Buffer, StringMap<StringRef> &VariableTable,
                          bool VerboseVerbose) {
   if (!ExpectedMatch && !VerboseVerbose)
     return;
 
   // Otherwise, we have an error, emit an error message.
-  SM.PrintMessage(Loc,
-                  ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark,
-                  CheckTypeName(Prefix, Pat.getCheckTy()) + ": " +
-                      (ExpectedMatch ? "expected" : "excluded") +
-                      " string not found in input");
+  std::string Message = formatv("{0}: {1} string not found in input",
+                                Pat.getCheckTy().getDescription(Prefix),
+                                (ExpectedMatch ? "expected" : "excluded"))
+                            .str();
+  if (Pat.getCount() > 1)
+    Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
+
+  SM.PrintMessage(
+      Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);
 
   // 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.
@@ -903,11 +926,11 @@ static void PrintNoMatch(bool ExpectedMa
 }
 
 static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
-                         const FileCheckString &CheckStr, StringRef Buffer,
-                         StringMap<StringRef> &VariableTable,
+                         const FileCheckString &CheckStr, int MatchedCount,
+                         StringRef Buffer, StringMap<StringRef> &VariableTable,
                          bool VerboseVerbose) {
   PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
-               Buffer, VariableTable, VerboseVerbose);
+               MatchedCount, Buffer, VariableTable, VerboseVerbose);
 }
 
 /// Count the number of newlines in the specified range.
@@ -953,18 +976,38 @@ size_t FileCheckString::Check(const Sour
   }
 
   // Match itself from the last position after matching CHECK-DAG.
-  StringRef MatchBuffer = Buffer.substr(LastPos);
-  size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
-  if (MatchPos == StringRef::npos) {
-    PrintNoMatch(true, SM, *this, MatchBuffer, VariableTable, Req.VerboseVerbose);
-    return StringRef::npos;
+  size_t LastMatchEnd = LastPos;
+  size_t FirstMatchPos = 0;
+  // Go match the pattern Count times. Majority of patterns only match with
+  // count 1 though.
+  assert(Pat.getCount() != 0 && "pattern count can not be zero");
+  for (int i = 1; i <= Pat.getCount(); i++) {
+    StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
+    size_t CurrentMatchLen;
+    // get a match at current start point
+    size_t MatchPos = Pat.Match(MatchBuffer, CurrentMatchLen, VariableTable);
+    if (i == 1)
+      FirstMatchPos = LastPos + MatchPos;
+
+    // report
+    if (MatchPos == StringRef::npos) {
+      PrintNoMatch(true, SM, *this, i, MatchBuffer, VariableTable,
+                   Req.VerboseVerbose);
+      return StringRef::npos;
+    }
+    PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos,
+               CurrentMatchLen, Req);
+
+    // move start point after the match
+    LastMatchEnd += MatchPos + CurrentMatchLen;
   }
-  PrintMatch(true, SM, *this, MatchBuffer, VariableTable, MatchPos, MatchLen, Req);
+  // Full match len counts from first match pos.
+  MatchLen = LastMatchEnd - FirstMatchPos;
 
   // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
   // or CHECK-NOT
   if (!IsLabelScanMode) {
-    StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
+    StringRef SkippedRegion = Buffer.substr(LastPos, FirstMatchPos - LastPos);
 
     // If this check is a "CHECK-NEXT", verify that the previous match was on
     // the previous line (i.e. that there is one newline between them).
@@ -982,7 +1025,7 @@ size_t FileCheckString::Check(const Sour
       return StringRef::npos;
   }
 
-  return LastPos + MatchPos;
+  return FirstMatchPos;
 }
 
 /// Verify there is a single line in the given buffer.
@@ -1072,12 +1115,12 @@ bool FileCheckString::CheckNot(const Sou
     size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
 
     if (Pos == StringRef::npos) {
-      PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer,
+      PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
                    VariableTable, Req.VerboseVerbose);
       continue;
     }
 
-    PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer, VariableTable,
+    PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, VariableTable,
                Pos, MatchLen, Req);
 
     return true;
@@ -1133,15 +1176,15 @@ size_t FileCheckString::CheckDag(const S
       // With a group of CHECK-DAGs, a single mismatching means the match on
       // that group of CHECK-DAGs fails immediately.
       if (MatchPosBuf == StringRef::npos) {
-        PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, MatchBuffer,
+        PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
                      VariableTable, Req.VerboseVerbose);
         return StringRef::npos;
       }
       // Re-calc it as the offset relative to the start of the original string.
       MatchPos += MatchPosBuf;
       if (Req.VerboseVerbose)
-        PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
-                   MatchPos, MatchLen, Req);
+        PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
+                   VariableTable, MatchPos, MatchLen, Req);
       MatchRange M{MatchPos, MatchPos + MatchLen};
       if (Req.AllowDeprecatedDagOverlap) {
         // We don't need to track all matches in this mode, so we just maintain
@@ -1182,7 +1225,7 @@ size_t FileCheckString::CheckDag(const S
       MatchPos = MI->End;
     }
     if (!Req.VerboseVerbose)
-      PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
+      PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, VariableTable,
                  MatchPos, MatchLen, Req);
 
     // Handle the end of a CHECK-DAG group.

Added: llvm/trunk/test/FileCheck/check-count.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-count.txt?rev=346722&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-count.txt (added)
+++ llvm/trunk/test/FileCheck/check-count.txt Mon Nov 12 16:46:13 2018
@@ -0,0 +1,100 @@
+;
+; Basic error checking.
+;
+
+this is something else
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-ERR1 2>&1 | FileCheck %s --check-prefix=ERRCOUNT1
+CHECK-ERR1-COUNT-xx: this
+ERRCOUNT1: [[@LINE-1]]:18: error: invalid count in -COUNT specification on prefix 'CHECK-ERR1'
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-ERR2 2>&1 | FileCheck %s --check-prefix=ERRCOUNT2
+CHECK-ERR2-COUNT-0x1: something
+ERRCOUNT2: [[@LINE-1]]:19: error: invalid count in -COUNT specification on prefix 'CHECK-ERR2'
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-ERR3 2>&1 | FileCheck %s --check-prefix=ERRCOUNT3
+CHECK-ERR3-COUNT-100x: else
+ERRCOUNT3: [[@LINE-1]]:21: error: invalid count in -COUNT specification on prefix 'CHECK-ERR3'
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-ERR4 2>&1 | FileCheck %s --check-prefix=ERRCOUNT4
+CHECK-ERR4-COUNT-0: else
+ERRCOUNT4: [[@LINE-1]]:19: error: invalid count in -COUNT specification on prefix 'CHECK-ERR4'
+
+;
+; Main functionality
+;
+
+this is duplicate
+this is duplicate
+this is not duplicate
+this is duplicate
+this is duplicate
+this is duplicate
+
+; RUN: FileCheck %s --input-file %s --check-prefix=CHECK-CNT1
+CHECK-CNT1-COUNT-1: this is duplicate
+CHECK-CNT1: 	    this is duplicate
+CHECK-CNT1-NEXT:    this is not duplicate
+
+; RUN: FileCheck %s --input-file %s --check-prefix=CHECK-CNT2
+CHECK-CNT2-COUNT-2: this is duplicate
+CHECK-CNT2:         this is not duplicate
+
+; RUN: FileCheck %s --input-file %s --check-prefix=CHECK-CNT3
+CHECK-CNT3-COUNT-2: this is duplicate
+CHECK-CNT3:         this is not duplicate
+CHECK-CNT3-COUNT-3: this is duplicate
+CHECK-CNT3-NOT:     {{^}}this is duplicate
+
+; RUN: FileCheck %s --input-file %s --check-prefix=CHECK-CNT4
+CHECK-CNT4-COUNT-5: this is duplicate
+CHECK-CNT4-EMPTY:
+
+Many-label:
+
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+-many-
+
+; RUN: FileCheck %s --input-file %s --check-prefix=CHECK-CNTMANY
+CHECK-CNTMANY-COUNT-2: this is duplicate
+CHECK-CNTMANY-LABEL: Many-label:
+CHECK-CNTMANY-EMPTY:
+CHECK-CNTMANY-COUNT-16: {{^}}-many-
+CHECK-CNTMANY-EMPTY:
+
+;
+; Tests on mismatches:
+;
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-MIS1 2>&1 | FileCheck %s --check-prefix=MISCOUNT1
+CHECK-MIS1-COUNT-3: this is duplicate
+CHECK-MIS1: {{^}}this is not duplicate
+MISCOUNT1: [[@LINE-1]]:13: error: CHECK-MIS1: expected string not found in input
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-MIS2 2>&1 | FileCheck %s --check-prefix=MISCOUNT2
+CHECK-MIS2-COUNT-10: {{^this is duplicate}}
+CHECK-MIS2: {{^}}this is not duplicate
+MISCOUNT2: [[@LINE-2]]:22: error: CHECK-MIS2-COUNT: expected string not found in input
+
+; RUN: not FileCheck %s --input-file %s --check-prefix=CHECK-MIS3 2>&1 | FileCheck %s --check-prefix=MISCOUNT3
+CHECK-MIS3-COUNT-5: this is duplicate
+CHECK-MIS3-EMPTY:
+CHECK-MIS3-LABEL: Many-label:
+CHECK-MIS3-EMPTY:
+CHECK-MIS3-COUNT-160: {{^}}-many-
+CHECK-MIS3-EMPTY:
+MISCOUNT3: [[@LINE-2]]:23: error: CHECK-MIS3-COUNT: expected string not found in input (17 out of 160)




More information about the llvm-commits mailing list