<div dir="ltr">Hey there - a bunch of these commit messages came through as N/7, all otherwise containing an identical description. Could you reply to the commit emails with specifics about what was changed in each commit - it'd be helpful for future archaeology (ideally the specific patch descriptions would be in the specific commits, but having the info on the mailing list at least will help some folks).</div><br><div class="gmail_quote"><div dir="ltr">On Mon, Dec 17, 2018 at 4:04 PM Joel E. Denny via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: jdenny<br>
Date: Mon Dec 17 16:01:39 2018<br>
New Revision: 349418<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=349418&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=349418&view=rev</a><br>
Log:<br>
[FileCheck] Annotate input dump (1/7)<br>
<br>
Extend FileCheck to dump its input annotated with FileCheck's<br>
diagnostics: errors, good matches if -v, and additional information if<br>
-vv.  The goal is to make it easier to visualize FileCheck's matching<br>
behavior when debugging.<br>
<br>
Each patch in this series implements input annotations for a<br>
particular category of FileCheck diagnostics.  While the first few<br>
patches alone are somewhat useful, the annotations become much more<br>
useful as later patches implement annotations for -v and -vv<br>
diagnostics, which show the matching behavior leading up to the error.<br>
<br>
This first patch implements boilerplate plus input annotations for<br>
error diagnostics reporting that no matches were found for a<br>
directive.  These annotations mark the search ranges of the failed<br>
directives.  Instead of using the usual `^~~`, which is used by later<br>
patches for good matches, these annotations use `X~~` so that this<br>
category of errors is visually distinct.<br>
<br>
For example:<br>
<br>
```<br>
$ FileCheck -dump-input=help<br>
The following description was requested by -dump-input=help to<br>
explain the input annotations printed by -dump-input=always and<br>
-dump-input=fail:<br>
<br>
  - L:     labels line number L of the input file<br>
  - T:L    labels the match result for a pattern of type T from line L of<br>
           the check file<br>
  - X~~    marks search range when no match is found<br>
  - colors error<br>
<br>
If you are not seeing color above or in input dumps, try: -color<br>
<br>
$ FileCheck -v -dump-input=always check1 < input1 |& sed -n '/^Input file/,$p'<br>
Input file: <stdin><br>
Check file: check1<br>
<br>
-dump-input=help describes the format of the following dump.<br>
<br>
Full input was:<br>
<<<<<<<br>
        1: ; abc def<br>
        2: ; ghI jkl<br>
next:3     X~~~~~~~~ error: no match found<br>
>>>>>><br>
<br>
$ cat check1<br>
CHECK: abc<br>
CHECK-SAME: def<br>
CHECK-NEXT: ghi<br>
CHECK-SAME: jkl<br>
<br>
$ cat input1<br>
; abc def<br>
; ghI jkl<br>
```<br>
<br>
Some additional details related to the boilerplate:<br>
<br>
* Enabling: The annotated input dump is enabled by `-dump-input`,<br>
  which can also be set via the `FILECHECK_OPTS` environment variable.<br>
  Accepted values are `help`, `always`, `fail`, or `never`.  As shown<br>
  above, `help` describes the format of the dump.  `always` is helpful<br>
  when you want to investigate a successful FileCheck run, perhaps for<br>
  an unexpected pass. `-dump-input-on-failure` and<br>
  `FILECHECK_DUMP_INPUT_ON_FAILURE` remain as a deprecated alias for<br>
  `-dump-input=fail`.<br>
<br>
* Diagnostics: The usual diagnostics are not suppressed in this mode<br>
  and are printed first.  For brevity in the example above, I've<br>
  omitted them using a sed command.  Sometimes they're perfectly<br>
  sufficient, and then they make debugging quicker than if you were<br>
  forced to hunt through a dump of long input looking for the error.<br>
  If you think they'll get in the way sometimes, keep in mind that<br>
  it's pretty easy to grep for the start of the input dump, which is<br>
  `<<<`.<br>
<br>
* Colored Annotations: The annotated input is colored if colors are<br>
  enabled (enabling colors can be forced using -color).  For example,<br>
  errors are red.  However, as in the above example, colors are not<br>
  vital to reading the annotations.<br>
<br>
I don't know how to test color in the output, so any hints here would<br>
be appreciated.<br>
<br>
Reviewed By: george.karpenkov, zturner, probinson<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D52999" rel="noreferrer" target="_blank">https://reviews.llvm.org/D52999</a><br>
<br>
Added:<br>
    llvm/trunk/test/FileCheck/dump-input-annotations.txt<br>
    llvm/trunk/test/FileCheck/dump-input-enable.txt<br>
    llvm/trunk/test/FileCheck/no-check-file.txt<br>
Removed:<br>
    llvm/trunk/test/FileCheck/verbose_mode.txt<br>
Modified:<br>
    llvm/trunk/docs/CommandGuide/FileCheck.rst<br>
    llvm/trunk/include/llvm/Support/FileCheck.h<br>
    llvm/trunk/lib/Support/FileCheck.cpp<br>
    llvm/trunk/utils/FileCheck/FileCheck.cpp<br>
<br>
Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=349418&r1=349417&r2=349418&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=349418&r1=349417&r2=349418&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)<br>
+++ llvm/trunk/docs/CommandGuide/FileCheck.rst Mon Dec 17 16:01:39 2018<br>
@@ -80,9 +80,16 @@ and from the command line.<br>
   -verify``. With this option FileCheck will verify that input does not contain<br>
   warnings not covered by any ``CHECK:`` patterns.<br>
<br>
+.. option:: --dump-input <mode><br>
+<br>
+  Dump input to stderr, adding annotations representing currently enabled<br>
+  diagnostics.  Do this either 'always', on 'fail', or 'never'.  Specify 'help'<br>
+  to explain the dump format and quit.<br>
+<br>
 .. option:: --dump-input-on-failure<br>
<br>
-  When the check fails, dump all of the original input.<br>
+  When the check fails, dump all of the original input.  This option is<br>
+  deprecated in favor of `--dump-input=fail`.<br>
<br>
 .. option:: --enable-var-scope<br>
