[llvm] 77b6ddf - [FileCheck] In input dump, elide only if ellipsis is shorter

Joel E. Denny via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 10 08:04:29 PDT 2020


Author: Joel E. Denny
Date: 2020-07-10T11:02:11-04:00
New Revision: 77b6ddf1bd77da90407316345156415dc646e744

URL: https://github.com/llvm/llvm-project/commit/77b6ddf1bd77da90407316345156415dc646e744
DIFF: https://github.com/llvm/llvm-project/commit/77b6ddf1bd77da90407316345156415dc646e744.diff

LOG: [FileCheck] In input dump, elide only if ellipsis is shorter

For example, given `-dump-input-context=3 -vv`, the following now
shows more leading context for the error than requested because a
leading ellipsis would occupy the same number of lines as it would
elide:

```
<<<<<<
         1: foo6
         2: foo5
         3: foo4
         4: foo3
         5: foo2
         6: foo1
         7: hello world
check:1     ^~~~~
check:2           X~~~~ error: no match found
         8: foo1
check:2     ~~~~
         9: foo2
check:2     ~~~~
        10: foo3
check:2     ~~~~
         .
         .
         .
>>>>>>
```

Reviewed By: mehdi_amini

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

Added: 
    

Modified: 
    llvm/test/FileCheck/dump-input-context.txt
    llvm/utils/FileCheck/FileCheck.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/FileCheck/dump-input-context.txt b/llvm/test/FileCheck/dump-input-context.txt
index 6badaf88778d..2e4382ec12ed 100644
--- a/llvm/test/FileCheck/dump-input-context.txt
+++ b/llvm/test/FileCheck/dump-input-context.txt
@@ -9,9 +9,9 @@
 ; - M: Between two input lines included by the filter.
 ; - E: At the end of the input.
 ;
-; They are all present at -dump-input-context=6.  One disappears each time
-; -dump-input-context is incremented beyond that because there are no lines
-; left to elide.
+; They are all present at -dump-input-context=4.  One becomes useless each time
+; -dump-input-context is incremented beyond that because then that ellipsis
+; becomes equal to or larger than the input lines it elides.
 ;--------------------------------------------------
 
 ; RUN: echo foo8       >  %t.in
@@ -47,6 +47,7 @@
 ; RUN: echo foo7       >> %t.in
 ; RUN: echo foo8       >> %t.in
 ; RUN: echo foo9       >> %t.in
+; RUN: echo foo0       >> %t.in
 
 ; RUN: echo 'CHECK-LABEL: lab1'  >  %t.chk
 ; RUN: echo ' CHECK-NEXT: hello' >> %t.chk
@@ -57,9 +58,9 @@
 ; CS-NEXT:            .
 ; CS-NEXT:            .
 ; CS-NEXT:            .
-; C8-NEXT:            1: foo8
-; C7-NEXT:            2: foo7
-; C6-NEXT:            3: foo6
+; C5-NEXT:            1: foo8
+; C5-NEXT:            2: foo7
+; C5-NEXT:            3: foo6
 ; C5-NEXT:            4: foo5
 ; C4-NEXT:            5: foo4
 ; C3-NEXT:            6: foo3
@@ -75,11 +76,11 @@
 ; C4-NEXT:           13: foo4
 ; C5-NEXT:           14: foo5
 ; C6-NEXT:           15: foo6
-; C7-NEXT:           16: foo7
+; C6-NEXT:           16: foo7
 ; CM-NEXT:            .
 ; CM-NEXT:            .
 ; CM-NEXT:            .
-; C7-NEXT:           17: foo7
+; C6-NEXT:           17: foo7
 ; C6-NEXT:           18: foo6
 ; C5-NEXT:           19: foo5
 ; C4-NEXT:           20: foo4
@@ -96,13 +97,65 @@
 ; C5-NEXT:           29: foo5
 ; C6-NEXT:           30: foo6
 ; C7-NEXT:           31: foo7
-; C8-NEXT:           32: foo8
-; C9-NEXT:           33: foo9
+; C7-NEXT:           32: foo8
+; C7-NEXT:           33: foo9
+; C7-NEXT:           34: foo0
 ; CE-NEXT:            .
 ; CE-NEXT:            .
 ; CE-NEXT:            .
 ; C0-NEXT: >>>>>>
 
