| // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:io' show exitCode, File, stdout; |
| |
| import 'package:front_end/src/api_prototype/compiler_options.dart'; |
| import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart'; |
| import 'package:front_end/src/api_prototype/memory_file_system.dart'; |
| import 'package:front_end/src/compute_platform_binaries_location.dart'; |
| import 'package:front_end/src/fasta/kernel/utils.dart'; |
| import 'package:front_end/src/fasta/messages.dart'; |
| import 'package:kernel/binary/ast_to_binary.dart'; |
| |
| import 'package:kernel/kernel.dart' show Component; |
| |
| import 'incremental_suite.dart' as helper; |
| |
| Future<void> main() async { |
| CompilerAndOptions compilerAndOptions = TestCompiler.initialize(); |
| TestCompiler compiler = compilerAndOptions.compiler; |
| bool hasNewline = true; |
| int numErrors = 0; |
| List<String> errorSource = []; |
| for (Generator outerContext in generateOuterContext()) { |
| for (Generator innerContext |
| in generateInnerContext(outerContext.typeParameters)) { |
| for (Generator expression in generateExpression([] |
| ..addAll(outerContext.typeParameters) |
| ..addAll(innerContext.typeParameters))) { |
| String source = outerContext |
| .generate(innerContext.generate(expression.generate(""))); |
| String compileResult = await compiler.compile(source); |
| compilerAndOptions.options.skipPlatformVerification = true; |
| if (compileResult != "") { |
| if (!hasNewline) print(""); |
| hasNewline = true; |
| print(source); |
| print(compileResult); |
| print("\n\n----------\n\n"); |
| numErrors++; |
| errorSource.add(source); |
| } else { |
| hasNewline = false; |
| stdout.write("."); |
| } |
| } |
| } |
| } |
| |
| if (numErrors > 0) { |
| if (!hasNewline) print(""); |
| hasNewline = true; |
| print("Found $numErrors errors on these programs:"); |
| print(""); |
| for (String source in errorSource) { |
| print(source); |
| print("----"); |
| } |
| exitCode = 1; |
| } |
| if (!hasNewline) print(""); |
| } |
| |
| const Set<Code> ignoredCodes = { |
| codeInvalidAssignmentError, |
| codeTypeVariableInStaticContext, |
| codeExtensionDeclaresInstanceField, |
| codeExtraneousModifier, |
| }; |
| |
| class TestCompiler { |
| final Uri testUri; |
| final MemoryFileSystem fs; |
| final Set<String> formattedErrors; |
| final Set<String> formattedWarnings; |
| final helper.TestIncrementalCompiler compiler; |
| final List<Code> formattedErrorsCodes; |
| final List<Code> formattedWarningsCodes; |
| |
| TestCompiler._( |
| this.testUri, |
| this.fs, |
| this.formattedErrors, |
| this.formattedWarnings, |
| this.formattedErrorsCodes, |
| this.formattedWarningsCodes, |
| this.compiler); |
| |
| Future<String> compile(String src) async { |
| StringBuffer sb = new StringBuffer(); |
| fs.entityForUri(testUri).writeAsStringSync(src); |
| compiler.invalidate(testUri); |
| IncrementalCompilerResult compilerResult = |
| await compiler.computeDelta(entryPoints: [testUri]); |
| Component result = compilerResult.component; |
| Iterator<Code> codeIterator = formattedWarningsCodes.iterator; |
| for (String warning in formattedWarnings) { |
| codeIterator.moveNext(); |
| Code code = codeIterator.current; |
| if (ignoredCodes.contains(code)) continue; |
| sb.writeln("Warning: $warning ($code)"); |
| } |
| codeIterator = formattedErrorsCodes.iterator; |
| for (String error in formattedErrors) { |
| codeIterator.moveNext(); |
| Code code = codeIterator.current; |
| if (ignoredCodes.contains(code)) continue; |
| sb.writeln("Error: $error ($code)"); |
| } |
| formattedWarnings.clear(); |
| formattedWarningsCodes.clear(); |
| formattedErrors.clear(); |
| formattedErrorsCodes.clear(); |
| |
| try { |
| ByteSink byteSink = new ByteSink(); |
| final BinaryPrinter printer = new BinaryPrinter(byteSink); |
| printer.writeComponentFile(result); |
| } catch (e, st) { |
| sb.writeln("Error: Crash when serializing: $e ($st)"); |
| } |
| |
| return sb.toString(); |
| } |
| |
| static CompilerAndOptions initialize() { |
| final Uri base = Uri.parse("org-dartlang-test:///"); |
| final Uri sdkSummary = base.resolve("vm_platform_strong.dill"); |
| final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true); |
| Uri platformUri = sdkRoot.resolve("vm_platform_strong.dill"); |
| final List<int> sdkSummaryData = |
| new File.fromUri(platformUri).readAsBytesSync(); |
| MemoryFileSystem fs = new MemoryFileSystem(base); |
| fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData); |
| |
| CompilerOptions options = helper.getOptions(); |
| options.fileSystem = fs; |
| options.sdkRoot = null; |
| options.sdkSummary = sdkSummary; |
| options.omitPlatform = true; |
| options.verify = true; |
| |
| final Set<String> formattedErrors = new Set<String>(); |
| final Set<String> formattedWarnings = new Set<String>(); |
| final List<Code> formattedErrorsCodes = <Code>[]; |
| final List<Code> formattedWarningsCodes = <Code>[]; |
| |
| options.onDiagnostic = (DiagnosticMessage message) { |
| String stringId = message.ansiFormatted.join("\n"); |
| if (message is FormattedMessage) { |
| stringId = message.toJsonString(); |
| } else { |
| throw "Unsupported currently"; |
| } |
| FormattedMessage formattedMessage = message; |
| if (message.severity == Severity.error) { |
| if (!formattedErrors.add(stringId)) { |
| throw "Got the same message twice: ${stringId}"; |
| } |
| formattedErrorsCodes.add(formattedMessage.code); |
| } else if (message.severity == Severity.warning) { |
| if (!formattedWarnings.add(stringId)) { |
| throw "Got the same message twice: ${stringId}"; |
| } |
| formattedWarningsCodes.add(formattedMessage.code); |
| } |
| }; |
| |
| Uri testUri = base.resolve("test.dart"); |
| helper.TestIncrementalCompiler compiler = |
| new helper.TestIncrementalCompiler(options, testUri); |
| |
| return new CompilerAndOptions( |
| new TestCompiler._(testUri, fs, formattedErrors, formattedWarnings, |
| formattedErrorsCodes, formattedWarningsCodes, compiler), |
| options); |
| } |
| } |
| |
| Iterable<Generator> generateOuterContext() sync* { |
| yield new Generator([], "", ""); // top-level. |
| yield new Generator([], "class C {\n", "\n}"); |
| yield new Generator(["T1"], "class C<T1> {\n", "\n}"); |
| yield new Generator(["T1"], |
| "class NotList<NT1>{}\nclass C<T1> extends NotList<T1> {\n", "\n}"); |
| yield new Generator([], "extension E on String {\n", "\n}"); |
| yield new Generator(["E1"], "extension E<E1> on String {\n", "\n}"); |
| yield new Generator(["E1"], "extension E<E1> on List<E1> {\n", "\n}"); |
| } |
| |
| Iterable<Generator> generateInnerContext( |
| List<String> knownTypeParameters) sync* { |
| for (String static in ["", "static "]) { |
| yield new Generator([], "${static}int method() {\nreturn ", ";\n}"); |
| yield new Generator( |
| ["T2"], "${static}int method<T2>() {\n return ", ";\n}"); |
| for (String typeParameter in knownTypeParameters) { |
| yield new Generator( |
| [], "${static}$typeParameter method() {\nreturn ", ";\n}"); |
| } |
| yield new Generator([], "${static}int field = ", ";"); |
| yield new Generator([], "${static}int field = () { return ", "; }();"); |
| yield new Generator([], "${static}var field = ", ";"); |
| yield new Generator([], "${static}var field = () { return ", "; }();"); |
| |
| for (String typeParameter in knownTypeParameters) { |
| yield new Generator(["T2"], "${static}int field = <T2>() { return ", |
| "; }<$typeParameter>();"); |
| yield new Generator([], "${static}${typeParameter} field = ", ";"); |
| yield new Generator( |
| [], "${static}${typeParameter} field = () { return ", "; }();"); |
| } |
| } |
| } |
| |
| Iterable<Generator> generateExpression(List<String> knownTypeParameters) sync* { |
| yield new Generator([], "42", ""); |
| for (String typeParameter in knownTypeParameters) { |
| yield new Generator([], "() { $typeParameter x = null; return x; }()", ""); |
| } |
| } |
| |
| class Generator { |
| final List<String> typeParameters; |
| final String beforePlug; |
| final String afterPlug; |
| |
| Generator(this.typeParameters, this.beforePlug, this.afterPlug); |
| |
| String generate(String plug) { |
| return "// @dart = 2.9\n${beforePlug}${plug}${afterPlug}"; |
| } |
| } |
| |
| class CompilerAndOptions { |
| final TestCompiler compiler; |
| final CompilerOptions options; |
| |
| CompilerAndOptions(this.compiler, this.options); |
| } |