<br>
<br>
Modified: llvm/trunk/include/llvm/Support/FileCheck.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=349418&r1=349417&r2=349418&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=349418&r1=349417&r2=349418&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/FileCheck.h (original)<br>
+++ llvm/trunk/include/llvm/Support/FileCheck.h Mon Dec 17 16:01:39 2018<br>
@@ -82,6 +82,8 @@ public:<br>
 };<br>
 }<br>
<br>
+struct FileCheckDiag;<br>
+<br>
 class FileCheckPattern {<br>
   SMLoc PatternLoc;<br>
<br>
@@ -146,6 +148,28 @@ private:<br>
 };<br>
<br>
 //===----------------------------------------------------------------------===//<br>
+/// Summary of a FileCheck diagnostic.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+struct FileCheckDiag {<br>
+  /// What is the FileCheck directive for this diagnostic?<br>
+  Check::FileCheckType CheckTy;<br>
+  /// Where is the FileCheck directive for this diagnostic?<br>
+  unsigned CheckLine, CheckCol;<br>
+  /// What kind of match result does this diagnostic describe?<br>
+  enum MatchType {<br>
+    // TODO: More members will appear with later patches in this series.<br>
+    /// Indicates no match for an expected pattern.<br>
+    MatchNoneButExpected,<br>
+    MatchTypeCount,<br>
+  } MatchTy;<br>
+  /// The search range.<br>
+  unsigned InputStartLine, InputStartCol, InputEndLine, InputEndCol;<br>
+  FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,<br>
+                SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);<br>
+};<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
 // Check Strings.<br>
 //===----------------------------------------------------------------------===//<br>
<br>
@@ -169,7 +193,7 @@ struct FileCheckString {<br>
<br>
   size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,<br>
                size_t &MatchLen, StringMap<StringRef> &VariableTable,<br>
-               FileCheckRequest &Req) const;<br>
+               FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const;<br>
<br>
   bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;<br>
   bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;<br>
@@ -180,7 +204,8 @@ struct FileCheckString {<br>
   size_t CheckDag(const SourceMgr &SM, StringRef Buffer,<br>
                   std::vector<const FileCheckPattern *> &NotStrings,<br>
                   StringMap<StringRef> &VariableTable,<br>
-                  const FileCheckRequest &Req) const;<br>
+                  const FileCheckRequest &Req,<br>
+                  std::vector<FileCheckDiag> *Diags) const;<br>
 };<br>
<br>
 /// FileCheck class takes the request and exposes various methods that<br>
@@ -217,7 +242,8 @@ public:<br>
   ///<br>
   /// Returns false if the input fails to satisfy the checks.<br>
   bool CheckInput(SourceMgr &SM, StringRef Buffer,<br>
-                  ArrayRef<FileCheckString> CheckStrings);<br>
+                  ArrayRef<FileCheckString> CheckStrings,<br>
+                  std::vector<FileCheckDiag> *Diags = nullptr);<br>
 };<br>
 } // namespace llvm<br>
 #endif<br>
<br>
Modified: llvm/trunk/lib/Support/FileCheck.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=349418&r1=349417&r2=349418&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=349418&r1=349417&r2=349418&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Support/FileCheck.cpp (original)<br>
+++ llvm/trunk/lib/Support/FileCheck.cpp Mon Dec 17 16:01:39 2018<br>
@@ -412,6 +412,21 @@ void FileCheckPattern::PrintVariableUses<br>
   }<br>
 }<br>
<br>
+static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,<br>
+                                  const SourceMgr &SM, SMLoc Loc,<br>
+                                  Check::FileCheckType CheckTy,<br>
+                                  StringRef Buffer, size_t Pos, size_t Len,<br>
+                                  std::vector<FileCheckDiag> *Diags) {<br>
+  SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);<br>
+  SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);<br>
+  SMRange Range(Start, End);<br>
+  // TODO: The second condition will disappear when we extend this to handle<br>
+  // more match types.<br>
+  if (Diags && MatchTy != FileCheckDiag::MatchTypeCount)<br>
+    Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);<br>
+  return Range;<br>
+}<br>
+<br>
 void FileCheckPattern::PrintFuzzyMatch(<br>
     const SourceMgr &SM, StringRef Buffer,<br>
     const StringMap<StringRef> &VariableTable) const {<br>
@@ -531,6 +546,22 @@ llvm::FileCheck::CanonicalizeFile(Memory<br>
   return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);<br>
 }<br>
<br>
+FileCheckDiag::FileCheckDiag(const SourceMgr &SM,<br>
+                             const Check::FileCheckType &CheckTy,<br>
+                             SMLoc CheckLoc, MatchType MatchTy,<br>
+                             SMRange InputRange)<br>
+    : CheckTy(CheckTy), MatchTy(MatchTy) {<br>
+  auto Start = SM.getLineAndColumn(InputRange.Start);<br>
+  auto End = SM.getLineAndColumn(InputRange.End);<br>
+  InputStartLine = Start.first;<br>
+  InputStartCol = Start.second;<br>
+  InputEndLine = End.first;<br>
+  InputEndCol = End.second;<br>
+  Start = SM.getLineAndColumn(CheckLoc);<br>
+  CheckLine = Start.first;<br>
+  CheckCol = Start.second;<br>
+}<br>
+<br>
 static bool IsPartOfWord(char c) {<br>
   return (isalnum(c) || c == '-' || c == '_');<br>
 }<br>
@@ -897,7 +928,8 @@ static void PrintNoMatch(bool ExpectedMa<br>
                          StringRef Prefix, SMLoc Loc,<br>
                          const FileCheckPattern &Pat, int MatchedCount,<br>
                          StringRef Buffer, StringMap<StringRef> &VariableTable,<br>
-                         bool VerboseVerbose) {<br>
+                         bool VerboseVerbose,<br>
+                         std::vector<FileCheckDiag> *Diags) {<br>
   if (!ExpectedMatch && !VerboseVerbose)<br>
     return;<br>
<br>
@@ -915,9 +947,11 @@ static void PrintNoMatch(bool ExpectedMa<br>
   // Print the "scanning from here" line.  If the current position is at the<br>
   // end of a line, advance to the start of the next line.<br>
   Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));<br>