+; Now build an alternate set of checks where input lines that might be elided by
+; ellipses have annotations.
+
+; RUN: cp %t.in %t.wide.in
+; RUN: echo 'CHECK-LABEL: lab1'    >  %t.wide.chk
+; RUN: echo '      CHECK: hello'   >> %t.wide.chk
+; RUN: echo '      CHECK: goodbye' >> %t.wide.chk
+; RUN: echo 'CHECK-LABEL: lab2'    >> %t.wide.chk
+; RUN: echo ' CHECK-NEXT: world'   >> %t.wide.chk
+
+;      W5: <<<<<<
+;      W5:            9: lab1 hello
+; W5-NEXT: label:1'0     ^~~~
+; W5-NEXT: label:1'1     ^~~~
+; W5-NEXT: check:2            ^~~~~
+; W5-NEXT:           10: foo1
+; W5-NEXT: check:3       X~~~ error: no match found
+; W5-NEXT:           11: foo2
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           12: foo3
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           13: foo4
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           14: foo5
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           15: foo6
+; W5-NEXT: check:3       ~~~~
+; W6-NEXT:           16: foo7
+; W6-NEXT: check:3       ~~~~
+; WM-NEXT:            .
+; WM-NEXT:            .
+; WM-NEXT:            .
+; W6-NEXT:           17: foo7
+; W6-NEXT: check:3       ~~~~
+; W6-NEXT:           18: foo6
+; W6-NEXT: check:3       ~~~~
+; W5-NEXT:           19: foo5
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           20: foo4
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           21: foo3
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           22: foo2
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           23: foo1
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT:           24: lab2 world
+; W5-NEXT: label:4       ^~~~
+; W5-NEXT: check:3       ~~~~
+; W5-NEXT: next:5             !~~~~ error: match on wrong line
+
 ;--------------------------------------------------
 ; Check -dump-input-context=<bad value>.
 ;--------------------------------------------------
@@ -135,40 +188,35 @@ BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL
 ; RUN:               -dump-input-context=1 \
 ; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
 
-; 6 is the boundary case at which all ellipses are present in our test.
+; 4 is the boundary case at which all ellipses are present in our test.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=6 \
-; RUN: | FileCheck %s -match-full-lines \
-; RUN:                -check-prefixes=C0,C1,C2,C3,C4,C5,C6,CS,CM,CE
+; RUN:               -dump-input-context=4 \
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,CS,CM,CE
 
-; 7 is the boundary case at which the middle ellipsis disappears.
+; 5 is the boundary case at which the start ellipsis is useless.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=7 \
-; RUN: | FileCheck %s -match-full-lines \
-; RUN:                -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7,CS,CE
+; RUN:               -dump-input-context=5 \
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,CM,CE
 
-; 8 is the boundary case at which the start ellipsis disappears.
+; 6 is the boundary case at which the middle ellipsis is useless.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=8 \
-; RUN: | FileCheck %s -match-full-lines \
-; RUN:                -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7,C8,CE
+; RUN:               -dump-input-context=6 \
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,C6,CE
 
-; 9 is the boundary case at which the end ellipsis disappears.
+; 7 is the boundary case at which the end ellipsis is useless.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN:               -dump-input-context=9 \
-; RUN: | FileCheck %s -match-full-lines \
-; RUN:                -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7,C8,C9
+; RUN:               -dump-input-context=7 \
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7
 
 ; Make sure all is fine when -dump-input-context is far larger than the input.
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
 ; RUN:               -dump-input-context=200 \
-; RUN: | FileCheck %s -match-full-lines \
-; RUN:                -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7,C8,C9
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,C6,C7
 
 ;--------------------------------------------------
 ; Check that -dump-input-context default is 5.
@@ -176,8 +224,7 @@ BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL
 
 ; RUN: %ProtectFileCheckOutput \
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-; RUN: | FileCheck %s -match-full-lines \
-; RUN:                -check-prefixes=C0,C1,C2,C3,C4,C5,CS,CM,CE
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,C2,C3,C4,C5,CM,CE
 
 ;--------------------------------------------------
 ; Check multiple -dump-input-context options.
@@ -225,3 +272,22 @@ BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL
 ; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
 ; RUN:               -dump-input-context=0 \
 ; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
+
+;--------------------------------------------------
+; Check how annotations on input lines that might be elided by ellipses affect
+; whether they are actually elided.
+;--------------------------------------------------
+
+; At -dump-input-context=5, the ellipsis is useful but only when annotations on
+; elided input lines are considered.
+; RUN: %ProtectFileCheckOutput \
+; RUN: not FileCheck -dump-input=fail -vv %t.wide.chk < %t.wide.in 2>&1 \
+; RUN:               -dump-input-context=5 \
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=W5,WM
+
+; At -dump-input-context=6, the ellipsis is not useful even when annotations on
+; elided input lines are considered.
+; RUN: %ProtectFileCheckOutput \
+; RUN: not FileCheck -dump-input=fail -vv %t.wide.chk < %t.wide.in 2>&1 \
+; RUN:               -dump-input-context=6 \
+; RUN: | FileCheck %s -match-full-lines -check-prefixes=W5,W6

diff  --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index 0952d4bd24d0..ec2556074aee 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -429,6 +429,25 @@ static unsigned FindInputLineInFilter(
   return UINT_MAX;
 }
 
