Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions filecheck/FileCheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,23 @@ def __init__(self, check, line_idx):
self.line_idx = line_idx


class FailedImplicitCheckContext:
def __init__(self, check, line, line_idx):
self.check = check
self.line = line
self.line_idx = line_idx


class CheckFailedException(BaseException):
def __init__(self, failed_check):
self.failed_check = failed_check


class ImplicitCheckNotFailedException(BaseException):
def __init__(self, failed_check_context):
self.failed_check_context = failed_check_context


class CheckNOTIsLastException(BaseException):
pass

Expand All @@ -46,6 +58,7 @@ class CheckType(Enum):


Check = namedtuple("Check", "check_type match_type check_keyword expression source_line check_line_idx start_index")
ImplicitCheck = namedtuple("ImplicitCheck", "original_check check")


def debug_print(string):
Expand Down Expand Up @@ -172,6 +185,15 @@ def check_line(line, current_check, match_full_lines):
return CheckResult.PASS


def implicit_check_line(check_not_check, strict_mode, line):
if strict_mode:
if check_not_check.original_check in line:
return True
elif check_not_check.check in line:
return True
return False


def main():
if len(sys.argv) == 1:
print("<check-file> not specified")
Expand Down Expand Up @@ -205,10 +227,25 @@ def main():
parser.add_argument('--strict-whitespace', action='store_true', help='TODO')
parser.add_argument('--match-full-lines', action='store_true', help='TODO')
parser.add_argument('--check-prefix', action='store', help='TODO')
parser.add_argument('--implicit-check-not', action='append', help='TODO')

args = parser.parse_args()

strict_mode = args.match_full_lines and args.strict_whitespace

check_prefix = args.check_prefix if args.check_prefix else "CHECK"
implicit_check_not_checks = []

if args.implicit_check_not:
for implicit_check_not_arg in args.implicit_check_not:
# LLVM FileCheck does rstrip() here for some reason that
# does not seem reasonable. We still prefer to be compatible.
stripped_check = implicit_check_not_arg.rstrip()

implicit_check_not = ImplicitCheck(
original_check=implicit_check_not_arg, check=stripped_check
)
implicit_check_not_checks.append(implicit_check_not)

if not re.search('^[A-Za-z][A-Za-z0-9-_]+$', check_prefix):
sys.stdout.flush()
Expand Down Expand Up @@ -361,9 +398,13 @@ def main():
current_not_checks = []
try:
failed_check = None
failed_implicit_check = None

while True:
line = line.rstrip()

unstripped_line = line

if not args.strict_whitespace:
line = canonicalize_whitespace(line)
if args.match_full_lines:
Expand All @@ -377,6 +418,15 @@ def main():
args.match_full_lines)
if check_result == CheckResult.CHECK_NOT_MATCH:
failed_check = FailedCheck(current_not_check, line_idx)
break

if not failed_implicit_check:
for check_not_check in implicit_check_not_checks:
if implicit_check_line(check_not_check, strict_mode, unstripped_line):
failed_implicit_check = FailedImplicitCheckContext(
check_not_check, unstripped_line, line_idx
)
break

check_result = check_line(line, current_check, args.match_full_lines)

Expand All @@ -385,6 +435,9 @@ def main():
raise CheckFailedException(failed_check)

elif check_result == CheckResult.PASS:
if failed_implicit_check:
raise ImplicitCheckNotFailedException(failed_implicit_check)

if failed_check:
raise CheckFailedException(failed_check)

Expand All @@ -394,6 +447,17 @@ def main():
try:
current_check = next(check_iterator)
except StopIteration:
if len(implicit_check_not_checks) == 0:
exit(0)

for line_idx, line in stdin_input_iter:
for check_not_check in implicit_check_not_checks:
if implicit_check_line(check_not_check, strict_mode, line):
failed_implicit_check = FailedImplicitCheckContext(
check_not_check, line, line_idx
)
raise ImplicitCheckNotFailedException(failed_implicit_check)

exit(0)

try:
Expand Down Expand Up @@ -475,6 +539,26 @@ def main():
current_check = e.failed_check.check
current_check_line_idx = e.failed_check.line_idx

except ImplicitCheckNotFailedException as e:
context = e.failed_check_context
failed_check = context.check
failed_line_num = context.line_idx + 1

failed_column_idx = context.line.find(failed_check.check)
assert failed_column_idx != -1

failed_column_num = failed_column_idx + 1

print("command line:1:22: error: CHECK-NOT: excluded string found in input")
print("-implicit-check-not='{}'".format(failed_check.original_check))
print(" ^")
print("<stdin>:{}:{}: note: found here".format(failed_line_num, failed_column_num))
print(context.line)
print("^"
.rjust(failed_column_idx + 1, ' ')
.ljust(len(failed_check.check) + failed_column_idx, '~'))
exit(1)