-<br>
-  SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,<br>
-                  "scanning from here");<br>
+  SMRange SearchRange = ProcessMatchResult(<br>
+      ExpectedMatch ? FileCheckDiag::MatchNoneButExpected<br>
+                    : FileCheckDiag::MatchTypeCount,<br>
+      SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);<br>
+  SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");<br>
<br>
   // Allow the pattern to print additional information if desired.<br>
   Pat.PrintVariableUses(SM, Buffer, VariableTable);<br>
@@ -928,9 +962,10 @@ static void PrintNoMatch(bool ExpectedMa<br>
 static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,<br>
                          const FileCheckString &CheckStr, int MatchedCount,<br>
                          StringRef Buffer, StringMap<StringRef> &VariableTable,<br>
-                         bool VerboseVerbose) {<br>
+                         bool VerboseVerbose,<br>
+                         std::vector<FileCheckDiag> *Diags) {<br>
   PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,<br>
-               MatchedCount, Buffer, VariableTable, VerboseVerbose);<br>
+               MatchedCount, Buffer, VariableTable, VerboseVerbose, Diags);<br>
 }<br>
<br>
 /// Count the number of newlines in the specified range.<br>
@@ -958,9 +993,10 @@ static unsigned CountNumNewlinesBetween(<br>
<br>
 /// Match check string and its "not strings" and/or "dag strings".<br>
 size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,<br>
-                          bool IsLabelScanMode, size_t &MatchLen,<br>
-                          StringMap<StringRef> &VariableTable,<br>
-                          FileCheckRequest &Req) const {<br>
+                              bool IsLabelScanMode, size_t &MatchLen,<br>
+                              StringMap<StringRef> &VariableTable,<br>
+                              FileCheckRequest &Req,<br>
+                              std::vector<FileCheckDiag> *Diags) const {<br>
   size_t LastPos = 0;<br>
   std::vector<const FileCheckPattern *> NotStrings;<br>
<br>
@@ -970,7 +1006,7 @@ size_t FileCheckString::Check(const Sour<br>
   // over the block again (including the last CHECK-LABEL) in normal mode.<br>
   if (!IsLabelScanMode) {<br>
     // Match "dag strings" (with mixed "not strings" if any).<br>
-    LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable, Req);<br>
+    LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable, Req, Diags);<br>
     if (LastPos == StringRef::npos)<br>
       return StringRef::npos;<br>
   }<br>
@@ -992,7 +1028,7 @@ size_t FileCheckString::Check(const Sour<br>
     // report<br>
     if (MatchPos == StringRef::npos) {<br>
       PrintNoMatch(true, SM, *this, i, MatchBuffer, VariableTable,<br>
-                   Req.VerboseVerbose);<br>
+                   Req.VerboseVerbose, Diags);<br>
       return StringRef::npos;<br>
     }<br>
     PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos,<br>
@@ -1116,7 +1152,7 @@ bool FileCheckString::CheckNot(const Sou<br>
<br>
     if (Pos == StringRef::npos) {<br>
       PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,<br>
-                   VariableTable, Req.VerboseVerbose);<br>
+                   VariableTable, Req.VerboseVerbose, nullptr);<br>
       continue;<br>
     }<br>
<br>
@@ -1130,10 +1166,12 @@ bool FileCheckString::CheckNot(const Sou<br>
 }<br>
<br>
 /// Match "dag strings" and their mixed "not strings".<br>
-size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,<br>
-                             std::vector<const FileCheckPattern *> &NotStrings,<br>
-                             StringMap<StringRef> &VariableTable,<br>
-                             const FileCheckRequest &Req) const {<br>
+size_t<br>
+FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,<br>
+                          std::vector<const FileCheckPattern *> &NotStrings,<br>
+                          StringMap<StringRef> &VariableTable,<br>
+                          const FileCheckRequest &Req,<br>
+                          std::vector<FileCheckDiag> *Diags) const {<br>
   if (DagNotStrings.empty())<br>
     return 0;<br>
<br>
@@ -1177,7 +1215,7 @@ size_t FileCheckString::CheckDag(const S<br>
       // that group of CHECK-DAGs fails immediately.<br>
       if (MatchPosBuf == StringRef::npos) {<br>
         PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,<br>
-                     VariableTable, Req.VerboseVerbose);<br>
+                     VariableTable, Req.VerboseVerbose, Diags);<br>
         return StringRef::npos;<br>
       }<br>
       // Re-calc it as the offset relative to the start of the original string.<br>
