mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Syntax] Add round-trip syntax test driver and stdlib roundtrip test
This commit is contained in:
@@ -284,6 +284,9 @@ RC<SyntaxData>
|
|||||||
LegacyASTTransformer::visitStructDecl(StructDecl *D,
|
LegacyASTTransformer::visitStructDecl(StructDecl *D,
|
||||||
const SyntaxData *Parent,
|
const SyntaxData *Parent,
|
||||||
const CursorIndex IndexInParent) {
|
const CursorIndex IndexInParent) {
|
||||||
|
return getUnknownDecl(D);
|
||||||
|
|
||||||
|
/* TODO
|
||||||
StructDeclSyntaxBuilder StructBuilder;
|
StructDeclSyntaxBuilder StructBuilder;
|
||||||
if (D->getStartLoc().isValid()) {
|
if (D->getStartLoc().isValid()) {
|
||||||
auto StructKeyword = findTokenSyntax(tok::kw_struct, "struct", SourceMgr,
|
auto StructKeyword = findTokenSyntax(tok::kw_struct, "struct", SourceMgr,
|
||||||
@@ -329,6 +332,7 @@ LegacyASTTransformer::visitStructDecl(StructDecl *D,
|
|||||||
StructBuilder.useMembers(MemberBuilder.build());
|
StructBuilder.useMembers(MemberBuilder.build());
|
||||||
|
|
||||||
return StructBuilder.build().Root;
|
return StructBuilder.build().Root;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
RC<SyntaxData>
|
RC<SyntaxData>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function(get_test_dependencies SDK result_var_name)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(deps_binaries
|
set(deps_binaries
|
||||||
swift swift-ide-test sil-opt swift-llvm-opt swift-demangle
|
swift swift-ide-test swift-syntax-test sil-opt swift-llvm-opt swift-demangle
|
||||||
sil-func-extractor sil-llvm-gen sil-nm sil-passpipeline-dumper
|
sil-func-extractor sil-llvm-gen sil-nm sil-passpipeline-dumper
|
||||||
lldb-moduleimport-test swift-reflection-dump swift-remoteast-test
|
lldb-moduleimport-test swift-reflection-dump swift-remoteast-test
|
||||||
swift-api-digester)
|
swift-api-digester)
|
||||||
|
|||||||
1
test/Syntax/round_trip_stdlib.swift
Normal file
1
test/Syntax/round_trip_stdlib.swift
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// RUN: %round-trip-syntax-test -d ../stdlib --swift-syntax-test %swift-syntax-test
|
||||||
@@ -280,6 +280,7 @@ config.sil_nm = inferSwiftBinary('sil-nm')
|
|||||||
config.sil_passpipeline_dumper = inferSwiftBinary('sil-passpipeline-dumper')
|
config.sil_passpipeline_dumper = inferSwiftBinary('sil-passpipeline-dumper')
|
||||||
config.lldb_moduleimport_test = inferSwiftBinary('lldb-moduleimport-test')
|
config.lldb_moduleimport_test = inferSwiftBinary('lldb-moduleimport-test')
|
||||||
config.swift_ide_test = inferSwiftBinary('swift-ide-test')
|
config.swift_ide_test = inferSwiftBinary('swift-ide-test')
|
||||||
|
config.swift_syntax_test = inferSwiftBinary('swift-syntax-test')
|
||||||
config.swift_reflection_dump = inferSwiftBinary('swift-reflection-dump')
|
config.swift_reflection_dump = inferSwiftBinary('swift-reflection-dump')
|
||||||
config.swift_remoteast_test = inferSwiftBinary('swift-remoteast-test')
|
config.swift_remoteast_test = inferSwiftBinary('swift-remoteast-test')
|
||||||
config.swift_format = inferSwiftBinary('swift-format')
|
config.swift_format = inferSwiftBinary('swift-format')
|
||||||
@@ -298,6 +299,7 @@ config.rth = os.path.join(config.swift_utils, 'rth') # Resilience test helper
|
|||||||
config.scale_test = os.path.join(config.swift_utils, 'scale-test')
|
config.scale_test = os.path.join(config.swift_utils, 'scale-test')
|
||||||
config.PathSanitizingFileCheck = os.path.join(config.swift_utils, 'PathSanitizingFileCheck')
|
config.PathSanitizingFileCheck = os.path.join(config.swift_utils, 'PathSanitizingFileCheck')
|
||||||
config.swift_lib_dir = os.path.join(os.path.dirname(os.path.dirname(config.swift)), 'lib')
|
config.swift_lib_dir = os.path.join(os.path.dirname(os.path.dirname(config.swift)), 'lib')
|
||||||
|
config.round_trip_syntax_test = os.path.join(config.swift_utils, 'round-trip-syntax-test')
|
||||||
|
|
||||||
# Find the resource directory. Assume it's near the swift compiler if not set.
|
# Find the resource directory. Assume it's near the swift compiler if not set.
|
||||||
test_resource_dir = lit_config.params.get('test_resource_dir')
|
test_resource_dir = lit_config.params.get('test_resource_dir')
|
||||||
@@ -365,6 +367,7 @@ config.substitutions.append( ('%sil-passpipeline-dumper', "%r" % (config.sil_pas
|
|||||||
config.substitutions.append( ('%lldb-moduleimport-test', "%r %s" % (config.lldb_moduleimport_test, mcp_opt)) )
|
config.substitutions.append( ('%lldb-moduleimport-test', "%r %s" % (config.lldb_moduleimport_test, mcp_opt)) )
|
||||||
config.substitutions.append( ('%swift-ide-test_plain', config.swift_ide_test) )
|
config.substitutions.append( ('%swift-ide-test_plain', config.swift_ide_test) )
|
||||||
config.substitutions.append( ('%swift-ide-test', "%r %s %s -swift-version %s" % (config.swift_ide_test, mcp_opt, ccp_opt, swift_version)) )
|
config.substitutions.append( ('%swift-ide-test', "%r %s %s -swift-version %s" % (config.swift_ide_test, mcp_opt, ccp_opt, swift_version)) )
|
||||||
|
config.substitutions.append( ('%swift-syntax-test', config.swift_syntax_test) )
|
||||||
config.substitutions.append( ('%swift-format', config.swift_format) )
|
config.substitutions.append( ('%swift-format', config.swift_format) )
|
||||||
config.substitutions.append( ('%llvm-link', config.llvm_link) )
|
config.substitutions.append( ('%llvm-link', config.llvm_link) )
|
||||||
config.substitutions.append( ('%swift-llvm-opt', config.swift_llvm_opt) )
|
config.substitutions.append( ('%swift-llvm-opt', config.swift_llvm_opt) )
|
||||||
@@ -999,6 +1002,7 @@ config.substitutions.append(
|
|||||||
config.substitutions.append(('%utils', config.swift_utils))
|
config.substitutions.append(('%utils', config.swift_utils))
|
||||||
config.substitutions.append(('%line-directive', config.line_directive))
|
config.substitutions.append(('%line-directive', config.line_directive))
|
||||||
config.substitutions.append(('%gyb', config.gyb))
|
config.substitutions.append(('%gyb', config.gyb))
|
||||||
|
config.substitutions.append(('%round-trip-syntax-test', config.round_trip_syntax_test))
|
||||||
config.substitutions.append(('%rth', config.rth))
|
config.substitutions.append(('%rth', config.rth))
|
||||||
config.substitutions.append(('%scale-test',
|
config.substitutions.append(('%scale-test',
|
||||||
'{} --swiftc-binary={} --tmpdir=%t'.format(
|
'{} --swiftc-binary={} --tmpdir=%t'.format(
|
||||||
|
|||||||
@@ -194,12 +194,9 @@ int doFullParseRoundTrip(const StringRef InputFilename) {
|
|||||||
if (NewNode.hasValue()) {
|
if (NewNode.hasValue()) {
|
||||||
NewNode.getValue().print(llvm::outs());
|
NewNode.getValue().print(llvm::outs());
|
||||||
auto Symbol = Sema.getNodeForSyntax(NewNode.getValue());
|
auto Symbol = Sema.getNodeForSyntax(NewNode.getValue());
|
||||||
assert(Symbol.hasValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sema.dumpSyntaxMap();
|
|
||||||
|
|
||||||
if (Tokens.back().first->getTokenKind() == tok::eof) {
|
if (Tokens.back().first->getTokenKind() == tok::eof) {
|
||||||
Tokens.back().first->print(llvm::outs());
|
Tokens.back().first->print(llvm::outs());
|
||||||
}
|
}
|
||||||
|
|||||||
165
utils/round-trip-syntax-test
Executable file
165
utils/round-trip-syntax-test
Executable file
@@ -0,0 +1,165 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
logging.basicConfig(format='%(message)s', level=logging.INFO)
|
||||||
|
|
||||||
|
class RoundTripTask(object):
|
||||||
|
def __init__(self, input_filename, action, swift_syntax_test, skip_bad_syntax):
|
||||||
|
assert action == '-round-trip-parse' or action == '-round-trip-lex'
|
||||||
|
assert type(input_filename) == unicode
|
||||||
|
assert type(swift_syntax_test) == str
|
||||||
|
assert os.path.isfile(input_filename), "Input file {} is not accessible!".format(input_filename)
|
||||||
|
assert os.path.isfile(swift_syntax_test), "{} tool is not accessible!".format(swift_syntax_test)
|
||||||
|
self.input_filename = input_filename
|
||||||
|
self.action = action
|
||||||
|
self.swift_syntax_test = swift_syntax_test
|
||||||
|
self.skip_bad_syntax = skip_bad_syntax
|
||||||
|
self.returncode = None
|
||||||
|
self.stdout = None
|
||||||
|
self.stderr = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def test_command(self):
|
||||||
|
return [
|
||||||
|
self.swift_syntax_test, self.action,
|
||||||
|
'-input-source-filename', self.input_filename
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def diff_command(self):
|
||||||
|
return ['/usr/bin/diff', '-u', self.input_filename, '-']
|
||||||
|
|
||||||
|
def diff(self):
|
||||||
|
logging.debug(' '.join(self.diff_command))
|
||||||
|
diff = subprocess.Popen(self.diff_command, stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
stdout, stderr = diff.communicate(self.stdout)
|
||||||
|
if diff.returncode != 0:
|
||||||
|
return stdout
|
||||||
|
assert stdout == ''
|
||||||
|
assert stderr == ''
|
||||||
|
return None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
command = self.test_command
|
||||||
|
logging.debug(' '.join(command))
|
||||||
|
self.output_file = tempfile.NamedTemporaryFile('w')
|
||||||
|
self.stderr_file = tempfile.NamedTemporaryFile('w')
|
||||||
|
|
||||||
|
process = subprocess.Popen(command, stdout=self.output_file,
|
||||||
|
stderr=self.stderr_file)
|
||||||
|
process.wait()
|
||||||
|
self.returncode = process.returncode
|
||||||
|
|
||||||
|
with open(self.output_file.name, 'r') as stdout_in:
|
||||||
|
self.stdout = stdout_in.read()
|
||||||
|
with open(self.stderr_file.name, 'r') as stderr_in:
|
||||||
|
self.stderr = stderr_in.read()
|
||||||
|
|
||||||
|
self.output_file.flush()
|
||||||
|
self.stderr_file.flush()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.returncode != 0:
|
||||||
|
if self.skip_bad_syntax:
|
||||||
|
logging.warning('---===WARNING===--- Lex/parse had error diagnostics, so not diffing. Skipping this file due to -skip-bad-syntax.')
|
||||||
|
logging.error(' '.join(command))
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
logging.error('---===ERROR===--- Lex/parse had error diagnostics, so not diffing.')
|
||||||
|
logging.error(' '.join(command))
|
||||||
|
logging.error(self.stdout)
|
||||||
|
logging.error(self.stderr)
|
||||||
|
raise RuntimeError()
|
||||||
|
finally:
|
||||||
|
self.output_file.close()
|
||||||
|
self.stderr_file.close()
|
||||||
|
|
||||||
|
diff = self.diff()
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def swift_files_in_dir(d):
|
||||||
|
swift_files = []
|
||||||
|
for root, dirs, files in os.walk(d):
|
||||||
|
for basename in files:
|
||||||
|
if not basename.decode('utf-8').endswith('.swift'):
|
||||||
|
continue
|
||||||
|
abs_file = os.path.abspath(os.path.join(root, basename))
|
||||||
|
swift_files.append(abs_file)
|
||||||
|
return swift_files
|
||||||
|
|
||||||
|
def run_task(task):
|
||||||
|
try:
|
||||||
|
diff = task.run()
|
||||||
|
if diff is not None:
|
||||||
|
logging.error('---===ERROR===--- Diff failed!')
|
||||||
|
logging.error(' '.join(task.test_command))
|
||||||
|
logging.error(diff)
|
||||||
|
logging.error('')
|
||||||
|
return True
|
||||||
|
except RuntimeError as e:
|
||||||
|
logging.error(e.message)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
tool_description='''
|
||||||
|
Checks for round-trip lex/parse/print compatibility.
|
||||||
|
|
||||||
|
Swift's syntax representation should be "full-fidelity", meaning that there is
|
||||||
|
a perfect representation of what is in the source. When printing a syntax tree
|
||||||
|
to a file, that file should be identical to the file that was
|
||||||
|
originally parsed.
|
||||||
|
|
||||||
|
This driver invokes swift-syntax-test using -round-trip-lex and -round-trip-parse
|
||||||
|
on .swift files and .swift files in directories.
|
||||||
|
'''
|
||||||
|
parser = argparse.ArgumentParser(description=tool_description)
|
||||||
|
parser.add_argument('--directory', '-d', action='append',
|
||||||
|
dest='input_directories', default=[],
|
||||||
|
help='Add a directory, searching for .swift files within')
|
||||||
|
parser.add_argument('--file', '-f', action='append',
|
||||||
|
dest='individual_input_files', default=[],
|
||||||
|
help='Add an individual file to test')
|
||||||
|
parser.add_argument('--swift-syntax-test', '-t', required=True,
|
||||||
|
dest='tool_path',
|
||||||
|
help='Absolute path to the swift-syntax-test tool')
|
||||||
|
parser.add_argument('--skip-bad-syntax',
|
||||||
|
action='store_true',
|
||||||
|
default=False,
|
||||||
|
help="Skip files that caused lex or parse diagnostics to be emitted")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
dir_listings = [swift_files_in_dir(d) for d in args.input_directories]
|
||||||
|
all_input_files = [filename for dir_listing in dir_listings
|
||||||
|
for filename in dir_listing]
|
||||||
|
all_input_files += args.individual_input_files
|
||||||
|
all_input_files = [f.decode('utf-8') for f in all_input_files]
|
||||||
|
|
||||||
|
if len(all_input_files) == 0:
|
||||||
|
logging.error('No input files!')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not os.path.isfile(args.tool_path):
|
||||||
|
raise RuntimeError("Couldn't find swift-syntax-test at {}".format(args.tool_path))
|
||||||
|
|
||||||
|
lex_tasks = [RoundTripTask(filename, '-round-trip-lex', args.tool_path, args.skip_bad_syntax)
|
||||||
|
for filename in all_input_files]
|
||||||
|
parse_tasks = [RoundTripTask(filename, '-round-trip-parse', args.tool_path, args.skip_bad_syntax)
|
||||||
|
for filename in all_input_files]
|
||||||
|
|
||||||
|
failed = reduce(lambda a,b: a and b,
|
||||||
|
map(run_task, lex_tasks + parse_tasks))
|
||||||
|
sys.exit(1 if failed else 0)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user