# CHECK-EMPTY is special: if there is no output anymore and this check is
# the 1) current and 2) the last one we want to declare success.
# Otherwise we switch to a next check, make it current and go to do error
Expand Down
1 change: 0 additions & 1 deletion git-precommit-hook.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/bin/bash

invoke test

1 change: 1 addition & 0 deletions tests/integration/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ cat_exec = "cat" if cat_available() else "type"
config.substitutions.append(('%cat', cat_exec))

config.substitutions.append(('%expect_exit', 'python \"{}/tests/integration/tools/expect_exit.py\"'.format(current_dir)))
config.substitutions.append(('%printf', 'python \"{}/tests/integration/tools/printf.py\"'.format(current_dir)))

config.suffixes = ['.itest', '.c']

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
; CHECK: string 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error
string 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; RUN: %cat "%S/filecheck.input" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not error | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines

; CHECK:command line:1:22: error: CHECK-NOT: excluded string found in input
; CHECK:-implicit-check-not='error'
; CHECK: ^
; CHECK:<stdin>:1:1: note: found here
; CHECK:error
; CHECK:^~~~~
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
; CHECK: string 1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
error
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; RUN: %cat "%S/filecheck.input" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not error | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines

; CHECK:{{^.*}}filecheck.check:1:10: error: CHECK: expected string not found in input
; CHECK:; CHECK: string 1
; CHECK: ^
; CHECK:<stdin>:1:1: note: scanning from here
; CHECK:error
; CHECK:^
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; CHECK-NOT: error
; CHECK: string 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error
string 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; RUN: %cat "%S/filecheck.input" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not error | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines

; CHECK:command line:1:22: error: CHECK-NOT: excluded string found in input
; CHECK:-implicit-check-not='error'
; CHECK: ^
; CHECK:<stdin>:1:1: note: found here
; CHECK:error
; CHECK:^~~~~
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
; CHECK:Foo
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; RUN: %printf "someerrorsome\nFoo" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not "error" | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines --check-prefix CHECK-BEFORE

; CHECK-BEFORE:command line:1:22: error: CHECK-NOT: excluded string found in input
; CHECK-BEFORE:-implicit-check-not='error'
; CHECK-BEFORE: ^
; CHECK-BEFORE:<stdin>:1:5: note: found here
; CHECK-BEFORE:someerrorsome
; CHECK-BEFORE: ^~~~~

; RUN: %printf "Foo\nsomeerrorsome" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not "error" | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines --check-prefix CHECK-AFTER

; CHECK-AFTER:command line:1:22: error: CHECK-NOT: excluded string found in input
; CHECK-AFTER:-implicit-check-not='error'
; CHECK-AFTER: ^
; CHECK-AFTER:<stdin>:2:5: note: found here
; CHECK-AFTER:someerrorsome
; CHECK-AFTER: ^~~~~

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
; CHECK:Foo
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; RUN: %printf "error\nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error "
; RUN: %printf "error\nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --strict-whitespace
; RUN: %printf "error\nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --match-full-lines
; RUN: %printf "error\nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --strict-whitespace --match-full-lines

; RUN: %printf "error \nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error "
; RUN: %printf "error \nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --strict-whitespace
; RUN: %printf "error \nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --match-full-lines
; RUN: %printf "error \nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --strict-whitespace --match-full-lines

; RUN: %printf " error\nFoo" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines
; RUN: %printf " error\nFoo" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --strict-whitespace | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines
; RUN: %printf " error\nFoo" | %expect_exit 1 %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --match-full-lines | %FILECHECK_TESTER_EXEC "%s" --strict-whitespace --match-full-lines
; RUN: %printf " error\nFoo" | %expect_exit 0 --expect-no-content %FILECHECK_EXEC "%S/filecheck.check" --implicit-check-not " error " --strict-whitespace --match-full-lines

; CHECK:command line:1:22: error: CHECK-NOT: excluded string found in input
; CHECK:-implicit-check-not=' error '
; CHECK: ^
; CHECK:<stdin>:1:1: note: found here
; CHECK: error
; CHECK:^~~~~~
2 changes: 1 addition & 1 deletion tests/integration/tools/expect_exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
for word in output_lines:
print(word)

if unexpected_content or unexpected_content:
if unexpected_exit_code or unexpected_content:
exit(1)

exit(0)
11 changes: 11 additions & 0 deletions tests/integration/tools/printf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sys

if len(sys.argv) != 2:
print("error: printf: expect one argument to be provided")
exit(1)

formatted_string = sys.argv[1]

formatted_string = formatted_string.replace('\\n', '\n')

print(formatted_string, end='')