@@ -1318,7 +1356,8 @@ static void ClearLocalVars(StringMap<Str<br>
 ///<br>
 /// Returns false if the input fails to satisfy the checks.<br>
 bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,<br>
-                ArrayRef<FileCheckString> CheckStrings) {<br>
+                                 ArrayRef<FileCheckString> CheckStrings,<br>
+                                 std::vector<FileCheckDiag> *Diags) {<br>
   bool ChecksFailed = false;<br>
<br>
   /// VariableTable - This holds all the current filecheck variables.<br>
@@ -1341,9 +1380,8 @@ bool llvm::FileCheck::CheckInput(SourceM<br>
<br>
       // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG<br>
       size_t MatchLabelLen = 0;<br>
-      size_t MatchLabelPos =<br>
-          CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, VariableTable,<br>
-                              Req);<br>
+      size_t MatchLabelPos = CheckLabelStr.Check(<br>
+          SM, Buffer, true, MatchLabelLen, VariableTable, Req, Diags);<br>
       if (MatchLabelPos == StringRef::npos)<br>
         // Immediately bail of CHECK-LABEL fails, nothing else we can do.<br>
         return false;<br>
@@ -1362,8 +1400,8 @@ bool llvm::FileCheck::CheckInput(SourceM<br>
       // Check each string within the scanned region, including a second check<br>
       // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)<br>
       size_t MatchLen = 0;<br>
-      size_t MatchPos =<br>
-          CheckStr.Check(SM, CheckRegion, false, MatchLen, VariableTable, Req);<br>
+      size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen,<br>
+                                       VariableTable, Req, Diags);<br>
<br>
       if (MatchPos == StringRef::npos) {<br>
         ChecksFailed = true;<br>
<br>
Added: llvm/trunk/test/FileCheck/dump-input-annotations.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/dump-input-annotations.txt?rev=349418&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/dump-input-annotations.txt?rev=349418&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/dump-input-annotations.txt (added)<br>
+++ llvm/trunk/test/FileCheck/dump-input-annotations.txt Mon Dec 17 16:01:39 2018<br>
@@ -0,0 +1,241 @@<br>
+;--------------------------------------------------<br>
+; Use -strict-whitespace to check marker alignment here.<br>
+; (Also check multiline marker where start/end columns vary across lines.)<br>
+;<br>
+; In the remaining checks, don't use -strict-whitespace and thus check just the<br>
+; presence, order, and lengths of markers.  That way, if we ever change padding<br>
+; within line labels, we don't have to adjust so many tests.<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: echo 'hello world' > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'goodbye' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'world' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK: hello' > %t.chk<br>
+; RUN: echo 'CHECK: universe' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -strict-whitespace -match-full-lines -check-prefix=ALIGN %s<br>
+<br>
+; ALIGN:Full input was:<br>
+; ALIGN-NEXT:<<<<<<<br>
+; ALIGN-NEXT:         1: hello world<br>
+; ALIGN-NEXT:check:2           X~~~~<br>
+; ALIGN-NEXT:         2: goodbye<br>
+; ALIGN-NEXT:check:2     ~~~~~~~<br>
+; ALIGN-NEXT:         3: world<br>
+; ALIGN-NEXT:check:2     ~~~~~ error: no match found<br>
+; ALIGN-NEXT:>>>>>><br>
+; ALIGN-NOT:{{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK (also: multi-line search range)<br>
+;--------------------------------------------------<br>
+<br>
+; Good match and no match.<br>
+<br>
+; RUN: echo 'hello'   > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'again'   >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'whirled' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK: hello' > %t.chk<br>
+; RUN: echo 'CHECK: world' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefix=CHK<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=CHK,CHK-V<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=CHK,CHK-V<br>
+<br>
+; CHK:        <<<<<<<br>
+; CHK-NEXT:            1: hello<br>
+; CHK-NEXT:            2: again<br>
+; CHK-NEXT:   check:2     X~~~~<br>
+; CHK-NEXT:            3: whirled<br>
+; CHK-NEXT:   check:2     ~~~~~~~ error: no match found<br>
+; CHK-NEXT:   >>>>>><br>
+; CHK-NOT:    {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK-COUNT-<num><br>
+;--------------------------------------------------<br>
+<br>
+; Good match and no match.<br>
+<br>
+; RUN: echo 'pete'   > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'repete' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'repeat' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK-COUNT-3: pete' > %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefix=CNT<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-V<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-V<br>
+<br>
+; CNT:        <<<<<<<br>
+; CNT-NEXT:            1: pete<br>
+; CNT-NEXT:            2: repete<br>
+; CNT-NEXT:            3: repeat<br>
+; CNT-NEXT:   count:1     X~~~~~ error: no match found<br>
+; CNT-NEXT:   >>>>>><br>
+; CNT-NOT:    {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK-NEXT (also: EOF search-range)<br>
+;--------------------------------------------------<br>
+<br>
+; Good match and no match.<br>
+<br>
+; RUN: echo 'hello' > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'again' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK: hello' > %t.chk<br>
+; RUN: echo 'CHECK-NEXT: again' >> %t.chk<br>
+; RUN: echo 'CHECK-NEXT: world' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefix=NXT<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=NXT,NXT-V<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=NXT,NXT-V,NXT-VV<br>
+<br>
+; NXT:        <<<<<<<br>
+; NXT-NEXT:           1: hello<br>
+; NXT-NEXT:           2: again<br>
+; NXT-NEXT:           3:<br>
+; NXT-NEXT:   next:3     X error: no match found<br>
+; NXT-NEXT:   >>>>>><br>
+; NXT-NOT:    {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK-SAME (also: single-char search range)<br>
+;--------------------------------------------------<br>
+<br>
+; Good match and no match.<br>
+<br>
+; RUN: echo 'hello world!' > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK: hello' > %t.chk<br>
+; RUN: echo 'CHECK-SAME: world' >> %t.chk<br>
+; RUN: echo 'CHECK-SAME: again' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefix=SAM<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=SAM,SAM-V<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=SAM,SAM-V,SAM-VV<br>
+<br>
+; SAM:        <<<<<<<br>
+; SAM-NEXT:           1: hello world!<br>
+; SAM-NEXT:   same:3                X error: no match found<br>
+; SAM-NEXT:   >>>>>><br>
+; SAM-NOT:    {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK-EMPTY (also: search range ends at label)<br>
+;--------------------------------------------------<br>
+<br>
+; Good match and no match.<br>
+;<br>
+; CHECK-EMPTY always seems to match an empty line at EOF (illegally when it's<br>
+; not the next line) unless either (1) the last line is non-empty and has no<br>
+; newline or (2) there's a CHECK-LABEL to end the search range before EOF.  We<br>
+; choose scenario 2 to check the case of no match.<br>
+<br>
+; RUN: echo 'hello' > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo '' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'world' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'label' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK: hello' > %t.chk<br>
+; RUN: echo 'CHECK-EMPTY:' >> %t.chk<br>
+; RUN: echo 'CHECK-EMPTY:' >> %t.chk<br>
+; RUN: echo 'CHECK-LABEL: label' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefix=EMP<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=EMP,EMP-V<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=EMP,EMP-V,EMP-VV<br>
+<br>
+; EMP:        <<<<<<<br>
+; EMP-NEXT:            1: hello<br>
+; EMP-NEXT:            2:<br>
+; EMP-NEXT:            3: world<br>
+; EMP-NEXT:   empty:3     X~~~~<br>
+; EMP-NEXT:            4: label<br>
+; EMP-NEXT:   empty:3     ~~~~~ error: no match found<br>
+; EMP-NEXT:   >>>>>><br>
+; EMP-NOT:    {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK-DAG<br>
+;--------------------------------------------------<br>
+<br>
+; Good match, discarded match plus good match, and no match.<br>
+<br>
+; RUN: echo 'abc' > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'def' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'abc' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK-DAG: def' > %t.chk<br>
+; RUN: echo 'CHECK-DAG: abc' >> %t.chk<br>
+; RUN: echo 'CHECK-DAG: abc' >> %t.chk<br>
+; RUN: echo 'CHECK-DAG: def' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG<br>
+<br>
+; DAG:         <<<<<<<br>
+; DAG-NEXT:           1: abc<br>
+; DAG-NEXT:           2: def<br>
+; DAG-NEXT:           3: abc<br>
+; DAG-NEXT:    dag:4     X~~ error: no match found<br>
+; DAG-NEXT:    >>>>>><br>
+; DAG-NOT:     {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; CHECK-LABEL<br>
+;--------------------------------------------------<br>
+<br>
+; Good match and no match.<br>
+<br>
+; RUN: echo 'lab0' > %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'foo' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'lab1' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+; RUN: echo 'bar' >> %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a><br>
+<br>
+; RUN: echo 'CHECK-LABEL: lab0' > %t.chk<br>
+; RUN: echo 'CHECK: foo' >> %t.chk<br>
+; RUN: echo 'CHECK-LABEL: lab2' >> %t.chk<br>
+<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=LAB<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -v 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=LAB,LAB-V<br>
+; RUN: not FileCheck -dump-input=always -input-file %<a href="http://t.in" rel="noreferrer" target="_blank">t.in</a> %t.chk -vv 2>&1 \<br>
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=LAB,LAB-V,LAB-VV<br>
+<br>
+; LAB:         <<<<<<<br>
+; LAB-NEXT:             1: lab0<br>
+; LAB-NEXT:             2: foo<br>
+; LAB-NEXT:    label:3     X~~<br>
+; LAB-NEXT:             3: lab1<br>
+; LAB-NEXT:    label:3     ~~~~<br>
+; LAB-NEXT:             4: bar<br>
+; LAB-NEXT:    label:3     ~~~ error: no match found<br>
+; LAB-NEXT:    >>>>>><br>
+; LAB-NOT:     {{.}}<br>
+<br>
+<br>
<br>
Added: llvm/trunk/test/FileCheck/dump-input-enable.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/dump-input-enable.txt?rev=349418&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/dump-input-enable.txt?rev=349418&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/dump-input-enable.txt (added)<br>
+++ llvm/trunk/test/FileCheck/dump-input-enable.txt Mon Dec 17 16:01:39 2018<br>
@@ -0,0 +1,126 @@<br>
+; RUN: echo ciao > %t.good<br>
+; RUN: echo world >> %t.good<br>
+<br>
+; RUN: echo hello > %t.err<br>
+; RUN: echo world >> %t.err<br>
+<br>
+; RUN: echo 'CHECK: ciao' > %t.check<br>
+; RUN: echo 'CHECK-NEXT: world' >> %t.check<br>
+<br>
+;--------------------------------------------------<br>
+; unknown value<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: not FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines -dump-input=foobar 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL<br>
+<br>
+; No positional arg.<br>
+; RUN: not FileCheck -dump-input=foobar 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL<br>
+<br>
+BADVAL: FileCheck: for the -dump-input option: Cannot find option named 'foobar'!<br>
+<br>
+;--------------------------------------------------<br>
+; help<br>
+;--------------------------------------------------<br>
+<br>
+; Appended to normal command line.<br>
+; RUN: FileCheck -input-file %t.err -color %t.check -dump-input=help \<br>
+; RUN: | FileCheck %s -check-prefix=HELP<br>
+<br>
+; No positional arg.<br>
+; RUN: FileCheck -dump-input=help | FileCheck %s -check-prefix=HELP<br>
+<br>
+HELP-NOT: {{.}}<br>
+HELP: The following description was requested by -dump-input=help<br>
+HELP: try{{.*}}-color<br>
+HELP-NOT: {{.}}<br>
+<br>
+;--------------------------------------------------<br>
+; never<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:           -match-full-lines -dump-input=never 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP -allow-empty<br>
+<br>
+; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines -dump-input=never 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP<br>
+<br>
+;--------------------------------------------------<br>
+; default: never<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:           -match-full-lines 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP -allow-empty<br>
+<br>
+; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP<br>
+<br>
+;--------------------------------------------------<br>
+; fail<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:           -match-full-lines -dump-input=fail 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP -allow-empty<br>
+<br>
+; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines -dump-input=fail 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR<br>
+<br>
+;--------------------------------------------------<br>
+; -dump-input-on-failure<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:           -match-full-lines -dump-input-on-failure 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP -allow-empty<br>
+<br>
+; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines -dump-input-on-failure 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR<br>
+<br>
+; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 \<br>
+; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:           -match-full-lines 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP -allow-empty<br>
+<br>
+; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 \<br>
+; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR<br>
+<br>
+;--------------------------------------------------<br>
+; always<br>
+;--------------------------------------------------<br>
+<br>
+; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \<br>
+; RUN:           -match-full-lines -dump-input=always -v 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-GOOD<br>
+<br>
+; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \<br>
+; RUN:               -match-full-lines -dump-input=always 2>&1 \<br>
+; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR<br>
+<br>
+; END.<br>
+<br>
+; CHECK-GOOD: Full input was:<br>
+; CHECK-GOOD-NEXT: <<<<<<<br>
+; CHECK-GOOD-NEXT:          1: ciao<br>
+; CHECK-GOOD-NEXT:          2: world<br>
+; CHECK-GOOD-NEXT: >>>>>><br>
+<br>
+; CHECK-ERR: Full input was:<br>
+; CHECK-ERR-NEXT: <<<<<<<br>
+; CHECK-ERR-NEXT:          1: hello<br>
+; CHECK-ERR-NEXT: check:1     X~~~~<br>
+; CHECK-ERR-NEXT:          2: world<br>
+; CHECK-ERR-NEXT: check:1     ~~~~~ error: no match found<br>
+; CHECK-ERR-NEXT: >>>>>><br>
+<br>
+; CHECK-NODUMP-NOT: <<<<<<<br>
<br>
Added: llvm/trunk/test/FileCheck/no-check-file.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/no-check-file.txt?rev=349418&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/no-check-file.txt?rev=349418&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/no-check-file.txt (added)<br>
+++ llvm/trunk/test/FileCheck/no-check-file.txt Mon Dec 17 16:01:39 2018<br>
@@ -0,0 +1,3 @@<br>
+; RUN: not FileCheck 2>&1 | FileCheck %s<br>
+<br>
+CHECK: <check-file> not specified<br>
<br>
Removed: llvm/trunk/test/FileCheck/verbose_mode.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/verbose_mode.txt?rev=349417&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/verbose_mode.txt?rev=349417&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/FileCheck/verbose_mode.txt (original)<br>
+++ llvm/trunk/test/FileCheck/verbose_mode.txt (removed)<br>
@@ -1,17 +0,0 @@<br>
-; RUN: not FileCheck -input-file %s %s --check-prefix=CHECK1 --match-full-lines --dump-input-on-failure 2>&1 | FileCheck %s --check-prefix=CHECKERROR --match-full-lines<br>
-; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 not FileCheck -input-file %s %s --check-prefix=CHECK1 --match-full-lines 2>&1 |  FileCheck %s --check-prefix=CHECKERROR --match-full-lines<br>
-; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 not FileCheck -input-file %s %s --check-prefix=CHECK1 --match-full-lines --dump-input-on-failure=0 2>&1 |  FileCheck %s --check-prefix=CHECKERRORNOVERBOSE --match-full-lines<br>
-<br>
-hello<br>
-world<br>
-<br>
-; CHECK1: ciao<br>
-; CHECK1-NEXT: world<br>
-<br>
-; CHECKERROR: Full input was:<br>
-; CHECKERROR-NEXT: <<<<<<<br>
-; CHECKERROR: hello<br>
-; CHECKERROR: world<br>
-; CHECKERROR: >>>>>><br>
-<br>
-; CHECKERRORNOVERBOSE-NOT: <<<<<<<br>
<br>
Modified: llvm/trunk/utils/FileCheck/FileCheck.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=349418&r1=349417&r2=349418&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=349418&r1=349417&r2=349418&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/utils/FileCheck/FileCheck.cpp (original)<br>
+++ llvm/trunk/utils/FileCheck/FileCheck.cpp Mon Dec 17 16:01:39 2018<br>
@@ -19,12 +19,13 @@<br>
 #include "llvm/Support/CommandLine.h"<br>
 #include "llvm/Support/InitLLVM.h"<br>
 #include "llvm/Support/Process.h"<br>
+#include "llvm/Support/WithColor.h"<br>
 #include "llvm/Support/raw_ostream.h"<br>
 #include "llvm/Support/FileCheck.h"<br>
 using namespace llvm;<br>
<br>
 static cl::opt<std::string><br>
-    CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required);<br>
+    CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);<br>
<br>
 static cl::opt<std::string><br>
     InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),<br>
@@ -91,7 +92,27 @@ static cl::opt<bool> DumpInputOnFailure(<br>
     "dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),<br>
     cl::desc("Dump original input to stderr before failing.\n"<br>
              "The value can be also controlled using\n"<br>
-             "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"));<br>
+             "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"<br>
+             "This option is deprecated in favor of -dump-input=fail.\n"));<br>
+<br>
+enum DumpInputValue {<br>
+  DumpInputDefault,<br>
+  DumpInputHelp,<br>
+  DumpInputNever,<br>
+  DumpInputFail,<br>
+  DumpInputAlways<br>
+};<br>
+<br>
+static cl::opt<DumpInputValue> DumpInput(<br>
+    "dump-input", cl::init(DumpInputDefault),<br>
+    cl::desc("Dump input to stderr, adding annotations representing\n"<br>
+             " currently enabled diagnostics\n"),<br>
+    cl::value_desc("mode"),<br>
+    cl::values(clEnumValN(DumpInputHelp, "help",<br>
+                          "Explain dump format and quit"),<br>
+               clEnumValN(DumpInputNever, "never", "Never dump input"),<br>
+               clEnumValN(DumpInputFail, "fail", "Dump input on failure"),<br>
+               clEnumValN(DumpInputAlways, "always", "Always dump input")));<br>
<br>
 typedef cl::list<std::string>::const_iterator prefix_iterator;<br>
<br>
@@ -108,6 +129,269 @@ static void DumpCommandLine(int argc, ch<br>
   errs() << "\n";<br>
 }<br>
<br>
+struct MarkerStyle {<br>
+  /// The starting char (before tildes) for marking the line.<br>
+  char Lead;<br>
+  /// What color to use for this annotation.<br>
+  raw_ostream::Colors Color;<br>
+  /// A note to follow the marker, or empty string if none.<br>
+  std::string Note;<br>
+  MarkerStyle() {}<br>
+  MarkerStyle(char Lead, raw_ostream::Colors Color, const std::string &Note)<br>
+      : Lead(Lead), Color(Color), Note(Note) {}<br>
+};<br>
+<br>
+static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {<br>
+  switch (MatchTy) {<br>
+  case FileCheckDiag::MatchNoneButExpected:<br>
+    return MarkerStyle('X', raw_ostream::RED, "error: no match found");<br>
+  case FileCheckDiag::MatchTypeCount:<br>
+    llvm_unreachable_internal("unexpected match type");<br>
+  }<br>
+  llvm_unreachable_internal("unexpected match type");<br>
+}<br>
+<br>
+static void DumpInputAnnotationHelp(raw_ostream &OS) {<br>
+  OS << "The following description was requested by -dump-input=help to\n"<br>
+     << "explain the input annotations printed by -dump-input=always and\n"<br>
+     << "-dump-input=fail:\n\n";<br>
+<br>
+  // Labels for input lines.<br>
+  OS << "  - ";<br>
+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";<br>
+  OS << "     labels line number L of the input file\n";<br>
+<br>
+  // Labels for annotation lines.<br>
+  OS << "  - ";<br>
+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";<br>
+  OS << "    labels the match result for a pattern of type T from "<br>
+     << "line L of\n"<br>
+     << "           the check file\n";<br>
+<br>
+  // Markers on annotation lines.<br>
+  OS << "  - ";<br>
+  WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";<br>
+  OS << "    marks search range when no match is found\n";<br>
+<br>
+  // Colors.<br>
+  OS << "  - colors ";<br>
+  WithColor(OS, raw_ostream::RED, true) << "error";<br>
+  OS << "\n\n"<br>
+     << "If you are not seeing color above or in input dumps, try: -color\n";<br>
+}<br>
+<br>
+/// An annotation for a single input line.<br>
+struct InputAnnotation {<br>
+  /// The check file line (one-origin indexing) where the directive that<br>
+  /// produced this annotation is located.<br>
+  unsigned CheckLine;<br>
+  /// The label for this annotation.<br>
+  std::string Label;<br>
+  /// What input line (one-origin indexing) this annotation marks.  This might<br>
+  /// be different from the starting line of the original diagnostic if this is<br>
+  /// a non-initial fragment of a diagnostic that has been broken across<br>
+  /// multiple lines.<br>
+  unsigned InputLine;<br>
+  /// The column range (one-origin indexing, open end) in which to to mark the<br>
+  /// input line.  If InputEndCol is UINT_MAX, treat it as the last column<br>
+  /// before the newline.<br>
+  unsigned InputStartCol, InputEndCol;<br>
+  /// The marker to use.<br>
+  MarkerStyle Marker;<br>
+};<br>
+<br>
+/// Get an abbreviation for the check type.<br>
+std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {<br>
+  switch (Ty) {<br>
+  case Check::CheckPlain:<br>
+    if (Ty.getCount() > 1)<br>
+      return "count";<br>
+    return "check";<br>
+  case Check::CheckNext:<br>
+    return "next";<br>
+  case Check::CheckSame:<br>
+    return "same";<br>
+  case Check::CheckNot:<br>
+    return "not";<br>
+  case Check::CheckDAG:<br>
+    return "dag";<br>
+  case Check::CheckLabel:<br>
+    return "label";<br>
+  case Check::CheckEmpty:<br>
+    return "empty";<br>
+  case Check::CheckEOF:<br>
+    return "eof";<br>
+  case Check::CheckBadNot:<br>
+    return "bad-not";<br>
+  case Check::CheckBadCount:<br>
+    return "bad-count";<br>
+  case Check::CheckNone:<br>
+    llvm_unreachable("invalid FileCheckType");<br>
+  }<br>
+  llvm_unreachable("unknown FileCheckType");<br>
+}<br>
+<br>
+static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,<br>
+                                  std::vector<InputAnnotation> &Annotations,<br>
+                                  unsigned &LabelWidth) {<br>
+  // What's the widest label?<br>
+  LabelWidth = 0;<br>
+  for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;<br>
+       ++DiagItr) {<br>
+    InputAnnotation A;<br>
+<br>
+    // Build label, which uniquely identifies this check result.<br>
+    A.CheckLine = DiagItr->CheckLine;<br>
+    llvm::raw_string_ostream Label(A.Label);<br>
+    Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"<br>
+          << DiagItr->CheckLine;<br>
+    Label.flush();<br>
+    LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());<br>
+<br>
+    MarkerStyle Marker = GetMarker(DiagItr->MatchTy);<br>
+    A.Marker = Marker;<br>
+<br>
+    // Compute the mark location, and break annotation into multiple<br>
+    // annotations if it spans multiple lines.<br>
+    A.InputLine = DiagItr->InputStartLine;<br>
+    A.InputStartCol = DiagItr->InputStartCol;<br>
+    if (DiagItr->InputStartLine == DiagItr->InputEndLine) {<br>
+      // Sometimes ranges are empty in order to indicate a specific point, but<br>
+      // that would mean nothing would be marked, so adjust the range to<br>
+      // include the following character.<br>
+      A.InputEndCol =<br>
+          std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);<br>
+      Annotations.push_back(A);<br>
+    } else {<br>
+      assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&<br>
+             "expected input range not to be inverted");<br>
+      A.InputEndCol = UINT_MAX;<br>
+      A.Marker.Note = "";<br>
+      Annotations.push_back(A);<br>
+      for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;<br>
+           L <= E; ++L) {<br>
+        // If a range ends before the first column on a line, then it has no<br>
+        // characters on that line, so there's nothing to render.<br>
+        if (DiagItr->InputEndCol == 1 && L == E) {<br>
+          Annotations.back().Marker.Note = Marker.Note;<br>
+          break;<br>
+        }<br>
+        InputAnnotation B;<br>
+        B.CheckLine = A.CheckLine;<br>
+        B.Label = A.Label;<br>
+        B.InputLine = L;<br>
+        B.Marker = Marker;<br>
+        B.Marker.Lead = '~';<br>
+        B.InputStartCol = 1;<br>
+        if (L != E) {<br>
+          B.InputEndCol = UINT_MAX;<br>
+          B.Marker.Note = "";<br>
+        } else<br>
+          B.InputEndCol = DiagItr->InputEndCol;<br>
+        Annotations.push_back(B);<br>
+      }<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+static void DumpAnnotatedInput(<br>
+    raw_ostream &OS, StringRef InputFileText,<br>
+    std::vector<InputAnnotation> &Annotations, unsigned LabelWidth) {<br>
+  OS << "Full input was:\n<<<<<<\n";<br>
+<br>
+  // Sort annotations.<br>
+  //<br>
+  // First, sort in the order of input lines to make it easier to find relevant<br>
+  // annotations while iterating input lines in the implementation below.<br>
+  // FileCheck diagnostics are not always reported and recorded in the order of<br>
+  // input lines due to, for example, CHECK-DAG and CHECK-NOT.<br>
+  //<br>
+  // Second, for annotations for the same input line, sort in the order of the<br>
+  // FileCheck directive's line in the check file (where there's at most one<br>
+  // directive per line).  The rationale of this choice is that, for any input<br>
+  // line, this sort establishes a total order of annotations that, with<br>
+  // respect to match results, is consistent across multiple lines, thus<br>
+  // making match results easier to track from one line to the next when they<br>
+  // span multiple lines.<br>
+  std::sort(Annotations.begin(), Annotations.end(),<br>
+            [](const InputAnnotation &A, const InputAnnotation &B) {<br>
+              if (A.InputLine != B.InputLine)<br>
+                return A.InputLine < B.InputLine;<br>
+              return A.CheckLine < B.CheckLine;<br>
+            });<br>
+<br>
+  // Compute the width of the label column.<br>
+  const unsigned char *InputFilePtr = InputFileText.bytes_begin(),<br>
+                      *InputFileEnd = InputFileText.bytes_end();<br>
+  unsigned LineCount = InputFileText.count('\n');<br>
+  if (InputFileEnd[-1] != '\n')<br>
+    ++LineCount;<br>
+  unsigned LineNoWidth = log10(LineCount) + 1;<br>
+  // +3 below adds spaces (1) to the left of the (right-aligned) line numbers<br>
+  // on input lines and (2) to the right of the (left-aligned) labels on<br>
+  // annotation lines so that input lines and annotation lines are more<br>
+  // visually distinct.  For example, the spaces on the annotation lines ensure<br>
+  // that input line numbers and check directive line numbers never align<br>
+  // horizontally.  Those line numbers might not even be for the same file.<br>
+  // One space would be enough to achieve that, but more makes it even easier<br>
+  // to see.<br>
+  LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;<br>
+<br>
+  // Print annotated input lines.<br>
+  auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();<br>
+  for (unsigned Line = 1;<br>
+       InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;<br>
+       ++Line) {<br>
+    const unsigned char *InputFileLine = InputFilePtr;<br>
+<br>
+    // Print right-aligned line number.<br>
+    WithColor(OS, raw_ostream::BLACK, true)<br>
+        << format_decimal(Line, LabelWidth) << ": ";<br>
+<br>
+    // Print numbered line.<br>
+    bool Newline = false;<br>
+    while (InputFilePtr != InputFileEnd && !Newline) {<br>
+      if (*InputFilePtr == '\n')<br>
+        Newline = true;<br>
+      else<br>
+        OS << *InputFilePtr;<br>
+      ++InputFilePtr;<br>
+    }<br>
+    OS << '\n';<br>
+    unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;<br>
+<br>
+    // Print any annotations.<br>
+    while (AnnotationItr != AnnotationEnd &&<br>
+           AnnotationItr->InputLine == Line) {<br>
+      WithColor COS(OS, AnnotationItr->Marker.Color, true);<br>
+      // The two spaces below are where the ": " appears on input lines.<br>
+      COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";<br>
+      unsigned Col;<br>
+      for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)<br>
+        COS << ' ';<br>
+      COS << AnnotationItr->Marker.Lead;<br>
+      // If InputEndCol=UINT_MAX, stop at InputLineWidth.<br>
+      for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;<br>
+           ++Col)<br>
+        COS << '~';<br>
+      const std::string &Note = AnnotationItr->Marker.Note;<br>
+      if (!Note.empty()) {<br>
+        // Put the note at the end of the input line.  If we were to instead<br>
+        // put the note right after the marker, subsequent annotations for the<br>
+        // same input line might appear to mark this note instead of the input<br>
+        // line.<br>
+        for (; Col <= InputLineWidth; ++Col)<br>
+          COS << ' ';<br>
+        COS << ' ' << Note;<br>
+      }<br>
+      COS << '\n';<br>
+      ++AnnotationItr;<br>
+    }<br>
+  }<br>
+<br>
+  OS << ">>>>>>\n";<br>
+}<br>
+<br>
 int main(int argc, char **argv) {<br>
   // Enable use of ANSI color codes because FileCheck is using them to<br>
   // highlight text.<br>
@@ -116,6 +400,14 @@ int main(int argc, char **argv) {<br>
   InitLLVM X(argc, argv);<br>
   cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,<br>
                               "FILECHECK_OPTS");<br>
+  if (DumpInput == DumpInputHelp) {<br>
+    DumpInputAnnotationHelp(outs());<br>
+    return 0;<br>
+  }<br>
+  if (CheckFilename.empty()) {<br>
+    errs() << "<check-file> not specified\n";<br>
+    return 2;<br>
+  }<br>
<br>
   FileCheckRequest Req;<br>
   for (auto Prefix : CheckPrefixes)<br>
@@ -157,7 +449,6 @@ int main(int argc, char **argv) {<br>
     return 2;<br>
   }<br>
<br>
-<br>
   SourceMgr SM;<br>
<br>
   // Read the expected strings from the check file.<br>
@@ -204,10 +495,29 @@ int main(int argc, char **argv) {<br>
                             InputFileText, InputFile.getBufferIdentifier()),<br>
                         SMLoc());<br>
