mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[FileCheck] Implement -dump-input-context
This patch is motivated by discussions at each of: * <https://reviews.llvm.org/D81422> * <http://lists.llvm.org/pipermail/llvm-dev/2020-June/142369.html> When input is dumped as specified by `-dump-input=fail`, this patch filters the dump to show only input lines that are the starting lines of error diagnostics plus the number of contextual lines specified `-dump-input-context` (defaults to 5). When `-dump-input=always`, there might be not be any errors, so all input lines are printed, as without this patch. Here's some sample output with `-dump-input-context=3 -vv`: ``` <<<<<< . . . 13: foo 14: foo 15: hello world check:1 ^~~~~~~~~~~ 16: foo check:2'0 X~~ error: no match found 17: foo check:2'0 ~~~ 18: foo check:2'0 ~~~ 19: foo check:2'0 ~~~ . . . 27: foo check:2'0 ~~~ 28: foo check:2'0 ~~~ 29: foo check:2'0 ~~~ 30: goodbye word check:2'0 ~~~~~~~~~~~~ check:2'1 ? possible intended match 31: foo check:2'0 ~~~ 32: foo check:2'0 ~~~ 33: foo check:2'0 ~~~ . . . >>>>>> ``` Reviewed By: mehdi_amini, arsenm, jhenderson, rsmith, SjoerdMeijer, Meinersbur, lattner Differential Revision: https://reviews.llvm.org/D82203
This commit is contained in:
parent
f387d6739f
commit
82eeb7f9a7
@ -24,7 +24,7 @@
|
||||
; ALIGN:{{.*}}error:{{.*}}
|
||||
; ALIGN:{{.*}}possible intended match here{{.*}}
|
||||
|
||||
; ALIGN:Full input was:
|
||||
; ALIGN:Input was:
|
||||
; ALIGN-NEXT:<<<<<<
|
||||
; ALIGN-NEXT: 1: hello world
|
||||
; ALIGN-NEXT:check:1 ^~~~~
|
||||
|
227
test/FileCheck/dump-input-context.txt
Normal file
227
test/FileCheck/dump-input-context.txt
Normal file
@ -0,0 +1,227 @@
|
||||
;--------------------------------------------------
|
||||
; Input file, check file, and directives for checking the size of the context.
|
||||
;
|
||||
; These are designed to be used with -dump-input=fail -vv.
|
||||
;
|
||||
; In the resulting input dump, there are three potential ellipses:
|
||||
;
|
||||
; - S: At the start of the input.
|
||||
; - 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.
|
||||
;--------------------------------------------------
|
||||
|
||||
; RUN: echo foo8 > %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo lab1 hello >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo lab2 world >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo8 >> %t.in
|
||||
; RUN: echo foo9 >> %t.in
|
||||
|
||||
; RUN: echo 'CHECK-LABEL: lab1' > %t.chk
|
||||
; RUN: echo ' CHECK-NEXT: hello' >> %t.chk
|
||||
; RUN: echo 'CHECK-LABEL: lab2' >> %t.chk
|
||||
; RUN: echo ' CHECK-NEXT: world' >> %t.chk
|
||||
|
||||
; C0: <<<<<<
|
||||
; CS-NEXT: .
|
||||
; CS-NEXT: .
|
||||
; CS-NEXT: .
|
||||
; C8-NEXT: 1: foo8
|
||||
; C7-NEXT: 2: foo7
|
||||
; C6-NEXT: 3: foo6
|
||||
; C5-NEXT: 4: foo5
|
||||
; C4-NEXT: 5: foo4
|
||||
; C3-NEXT: 6: foo3
|
||||
; C2-NEXT: 7: foo2
|
||||
; C1-NEXT: 8: foo1
|
||||
; C0-NEXT: 9: lab1 hello
|
||||
; C0-NEXT: label:1'0 ^~~~
|
||||
; C0-NEXT: label:1'1 ^~~~
|
||||
; C0-NEXT: next:2 !~~~~ error: match on wrong line
|
||||
; C1-NEXT: 10: foo1
|
||||
; C2-NEXT: 11: foo2
|
||||
; C3-NEXT: 12: foo3
|
||||
; C4-NEXT: 13: foo4
|
||||
; C5-NEXT: 14: foo5
|
||||
; C6-NEXT: 15: foo6
|
||||
; C7-NEXT: 16: foo7
|
||||
; CM-NEXT: .
|
||||
; CM-NEXT: .
|
||||
; CM-NEXT: .
|
||||
; C7-NEXT: 17: foo7
|
||||
; C6-NEXT: 18: foo6
|
||||
; C5-NEXT: 19: foo5
|
||||
; C4-NEXT: 20: foo4
|
||||
; C3-NEXT: 21: foo3
|
||||
; C2-NEXT: 22: foo2
|
||||
; C1-NEXT: 23: foo1
|
||||
; C0-NEXT: 24: lab2 world
|
||||
; C0-NEXT: label:3 ^~~~
|
||||
; C0-NEXT: next:4 !~~~~ error: match on wrong line
|
||||
; C1-NEXT: 25: foo1
|
||||
; C2-NEXT: 26: foo2
|
||||
; C3-NEXT: 27: foo3
|
||||
; C4-NEXT: 28: foo4
|
||||
; C5-NEXT: 29: foo5
|
||||
; C6-NEXT: 30: foo6
|
||||
; C7-NEXT: 31: foo7
|
||||
; C8-NEXT: 32: foo8
|
||||
; C9-NEXT: 33: foo9
|
||||
; CE-NEXT: .
|
||||
; CE-NEXT: .
|
||||
; CE-NEXT: .
|
||||
; C0-NEXT: >>>>>>
|
||||
|
||||
;--------------------------------------------------
|
||||
; Check -dump-input-context=<bad value>.
|
||||
;--------------------------------------------------
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input-context=-1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL -DVAL=-1
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input-context=foobar \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL -DVAL=foobar
|
||||
|
||||
BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-context option: '[[VAL]]' value invalid for uint argument!
|
||||
|
||||
;--------------------------------------------------
|
||||
; Check -dump-input-context explicit values.
|
||||
;--------------------------------------------------
|
||||
|
||||
; 0 is an important boundary case.
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; 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,CS,CM,CE
|
||||
|
||||
; 1 is an important boundary case.
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; 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.
|
||||
; 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
|
||||
|
||||
; 7 is the boundary case at which the middle ellipsis disappears.
|
||||
; 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
|
||||
|
||||
; 8 is the boundary case at which the start ellipsis disappears.
|
||||
; 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
|
||||
|
||||
; 9 is the boundary case at which the end ellipsis disappears.
|
||||
; 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
|
||||
|
||||
; 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
|
||||
|
||||
;--------------------------------------------------
|
||||
; Check that -dump-input-context default is 5.
|
||||
;--------------------------------------------------
|
||||
|
||||
; 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
|
||||
|
||||
;--------------------------------------------------
|
||||
; Check multiple -dump-input-context options.
|
||||
;
|
||||
; This might occur when a test author specifies -dump-input-context on a
|
||||
; specific FileCheck call while a test runner specifies -dump-input-context in
|
||||
; FILECHECK_OPTS, but check the behavior generally.
|
||||
;
|
||||
; The largest value wins because it provides the most information.
|
||||
;--------------------------------------------------
|
||||
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
; Check duplicate.
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input-context=1 -dump-input-context=1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
|
||||
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
; Check precedence.
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input-context=0 -dump-input-context=1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input-context=1 -dump-input-context=0 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
|
||||
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
; Check that FILECHECK_OPTS isn't handled differently.
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-context=0 \
|
||||
; RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input-context=1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=C0,C1,CS,CM,CE
|
||||
|
||||
; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-context=1 \
|
||||
; 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
|
@ -236,7 +236,7 @@ BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find op
|
||||
|
||||
; NODUMP-NOT: <<<<<<
|
||||
|
||||
; DUMP-OK: Full input was:
|
||||
; DUMP-OK: Input was:
|
||||
; DUMP-OK-NEXT: <<<<<<
|
||||
; DUMP-OK-NEXT: 1: hello
|
||||
; DUMP-OK-NEXT: check:1 ^~~~~
|
||||
@ -244,7 +244,7 @@ BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input option: Cannot find op
|
||||
; DUMP-OK-NEXT: next:2 ^~~~~
|
||||
; DUMP-OK-NEXT: >>>>>>
|
||||
|
||||
; DUMP-ERR: Full input was:
|
||||
; DUMP-ERR: Input was:
|
||||
; DUMP-ERR-NEXT: <<<<<<
|
||||
; DUMP-ERR-NEXT: 1: hello
|
||||
; DUMP-ERR-V-NEXT: check:1 ^~~~~
|
||||
|
208
test/FileCheck/dump-input-filter.txt
Normal file
208
test/FileCheck/dump-input-filter.txt
Normal file
@ -0,0 +1,208 @@
|
||||
; To keep this test maintainable, avoid depending on -dump-input-context's
|
||||
; default value, which is checked in dump-input-context.txt instead.
|
||||
|
||||
;--------------------------------------------------
|
||||
; Create the input file and the check file.
|
||||
;--------------------------------------------------
|
||||
|
||||
; line 1
|
||||
; RUN: echo start > %t.in
|
||||
; RUN: echo foo0 >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo8 >> %t.in
|
||||
; RUN: echo foo9 >> %t.in
|
||||
; line 12
|
||||
; RUN: echo hello >> %t.in
|
||||
; RUN: echo foo0 >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo8 >> %t.in
|
||||
; RUN: echo foo9 >> %t.in
|
||||
; line 23
|
||||
; RUN: echo word >> %t.in
|
||||
; RUN: echo foo0 >> %t.in
|
||||
; RUN: echo foo1 >> %t.in
|
||||
; RUN: echo foo2 >> %t.in
|
||||
; RUN: echo foo3 >> %t.in
|
||||
; RUN: echo foo4 >> %t.in
|
||||
; RUN: echo foo5 >> %t.in
|
||||
; RUN: echo foo6 >> %t.in
|
||||
; RUN: echo foo7 >> %t.in
|
||||
; RUN: echo foo8 >> %t.in
|
||||
; RUN: echo foo9 >> %t.in
|
||||
; line 34
|
||||
; RUN: echo end >> %t.in
|
||||
|
||||
; RUN: echo 'CHECK: start' > %t.chk
|
||||
; RUN: echo 'CHECK: hello' >> %t.chk
|
||||
; RUN: echo 'CHECK: world' >> %t.chk
|
||||
; RUN: echo 'CHECK: end' >> %t.chk
|
||||
|
||||
;--------------------------------------------------
|
||||
; Directives for checking the dump.
|
||||
;--------------------------------------------------
|
||||
|
||||
; ALL: <<<<<<
|
||||
; ALL-NEXT: 1: start
|
||||
; ALL-NEXT: check:1 ^~~~~
|
||||
; ALL-NEXT: 2: foo0
|
||||
; ALL-NEXT: 3: foo1
|
||||
; ALL-NEXT: 4: foo2
|
||||
; ALL-NEXT: 5: foo3
|
||||
; ALL-NEXT: 6: foo4
|
||||
; ALL-NEXT: 7: foo5
|
||||
; ALL-NEXT: 8: foo6
|
||||
; ALL-NEXT: 9: foo7
|
||||
; ALL-NEXT: 10: foo8
|
||||
; ALL-NEXT: 11: foo9
|
||||
; ALL-NEXT: 12: hello
|
||||
; ALL-NEXT: check:2 ^~~~~
|
||||
; ALL-NEXT: 13: foo0
|
||||
; ALL-NEXT: check:3'0 X~~~ error: no match found
|
||||
; ALL-NEXT: 14: foo1
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 15: foo2
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 16: foo3
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 17: foo4
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 18: foo5
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 19: foo6
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 20: foo7
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 21: foo8
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 22: foo9
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 23: word
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: check:3'1 ? possible intended match
|
||||
; ALL-NEXT: 24: foo0
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 25: foo1
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 26: foo2
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 27: foo3
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 28: foo4
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 29: foo5
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 30: foo6
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 31: foo7
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 32: foo8
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 33: foo9
|
||||
; ALL-NEXT: check:3'0 ~~~~
|
||||
; ALL-NEXT: 34: end
|
||||
; ALL-NEXT: check:3'0 ~~~
|
||||
; ALL-NEXT: >>>>>>
|
||||
|
||||
; ERROR: <<<<<<
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: 11: foo9
|
||||
; ERROR-NEXT: 12: hello
|
||||
; ERROR-NEXT: check:2 ^~~~~
|
||||
; ERROR-NEXT: 13: foo0
|
||||
; ERROR-NEXT: check:3'0 X~~~ error: no match found
|
||||
; ERROR-NEXT: 14: foo1
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: 15: foo2
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: 21: foo8
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: 22: foo9
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: 23: word
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: check:3'1 ? possible intended match
|
||||
; ERROR-NEXT: 24: foo0
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: 25: foo1
|
||||
; ERROR-NEXT: check:3'0 ~~~~
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: .
|
||||
; ERROR-NEXT: >>>>>>
|
||||
|
||||
;--------------------------------------------------
|
||||
; Check how -dump-input affects filter.
|
||||
;--------------------------------------------------
|
||||
|
||||
; no -dump-input => include errors.
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR
|
||||
|
||||
; -dump-input=fail => include errors.
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input=fail \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR
|
||||
|
||||
; -dump-input=always => include all.
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \
|
||||
; RUN: -dump-input=always \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL
|
||||
|
||||
;--------------------------------------------------
|
||||
; Check that other kinds of errors are included by -dump-input=fail.
|
||||
;
|
||||
; "error: no match found" and "possible intended match" are checked above.
|
||||
;--------------------------------------------------
|
||||
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
; error: no match expected.
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
; RUN: echo 'foo' > %t.not-err.in
|
||||
; RUN: echo 'CHECK-NOT: foo' > %t.not-err.chk
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input-context=0 -dump-input=fail \
|
||||
; RUN: %t.not-err.chk < %t.not-err.in 2>&1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=NOT-ERR
|
||||
|
||||
; NOT-ERR: 1: foo
|
||||
; NOT-ERR-NEXT: not:1 !~~ error: no match expected
|
||||
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
; error: match on wrong line.
|
||||
;- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
; RUN: echo 'foo' > %t.next-err.in
|
||||
; RUN: echo 'foo' >> %t.next-err.in
|
||||
; RUN: echo 'bar' >> %t.next-err.in
|
||||
; RUN: echo 'CHECK: foo' > %t.next-err.chk
|
||||
; RUN: echo 'CHECK-NEXT: bar' >> %t.next-err.chk
|
||||
|
||||
; RUN: %ProtectFileCheckOutput \
|
||||
; RUN: not FileCheck -dump-input-context=0 -dump-input=fail \
|
||||
; RUN: %t.next-err.chk < %t.next-err.in 2>&1 \
|
||||
; RUN: | FileCheck %s -match-full-lines -check-prefixes=NEXT-ERR
|
||||
|
||||
; NEXT-ERR: 3: bar
|
||||
; NEXT-ERR-NEXT: next:2 !~~ error: match on wrong line
|
@ -128,6 +128,14 @@ static cl::list<DumpInputValue> DumpInputs(
|
||||
clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
|
||||
clEnumValN(DumpInputNever, "never", "Never dump input")));
|
||||
|
||||
static cl::list<unsigned> DumpInputContexts(
|
||||
"dump-input-context", cl::value_desc("N"),
|
||||
cl::desc("In the dump requested by -dump-input=fail, print <N> input\n"
|
||||
"lines before and <N> input lines after the starting line of\n"
|
||||
"any error diagnostic. When there are multiple occurrences of\n"
|
||||
"this option, the largest specified <N> has precedence. The\n"
|
||||
"default is 5.\n"));
|
||||
|
||||
typedef cl::list<std::string>::const_iterator prefix_iterator;
|
||||
|
||||
|
||||
@ -150,10 +158,16 @@ struct MarkerStyle {
|
||||
raw_ostream::Colors Color;
|
||||
/// A note to follow the marker, or empty string if none.
|
||||
std::string Note;
|
||||
/// Does this marker indicate inclusion by the input filter implied by
|
||||
/// -dump-input=fail?
|
||||
bool FiltersAsError;
|
||||
MarkerStyle() {}
|
||||
MarkerStyle(char Lead, raw_ostream::Colors Color,
|
||||
const std::string &Note = "")
|
||||
: Lead(Lead), Color(Color), Note(Note) {}
|
||||
const std::string &Note = "", bool FiltersAsError = false)
|
||||
: Lead(Lead), Color(Color), Note(Note), FiltersAsError(FiltersAsError) {
|
||||
assert((!FiltersAsError || !Note.empty()) &&
|
||||
"expected error diagnostic to have note");
|
||||
}
|
||||
};
|
||||
|
||||
static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
|
||||
@ -161,18 +175,22 @@ static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
|
||||
case FileCheckDiag::MatchFoundAndExpected:
|
||||
return MarkerStyle('^', raw_ostream::GREEN);
|
||||
case FileCheckDiag::MatchFoundButExcluded:
|
||||
return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
|
||||
return MarkerStyle('!', raw_ostream::RED, "error: no match expected",
|
||||
/*FiltersAsError=*/true);
|
||||
case FileCheckDiag::MatchFoundButWrongLine:
|
||||
return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
|
||||
return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line",
|
||||
/*FiltersAsError=*/true);
|
||||
case FileCheckDiag::MatchFoundButDiscarded:
|
||||
return MarkerStyle('!', raw_ostream::CYAN,
|
||||
"discard: overlaps earlier match");
|
||||
case FileCheckDiag::MatchNoneAndExcluded:
|
||||
return MarkerStyle('X', raw_ostream::GREEN);
|
||||
case FileCheckDiag::MatchNoneButExpected:
|
||||
return MarkerStyle('X', raw_ostream::RED, "error: no match found");
|
||||
return MarkerStyle('X', raw_ostream::RED, "error: no match found",
|
||||
/*FiltersAsError=*/true);
|
||||
case FileCheckDiag::MatchFuzzy:
|
||||
return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
|
||||
return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match",
|
||||
/*FiltersAsError=*/true);
|
||||
}
|
||||
llvm_unreachable_internal("unexpected match type");
|
||||
}
|
||||
@ -183,6 +201,7 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) {
|
||||
<< "\n"
|
||||
<< "Related command-line options:\n"
|
||||
<< " - -dump-input=<value> enables or disables the input dump\n"
|
||||
<< " - -dump-input-context=<N> adjusts the context of errors\n"
|
||||
<< " - -v and -vv add more annotations\n"
|
||||
<< " - -color forces colors to be enabled both in the dump and below\n"
|
||||
<< " - -help documents the above options in more detail\n"
|
||||
@ -228,6 +247,12 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) {
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
|
||||
OS << " marks fuzzy match when no match is found\n";
|
||||
|
||||
// Elided lines.
|
||||
OS << " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "...";
|
||||
OS << " indicates elided input lines and annotations, as specified by\n"
|
||||
<< " -dump-input=fail and -dump-input-context\n";
|
||||
|
||||
// Colors.
|
||||
OS << " - colors ";
|
||||
WithColor(OS, raw_ostream::GREEN, true) << "success";
|
||||
@ -248,10 +273,12 @@ struct InputAnnotation {
|
||||
unsigned DiagIndex;
|
||||
/// The label for this annotation.
|
||||
std::string Label;
|
||||
/// Is this the initial fragment of a diagnostic that has been broken across
|
||||
/// multiple lines?
|
||||
bool IsFirstLine;
|
||||
/// What input line (one-origin indexing) this annotation marks. This might
|
||||
/// be different from the starting line of the original diagnostic if this is
|
||||
/// a non-initial fragment of a diagnostic that has been broken across
|
||||
/// multiple lines.
|
||||
/// be different from the starting line of the original diagnostic if
|
||||
/// !IsFirstLine.
|
||||
unsigned InputLine;
|
||||
/// The column range (one-origin indexing, open end) in which to mark the
|
||||
/// input line. If InputEndCol is UINT_MAX, treat it as the last column
|
||||
@ -347,6 +374,7 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
|
||||
|
||||
// Compute the mark location, and break annotation into multiple
|
||||
// annotations if it spans multiple lines.
|
||||
A.IsFirstLine = true;
|
||||
A.InputLine = DiagItr->InputStartLine;
|
||||
A.InputStartCol = DiagItr->InputStartCol;
|
||||
if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
|
||||
@ -370,6 +398,7 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
|
||||
InputAnnotation B;
|
||||
B.DiagIndex = A.DiagIndex;
|
||||
B.Label = A.Label;
|
||||
B.IsFirstLine = false;
|
||||
B.InputLine = L;
|
||||
B.Marker = A.Marker;
|
||||
B.Marker.Lead = '~';
|
||||
@ -386,11 +415,27 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned FindInputLineInFilter(
|
||||
bool FilterOnError, unsigned CurInputLine,
|
||||
const std::vector<InputAnnotation>::iterator &AnnotationBeg,
|
||||
const std::vector<InputAnnotation>::iterator &AnnotationEnd) {
|
||||
if (!FilterOnError)
|
||||
return CurInputLine;
|
||||
for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd;
|
||||
++AnnotationItr) {
|
||||
if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError)
|
||||
return AnnotationItr->InputLine;
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
|
||||
bool DumpInputFilterOnError,
|
||||
unsigned DumpInputContext,
|
||||
StringRef InputFileText,
|
||||
std::vector<InputAnnotation> &Annotations,
|
||||
unsigned LabelWidth) {
|
||||
OS << "Full input was:\n<<<<<<\n";
|
||||
OS << "Input was:\n<<<<<<\n";
|
||||
|
||||
// Sort annotations.
|
||||
std::sort(Annotations.begin(), Annotations.end(),
|
||||
@ -460,12 +505,47 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
|
||||
LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
|
||||
|
||||
// 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;
|
||||
auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
|
||||
for (unsigned Line = 1;
|
||||
InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
|
||||
++Line) {
|
||||
const unsigned char *InputFileLine = InputFilePtr;
|
||||
|
||||
// Compute the previous and next line included by the filter.
|
||||
if (NextLineInFilter < Line)
|
||||
NextLineInFilter = FindInputLineInFilter(DumpInputFilterOnError, Line,
|
||||
AnnotationItr, AnnotationEnd);
|
||||
assert(NextLineInFilter && "expected NextLineInFilter to be computed");
|
||||
if (NextLineInFilter == Line)
|
||||
PrevLineInFilter = Line;
|
||||
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
PrevLineElided = false;
|
||||
|
||||
// Print right-aligned line number.
|
||||
WithColor(OS, raw_ostream::BLACK, true)
|
||||
<< format_decimal(Line, LabelWidth) << ": ";
|
||||
@ -553,10 +633,21 @@ int main(int argc, char **argv) {
|
||||
InitLLVM X(argc, argv);
|
||||
cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
|
||||
"FILECHECK_OPTS");
|
||||
|
||||
// Select -dump-input* values. The -help documentation specifies the default
|
||||
// value and which value to choose if an option is specified multiple times.
|
||||
// In the latter case, the general rule of thumb is to choose the value that
|
||||
// provides the most information.
|
||||
DumpInputValue DumpInput =
|
||||
DumpInputs.empty()
|
||||
? DumpInputFail
|
||||
: *std::max_element(DumpInputs.begin(), DumpInputs.end());
|
||||
bool DumpInputFilterOnError = DumpInput == DumpInputFail;
|
||||
unsigned DumpInputContext = DumpInputContexts.empty()
|
||||
? 5
|
||||
: *std::max_element(DumpInputContexts.begin(),
|
||||
DumpInputContexts.end());
|
||||
|
||||
if (DumpInput == DumpInputHelp) {
|
||||
DumpInputAnnotationHelp(outs());
|
||||
return 0;
|
||||
@ -689,7 +780,8 @@ int main(int argc, char **argv) {
|
||||
unsigned LabelWidth;
|
||||
BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags,
|
||||
Annotations, LabelWidth);
|
||||
DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
|
||||
DumpAnnotatedInput(errs(), Req, DumpInputFilterOnError, DumpInputContext,
|
||||
InputFileText, Annotations, LabelWidth);
|
||||
}
|
||||
|
||||
return ExitCode;
|
||||
|
Loading…
x
Reference in New Issue
Block a user