+/// To OS, print a vertical ellipsis (right-justified at LabelWidth) if it would
+/// occupy less lines than ElidedLines, but print ElidedLines otherwise.  Either
+/// way, clear ElidedLines.  Thus, if ElidedLines is empty, do nothing.
+static void DumpEllipsisOrElidedLines(raw_ostream &OS, std::string &ElidedLines,
+                                      unsigned LabelWidth) {
+  if (ElidedLines.empty())
+    return;
+  unsigned EllipsisLines = 3;
+  if (EllipsisLines < StringRef(ElidedLines).count('\n')) {
+    for (unsigned i = 0; i < EllipsisLines; ++i) {
+      WithColor(OS, raw_ostream::BLACK, /*Bold=*/true)
+          << right_justify(".", LabelWidth);
+      OS << '\n';
+    }
+  } else
+    OS << ElidedLines;
+  ElidedLines.clear();
+}
+
 static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
                                bool DumpInputFilterOnError,
                                unsigned DumpInputContext,
@@ -507,7 +526,12 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
   // Print annotated input lines.
   unsigned PrevLineInFilter = 0; // 0 means none so far
   unsigned NextLineInFilter = 0; // 0 means uncomputed, UINT_MAX means none
-  bool PrevLineElided = false;
+  std::string ElidedLines;
+  raw_string_ostream ElidedLinesOS(ElidedLines);
+  ColorMode TheColorMode =
+      WithColor(OS).colorsEnabled() ? ColorMode::Enable : ColorMode::Disable;
+  if (TheColorMode == ColorMode::Enable)
+    ElidedLinesOS.enable_colors(true);
   auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
   for (unsigned Line = 1;
        InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
@@ -524,37 +548,29 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
 
     // Elide this input line and its annotations if it's not within the
     // context specified by -dump-input-context of an input line included by
-    // the dump filter.
+    // the dump filter.  However, in case the resulting ellipsis would occupy
+    // more lines than the input lines and annotations it elides, buffer the
+    // elided lines and annotations so we can print them instead.
+    raw_ostream *LineOS = &OS;
     if ((!PrevLineInFilter || PrevLineInFilter + DumpInputContext < Line) &&
         (NextLineInFilter == UINT_MAX ||
-         Line + DumpInputContext < NextLineInFilter)) {
-      while (InputFilePtr != InputFileEnd && *InputFilePtr != '\n')
-        ++InputFilePtr;
-      if (InputFilePtr != InputFileEnd)
-        ++InputFilePtr;
-      while (AnnotationItr != AnnotationEnd && AnnotationItr->InputLine == Line)
-        ++AnnotationItr;
-      if (!PrevLineElided) {
-        for (unsigned i = 0; i < 3; ++i) {
-          WithColor(OS, raw_ostream::BLACK, /*Bold=*/true)
-              << right_justify(".", LabelWidth);
-          OS << '\n';
-        }
-        PrevLineElided = true;
-      }
-      continue;
+         Line + DumpInputContext < NextLineInFilter))
+      LineOS = &ElidedLinesOS;
+    else {
+      LineOS = &OS;
+      DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
     }
-    PrevLineElided = false;
 
     // Print right-aligned line number.
-    WithColor(OS, raw_ostream::BLACK, true)
+    WithColor(*LineOS, raw_ostream::BLACK, /*Bold=*/true, /*BF=*/false,
+              TheColorMode)
         << format_decimal(Line, LabelWidth) << ": ";
 
     // For the case where -v and colors are enabled, find the annotations for
     // good matches for expected patterns in order to highlight everything
     // else in the line.  There are no such annotations if -v is disabled.
     std::vector<InputAnnotation> FoundAndExpectedMatches;
-    if (Req.Verbose && WithColor(OS).colorsEnabled()) {
+    if (Req.Verbose && TheColorMode == ColorMode::Enable) {
       for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
            ++I) {
         if (I->FoundAndExpectedMatch)
@@ -566,7 +582,8 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
     // expected patterns.
     bool Newline = false;
     {
-      WithColor COS(OS);
+      WithColor COS(*LineOS, raw_ostream::SAVEDCOLOR, /*Bold=*/false,
+                    /*BG=*/false, TheColorMode);
       bool InMatch = false;
       if (Req.Verbose)
         COS.changeColor(raw_ostream::CYAN, true, true);
@@ -590,13 +607,14 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
         ++InputFilePtr;
       }
     }
-    OS << '\n';
+    *LineOS << '\n';
     unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
 
     // Print any annotations.
     while (AnnotationItr != AnnotationEnd &&
            AnnotationItr->InputLine == Line) {
-      WithColor COS(OS, AnnotationItr->Marker.Color, true);
+      WithColor COS(*LineOS, AnnotationItr->Marker.Color, /*Bold=*/true,
+                    /*BG=*/false, TheColorMode);
       // The two spaces below are where the ": " appears on input lines.
       COS << left_justify(AnnotationItr->Label, LabelWidth) << "  ";
       unsigned Col;
@@ -621,6 +639,7 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
       ++AnnotationItr;
     }
   }
+  DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
 
   OS << ">>>>>>\n";
 }


        


More information about the llvm-commits mailing list