<br>
-  int ExitCode =<br>
-      FC.CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1;<br>
-  if (ExitCode == 1 && DumpInputOnFailure)<br>
-    errs() << "Full input was:\n<<<<<<\n" << InputFileText << "\n>>>>>>\n";<br>
+  if (DumpInput == DumpInputDefault)<br>
+    DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;<br>
+<br>
+  std::vector<FileCheckDiag> Diags;<br>
+  int ExitCode = FC.CheckInput(SM, InputFileText, CheckStrings,<br>
+                               DumpInput == DumpInputNever ? nullptr : &Diags)<br>
+                     ? EXIT_SUCCESS<br>
+                     : 1;<br>
+  if (DumpInput == DumpInputAlways ||<br>
+      (ExitCode == 1 && DumpInput == DumpInputFail)) {<br>
+    errs() << "\n"<br>
+           << "Input file: "<br>
+           << (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())<br>
+           << "\n"<br>
+           << "Check file: " << CheckFilename << "\n"<br>
+           << "\n"<br>
+           << "-dump-input=help describes the format of the following dump.\n"<br>
+           << "\n";<br>
+    std::vector<InputAnnotation> Annotations;<br>
+    unsigned LabelWidth;<br>
+    BuildInputAnnotations(Diags, Annotations, LabelWidth);<br>
+    DumpAnnotatedInput(errs(), InputFileText, Annotations, LabelWidth);<br>
+  }<br>
<br>
   return ExitCode;<br>
 }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>