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
5 changes: 5 additions & 0 deletions test/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3291,3 +3291,8 @@ lit_config.note(f"Target Triple: {config.target_triple}, Variant Triple: {config

lit_config.note("Available features: " + ", ".join(sorted(config.available_features)))
config.substitutions.append( ('%use_no_opaque_pointers', '-Xcc -Xclang -Xcc -no-opaque-pointers' ) )

if lit_config.update_tests:
sys.path.append(config.swift_utils)
from update_verify_tests.litplugin import uvt_lit_plugin
lit_config.test_updaters.append(uvt_lit_plugin)
11 changes: 8 additions & 3 deletions utils/update-verify-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--prefix", default="", help="The prefix passed to -verify")
args = parser.parse_args()
(ret_code, output) = check_expectations(sys.stdin.readlines(), args.prefix)
print(output)
sys.exit(ret_code)
(err, updated_files) = check_expectations(sys.stdin.readlines(), args.prefix)
if err:
print(err)
sys.exit(1)

if len(updated_files) > 1:
print("\n\t".join(["updated files:"] + updated_files))
print(f"updated file: {updated_files[0]}")


if __name__ == "__main__":
Expand Down
16 changes: 8 additions & 8 deletions utils/update_verify_tests/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,13 +570,13 @@ def update_test_files(errors, prefix):
try:
update_test_file(filename, diag_errors, prefix, updated_test_files)
except KnownException as e:
return f"Error in update-verify-tests while updating {filename}: {e}"
return (
f"Error in update-verify-tests while updating {filename}: {e}",
None,
)
updated_files = list(updated_test_files)
assert updated_files
if len(updated_files) == 1:
return f"updated file {updated_files[0]}"
updated_files_s = "\n\t".join(updated_files)
return "updated files:\n\t{updated_files_s}"
return (None, updated_files)


"""
Expand Down Expand Up @@ -786,8 +786,8 @@ def check_expectations(tool_output, prefix):
top_level.extend(curr)

except KnownException as e:
return (1, f"Error in update-verify-tests while parsing tool output: {e}")
return (f"Error in update-verify-tests while parsing tool output: {e}", None)
if top_level:
return (0, update_test_files(top_level, prefix))
return update_test_files(top_level, prefix)
else:
return (1, "no mismatching diagnostics found")
return ("no mismatching diagnostics found", None)
135 changes: 135 additions & 0 deletions utils/update_verify_tests/litplugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import os
import shlex
import pathlib
from update_verify_tests.core import check_expectations

"""
This file provides the `uvt_lit_plugin` function, which is invoked on failed RUN lines when lit is executed with --update-tests.
It checks whether the failed command is a swift compiler invocation with the `-verify` flag and analyses the output to try to
repair the failed test. If the updated file was originally created by `split-file` it updates the corresponding slice in the source file.
"""


class SplitFileTarget:
def __init__(self, slice_start_idx, test_path, lines, name):
self.slice_start_idx = slice_start_idx
self.test_path = test_path
self.lines = lines
self.name = name

def copyFrom(self, source):
lines_before = self.lines[: self.slice_start_idx + 1]
self.lines = self.lines[self.slice_start_idx + 1 :]
slice_end_idx = None
for i, l in enumerate(self.lines):
if SplitFileTarget._get_split_line_path(l) != None:
slice_end_idx = i
break
if slice_end_idx is not None:
lines_after = self.lines[slice_end_idx:]
else:
lines_after = []
with open(source, "r") as f:
new_lines = lines_before + f.readlines() + lines_after
with open(self.test_path, "w") as f:
for l in new_lines:
f.write(l)

def __str__(self):
return f"slice {self.name} in {self.test_path}"

@staticmethod
def get_target_dir(commands, test_path):
# posix=True breaks Windows paths because \ is treated as an escaping character
for cmd in commands:
split = shlex.split(cmd, posix=False)
if "split-file" not in split:
continue
start_idx = split.index("split-file")
split = split[start_idx:]
if len(split) < 3:
continue
p = unquote(split[1].strip())
if not test_path.samefile(p):
continue
return unquote(split[2].strip())
return None

@staticmethod
def create(path, commands, test_path, target_dir):
path = pathlib.Path(path)
with open(test_path, "r") as f:
lines = f.readlines()
for i, l in enumerate(lines):
p = SplitFileTarget._get_split_line_path(l)
if p and path.samefile(os.path.join(target_dir, p)):
idx = i
break
else:
return None
return SplitFileTarget(idx, test_path, lines, p)

@staticmethod
def _get_split_line_path(l):
if len(l) < 6:
return None
if l.startswith("//"):
l = l[2:]
else:
l = l[1:]
if l.startswith("--- "):
l = l[4:]
else:
return None
return l.rstrip()


def unquote(s):
if len(s) > 1 and s[0] == s[-1] and (s[0] == '"' or s[0] == "'"):
return s[1:-1]
return s


def propagate_split_files(test_path, updated_files, commands):
test_path = pathlib.Path(test_path)
split_target_dir = SplitFileTarget.get_target_dir(commands, test_path)
if not split_target_dir:
return updated_files

new = []
for file in updated_files:
target = SplitFileTarget.create(file, commands, test_path, split_target_dir)
if target:
target.copyFrom(file)
new.append(target)
else:
new.append(file)
return new


def uvt_lit_plugin(result, test, commands):
if (
not any(e.endswith("swift-frontend") for e in result.command.args)
or not "-verify" in result.command.args
):
return None

prefix = ""
for i, arg in enumerate(result.command.args):
if arg == "-verify-additional-prefix":
if i + 1 >= len(result.command.args):
return None
if prefix:
# can only handle at most 1 additional prefix at the moment
return None
prefix = result.command.args[i + 1]

(err, updated_files) = check_expectations(result.stderr.split("\n"), prefix)
if err:
return err

updated_files = propagate_split_files(test.getFilePath(), updated_files, commands)

if len(updated_files) > 1:
return "\n\t".join(["updated files:"] + updated_files)
return f"updated file: {updated_files[0]}"