| // Copyright (c) 2017, 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:async'; | |
| import 'package:front_end/src/api_prototype/byte_store.dart'; | |
| import 'package:front_end/src/api_prototype/compiler_options.dart'; | |
| import 'package:front_end/src/api_prototype/memory_file_system.dart'; | |
| import 'package:front_end/src/api_prototype/summary_generator.dart'; | |
| import 'package:front_end/src/base/performance_logger.dart'; | |
| import 'package:front_end/src/base/processed_options.dart'; | |
| import 'package:front_end/src/fasta/kernel/utils.dart'; | |
| import 'package:front_end/src/fasta/uri_translator_impl.dart'; | |
| import 'package:front_end/src/incremental/kernel_driver.dart'; | |
| import 'package:kernel/ast.dart'; | |
| import 'package:kernel/binary/ast_from_binary.dart'; | |
| import 'package:kernel/target/targets.dart'; | |
| import 'package:kernel/text/ast_to_text.dart'; | |
| import 'package:kernel/verifier.dart'; | |
| import 'package:package_config/src/packages_impl.dart'; | |
| import 'package:test/test.dart'; | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| import 'mock_sdk.dart'; | |
| main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(KernelDriverTest); | |
| }); | |
| } | |
| @reflectiveTest | |
| class KernelDriverTest { | |
| /// Virtual filesystem for testing. | |
| final fileSystem = new MemoryFileSystem(Uri.parse('org-dartlang-test:///')); | |
| /// The object under test. | |
| KernelDriver driver; | |
| void setUp() { | |
| _createDriver(); | |
| } | |
| test_getKernel_chain() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| Uri aUri = writeFile(aPath, 'var a = 1;'); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'a.dart'; | |
| var b = a; | |
| '''); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'a.dart'; | |
| import 'b.dart'; | |
| var c1 = a; | |
| var c2 = b; | |
| '''); | |
| { | |
| KernelResult result = await driver.getKernel(cUri); | |
| _assertKernelResult(result, cUri, | |
| includes: [aUri, bUri, Uri.parse('dart:core')]); | |
| expect(_getLibraryText(result.libraryResult.library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field core::int c1 = a::a; | |
| static field core::int c2 = b::b; | |
| '''); | |
| } | |
| // Update b.dart and recompile c.dart | |
| writeFile(bPath, r''' | |
| import 'a.dart'; | |
| var b = 1.2; | |
| '''); | |
| driver.invalidate(bUri); | |
| { | |
| KernelResult result = await driver.getKernel(cUri); | |
| _assertKernelResult(result, cUri, | |
| includes: [aUri, bUri, Uri.parse('dart:core')]); | |
| expect(_getLibraryText(result.libraryResult.library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field core::int c1 = a::a; | |
| static field core::double c2 = b::b; | |
| '''); | |
| } | |
| } | |
| test_getKernel_cycle() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| Uri aUri = writeFile(aPath, 'var a = 1;'); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'c.dart'; | |
| var b1 = c1; | |
| var b2 = c2; | |
| '''); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'a.dart'; | |
| import 'b.dart'; | |
| var c1 = a; | |
| var c2 = b1; | |
| '''); | |
| { | |
| KernelResult result = await driver.getKernel(cUri); | |
| // b.dart and c.dart form a cycle. | |
| // We still get c.dart as the library, and b.dart in dependencies. | |
| _assertKernelResult(result, cUri, | |
| includes: [aUri, bUri, Uri.parse('dart:core')]); | |
| expect(_getLibraryText(result.libraryResult.library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field core::int c1 = a::a; | |
| static field core::int c2 = b::b1; | |
| '''); | |
| } | |
| // Update a.dart and recompile c.dart | |
| writeFile(aPath, r''' | |
| var a = 1.2; | |
| '''); | |
| driver.invalidate(aUri); | |
| { | |
| KernelResult result = await driver.getKernel(cUri); | |
| _assertKernelResult(result, cUri, | |
| includes: [aUri, bUri, Uri.parse('dart:core')]); | |
| expect(_getLibraryText(result.libraryResult.library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field core::double c1 = a::a; | |
| static field core::double c2 = b::b1; | |
| '''); | |
| } | |
| } | |
| test_getKernelSequence_chain() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| Uri aUri = writeFile(aPath, 'var a = 1;'); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'a.dart'; | |
| var b = a; | |
| '''); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'a.dart'; | |
| import 'b.dart'; | |
| var c1 = a; | |
| var c2 = b; | |
| void main() {} | |
| '''); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| _assertLibraryUris(result, | |
| includes: [aUri, bUri, cUri, Uri.parse('dart:core')]); | |
| Library library = _getLibrary(result, cUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field core::int c1 = a::a; | |
| static field core::int c2 = b::b; | |
| static method main() → void {} | |
| '''); | |
| } | |
| // Update b.dart and recompile c.dart | |
| writeFile(bPath, r''' | |
| import 'a.dart'; | |
| var b = 1.2; | |
| '''); | |
| driver.invalidate(bUri); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| _assertLibraryUris(result, | |
| includes: [aUri, bUri, cUri, Uri.parse('dart:core')]); | |
| Library library = _getLibrary(result, cUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field core::int c1 = a::a; | |
| static field core::double c2 = b::b; | |
| static method main() → void {} | |
| '''); | |
| } | |
| } | |
| test_getKernelSequence_export() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| String dPath = '/test/lib/d.dart'; | |
| writeFile(aPath, 'class A {}'); | |
| Uri bUri = writeFile(bPath, 'export "a.dart";'); | |
| Uri cUri = writeFile(cPath, 'export "b.dart";'); | |
| Uri dUri = writeFile(dPath, r''' | |
| import 'c.dart'; | |
| A a; | |
| '''); | |
| KernelSequenceResult result = await driver.getKernelSequence(dUri); | |
| Library library = _getLibrary(result, dUri); | |
| expect(_getLibraryText(_getLibrary(result, bUri)), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| additionalExports = (a::A) | |
| '''); | |
| expect(_getLibraryText(_getLibrary(result, cUri)), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| additionalExports = (a::A) | |
| '''); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| static field a::A a; | |
| '''); | |
| } | |
| test_getKernelSequence_export_cycle() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| writeFile(aPath, 'export "b.dart"; class A {}'); | |
| writeFile(bPath, 'export "a.dart"; class B {}'); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'b.dart'; | |
| A a; | |
| B b; | |
| '''); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| Library library = _getLibrary(result, cUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field a::A a; | |
| static field b::B b; | |
| '''); | |
| } | |
| // Update c.dart and compile. | |
| // We should load the cycle [a.dart, b.dart] from the byte store. | |
| // This tests that we compute export scopes after loading. | |
| writeFile(cPath, r''' | |
| import 'b.dart'; | |
| A a; | |
| B b; | |
| int c; | |
| '''); | |
| driver.invalidate(cUri); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| Library library = _getLibrary(result, cUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| import "dart:core" as core; | |
| static field a::A a; | |
| static field b::B b; | |
| static field core::int c; | |
| '''); | |
| } | |
| } | |
| test_getKernelSequence_export_hideWithLocal() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| writeFile(aPath, 'class A {} class B {}'); | |
| writeFile(bPath, 'export "a.dart"; class B {}'); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'b.dart'; | |
| A a; | |
| B b; | |
| '''); | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| Library library = _getLibrary(result, cUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| import "./b.dart" as b; | |
| static field a::A a; | |
| static field b::B b; | |
| '''); | |
| } | |
| test_getKernelSequence_recompileMixin() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| Uri aUri = writeFile(aPath, r''' | |
| import 'b.dart'; | |
| main() { | |
| new B().foo(); | |
| } | |
| '''); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'c.dart'; | |
| class B extends Object with C {} | |
| '''); | |
| Uri cUri = writeFile(cPath, r''' | |
| class C { | |
| void foo() { | |
| print(0); | |
| } | |
| } | |
| '''); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(aUri); | |
| _assertLibraryUris(result, | |
| includes: [aUri, bUri, cUri, Uri.parse('dart:core')]); | |
| } | |
| // Update c.dart and compute the delta. | |
| // Includes: c.dart, b.dart and a.dart files. | |
| // Compiled: c.dart (changed) and b.dart (has mixin), but not a.dart file. | |
| writeFile(cPath, r''' | |
| class C { | |
| void foo() { | |
| print(1); | |
| } | |
| } | |
| '''); | |
| driver.invalidate(cUri); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(aUri); | |
| _assertLibraryUris(result, | |
| includes: [aUri, bUri, cUri, Uri.parse('dart:core')]); | |
| // Compiled: c.dart (changed), and b.dart (has mixin). | |
| _assertCompiledUris(includes: [cUri, bUri], excludes: [aUri]); | |
| } | |
| } | |
| test_getKernelSequence_redirectingConstructor() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| writeFile(aPath, r''' | |
| class A { | |
| factory A() = B; | |
| } | |
| class B implements A { | |
| B(); | |
| } | |
| '''); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'a.dart'; | |
| var a = new A(); | |
| '''); | |
| // Initially "new A()" is resolved to "new B()". | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(bUri); | |
| Library library = _getLibrary(result, bUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| static field a::A a = new a::B::•(); | |
| '''); | |
| } | |
| // Update b.dart and recompile. | |
| // We should not lose information about redirecting constructors. | |
| // Som "new A()" should still be resolved to "new B()". | |
| writeFile(bPath, r''' | |
| import 'a.dart'; | |
| var a2 = new A(); | |
| '''); | |
| driver.invalidate(bUri); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(bUri); | |
| Library library = _getLibrary(result, bUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "./a.dart" as a; | |
| static field a::A a2 = new a::B::•(); | |
| '''); | |
| } | |
| } | |
| test_getKernelSequence_typedef() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| writeFile(aPath, 'typedef int F<T>(T x);'); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'a.dart'; | |
| F<String> f; | |
| '''); | |
| KernelSequenceResult result = await driver.getKernelSequence(bUri); | |
| Library library = _getLibrary(result, bUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| static field (core::String) → core::int f; | |
| '''); | |
| } | |
| test_getKernelSequence_typedef_storeReference() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| writeFile(aPath, 'typedef int F();'); | |
| writeFile(bPath, r''' | |
| import 'a.dart'; | |
| F f; | |
| '''); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'b.dart'; | |
| var fc = f; | |
| '''); | |
| // Compile first time, b.dart should store F typedef reference. | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| Library library = _getLibrary(result, cUri); | |
| expect((library.fields[0].type as FunctionType).typedef.name, 'F'); | |
| } | |
| // Update c.dart and recompile using the serialized b.dart kernel. | |
| // We should be able to read the F typedef reference. | |
| { | |
| writeFile(cPath, r''' | |
| import 'b.dart'; | |
| var fc2 = f; | |
| '''); | |
| driver.invalidate(cUri); | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| Library library = _getLibrary(result, cUri); | |
| expect((library.fields[0].type as FunctionType).typedef.name, 'F'); | |
| } | |
| } | |
| test_getKernelSequence_typeEnvironment() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| Uri aUri = writeFile(aPath, 'class A {}'); | |
| KernelSequenceResult result = await driver.getKernelSequence(aUri); | |
| expect(result.types.coreTypes.intClass, isNotNull); | |
| expect(result.types.hierarchy, isNotNull); | |
| } | |
| test_getKernelSequence_useSdkOutline() async { | |
| List<int> sdkOutlineBytes = await _computeSdkOutlineBytes(); | |
| // Configure the driver to use the SDK outline. | |
| _createDriver(sdkOutlineBytes: sdkOutlineBytes); | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| Uri aUri = writeFile(aPath, r''' | |
| int getValue() { | |
| return 1; | |
| } | |
| '''); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'dart:async'; | |
| import 'a.dart'; | |
| var a = 1; | |
| Future<String> b; | |
| '''); | |
| KernelSequenceResult result = await driver.getKernelSequence(bUri); | |
| // SDK libraries were not compiled. | |
| _assertCompiledUris( | |
| includes: [bUri], | |
| excludes: [Uri.parse('dart:core'), Uri.parse('dart:async')]); | |
| _assertLibraryUris(result, includes: [aUri, bUri]); | |
| // The types of top-level variables are resolved. | |
| var library = _getLibrary(result, bUri); | |
| expect(library.fields[0].type.toString(), 'dart.core::int'); | |
| expect(library.fields[1].type.toString(), | |
| 'dart.async::Future<dart.core::String>'); | |
| { | |
| // Update a.dart and recompile. | |
| writeFile(aPath, r''' | |
| int getValue() { | |
| return 2; | |
| } | |
| '''); | |
| driver.invalidate(aUri); | |
| var kernelResult = await driver.getKernelSequence(bUri); | |
| var allLibraries = kernelResult.results | |
| .map((c) => c.libraryResults.map((result) => result.library)) | |
| .expand((libs) => libs) | |
| .toList(); | |
| // The result does not include SDK libraries. | |
| _assertCompiledUris( | |
| includes: [aUri], | |
| excludes: [Uri.parse('dart:core'), Uri.parse('dart:async')]); | |
| _assertLibraryUris(result, includes: [aUri, bUri]); | |
| // The types of top-level variables are resolved. | |
| var library = _getLibrary(result, bUri); | |
| expect(library.fields[0].type.toString(), 'dart.core::int'); | |
| expect(library.fields[1].type.toString(), | |
| 'dart.async::Future<dart.core::String>'); | |
| // We should be able to serialize the libraries without SDK. | |
| var component = new Component( | |
| nameRoot: kernelResult.nameRoot, libraries: allLibraries); | |
| serializeComponent(component, | |
| filter: (library) => !library.importUri.isScheme('dart')); | |
| } | |
| // Ask dart:core, should be served from the outline. | |
| { | |
| var dartCoreUri = Uri.parse('dart:core'); | |
| var kernelResult = await driver.getKernelSequence(dartCoreUri); | |
| bool hasDartCore = false; | |
| for (var libraryResult in kernelResult.results) { | |
| for (var libResult in libraryResult.libraryResults) { | |
| if (libResult.library.importUri == dartCoreUri) { | |
| hasDartCore = true; | |
| break; | |
| } | |
| } | |
| } | |
| expect(hasDartCore, isTrue); | |
| } | |
| } | |
| test_limitedStore_exportDependencies() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| Uri aUri = writeFile(aPath, 'class A {}'); | |
| var bUri = writeFile(bPath, 'export "a.dart";'); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'b.dart'; | |
| A a; | |
| '''); | |
| // Compile all libraries initially. | |
| await driver.getKernelSequence(cUri); | |
| // Update c.dart and compile. | |
| // When we load "b", we should correctly read its exports. | |
| writeFile(cPath, r''' | |
| import 'b.dart'; | |
| A a2; | |
| '''); | |
| driver.invalidate(cUri); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(cUri); | |
| Library library = _getLibrary(result, cUri); | |
| Library getDepLib(Library lib, int index) { | |
| return lib.dependencies[index].importedLibraryReference.asLibrary; | |
| } | |
| var b = getDepLib(library, 0); | |
| var a = getDepLib(b, 0); | |
| expect(b.importUri, bUri); | |
| expect(a.importUri, aUri); | |
| } | |
| } | |
| test_limitedStore_memberReferences() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| writeFile(aPath, r''' | |
| int topField = 0; | |
| int get topGetter => 0; | |
| int topFunction({p}) => 0; | |
| abstract class I { | |
| int interfaceField; | |
| int get interfaceGetter; | |
| int interfaceMethod(); | |
| } | |
| class A implements I { | |
| static int staticField; | |
| static int get staticGetter => 0; | |
| static int staticMethod() => 0; | |
| int instanceField; | |
| int get instanceGetter => 0; | |
| int instanceMethod() => 0; | |
| int interfaceField; | |
| int get interfaceGetter => 0; | |
| int interfaceMethod() => 0; | |
| A(); | |
| A.named(); | |
| } | |
| '''); | |
| Uri bUri = writeFile(bPath, r''' | |
| import 'a.dart'; | |
| class B extends A { | |
| B() : super(); | |
| B.named() : super.named(); | |
| void foo() { | |
| super.instanceMethod(); | |
| instanceMethod(); | |
| super.interfaceField; | |
| super.interfaceField = 0; | |
| super.interfaceGetter; | |
| super.interfaceMethod(); | |
| } | |
| int instanceMethod() => 0; | |
| int interfaceField; | |
| int get interfaceGetter => 0; | |
| int interfaceMethod() => 0; | |
| } | |
| main() { | |
| topField; | |
| topField = 0; | |
| var v1 = topGetter; | |
| var v2 = topFunction(p: 0); | |
| A.staticField; | |
| A.staticField = 0; | |
| var v3 = A.staticGetter; | |
| var v4 = A.staticMethod(); | |
| var a = new A(); | |
| a.instanceField; | |
| a.instanceField = 0; | |
| var v5 = a.instanceGetter; | |
| var v6 = a.instanceMethod(); | |
| a.interfaceField; | |
| a.interfaceField = 0; | |
| var v7 = a.interfaceGetter; | |
| var v8 = a.interfaceMethod(); | |
| } | |
| '''); | |
| KernelSequenceResult result = await driver.getKernelSequence(bUri); | |
| Component component = new Component( | |
| nameRoot: result.nameRoot, libraries: _allLibraries(result)); | |
| String initialKernelText; | |
| List<int> bytes; | |
| { | |
| Library initialLibrary = _getLibraryFromComponent(component, bUri); | |
| initialKernelText = _getLibraryText(initialLibrary); | |
| bytes = serializeComponent(component, | |
| filter: (library) => library.importUri == bUri); | |
| // Remove b.dart from the component. | |
| // So, the component is now ready for re-adding the library. | |
| component.mainMethod = null; | |
| component.libraries.remove(initialLibrary); | |
| component.root.removeChild(initialLibrary.importUri.toString()); | |
| } | |
| // Load b.dart from bytes using the initial name root, so that | |
| // serialized canonical names can be linked to corresponding nodes. | |
| Library loadedLibrary; | |
| { | |
| var componentForLoading = new Component(nameRoot: component.root); | |
| var reader = new BinaryBuilder(bytes); | |
| reader.readComponent(componentForLoading); | |
| loadedLibrary = _getLibraryFromComponent(componentForLoading, bUri); | |
| } | |
| // Add the library into the component. | |
| component.libraries.add(loadedLibrary); | |
| loadedLibrary.parent = component; | |
| component.mainMethod = loadedLibrary.procedures | |
| .firstWhere((procedure) => procedure.name.name == 'main'); | |
| expect(_getLibraryText(loadedLibrary), initialKernelText); | |
| verifyComponent(component); | |
| } | |
| test_updatePackageSourceUsingFileUri() async { | |
| _createDriver(packages: {'test': _folderUri('/test/lib')}); | |
| writeFile('/test/.packages', 'test:lib/'); | |
| Uri aFileUri = writeFile('/test/bin/a.dart', r''' | |
| import 'package:test/b.dart'; | |
| var a = b; | |
| '''); | |
| Uri bFileUri = writeFile('/test/lib/b.dart', 'var b = 1;'); | |
| Uri bPackageUri = Uri.parse('package:test/b.dart'); | |
| // Compute the initial state. | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(aFileUri); | |
| Library library = _getLibrary(result, aFileUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "package:test/b.dart" as b; | |
| static field core::int a = b::b; | |
| '''); | |
| } | |
| // Update b.dart and use file URI to invalidate it. | |
| // The delta is recomputed even though b.dart is used with the package URI. | |
| writeFile('/test/lib/b.dart', 'var b = 1.2;'); | |
| driver.invalidate(bFileUri); | |
| { | |
| KernelSequenceResult result = await driver.getKernelSequence(aFileUri); | |
| _assertLibraryUris(result, includes: [aFileUri, bPackageUri]); | |
| Library library = _getLibrary(result, aFileUri); | |
| expect(_getLibraryText(library), r''' | |
| library; | |
| import self as self; | |
| import "dart:core" as core; | |
| import "package:test/b.dart" as b; | |
| static field core::double a = b::b; | |
| '''); | |
| } | |
| } | |
| test_updatePart() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String libPath = '/test/lib/test.dart'; | |
| String partPath = '/test/lib/bar.dart'; | |
| Uri libUri = writeFile(libPath, r''' | |
| library foo; | |
| part 'bar.dart'; | |
| var a = 1; | |
| var c = b; | |
| void main() {} | |
| '''); | |
| Uri partUri = writeFile(partPath, r''' | |
| part of foo; | |
| var b = 2; | |
| var d = a; | |
| '''); | |
| // Check the initial state - types flow between the part and the library. | |
| KernelSequenceResult result = await driver.getKernelSequence(libUri); | |
| Library library = _getLibrary(result, libUri); | |
| expect(_getLibraryText(library), r''' | |
| library foo; | |
| import self as self; | |
| import "dart:core" as core; | |
| static field core::int a = 1; | |
| static field core::int c = self::b; | |
| static field core::int b = 2 /* from org-dartlang-test:///test/lib/bar.dart */; | |
| static field core::int d = self::a /* from org-dartlang-test:///test/lib/bar.dart */; | |
| static method main() → void {} | |
| '''); | |
| // Update [b] in the part, the type is changed in the part and library. | |
| { | |
| writeFile(partPath, r''' | |
| part of foo; | |
| var b = 2.3; | |
| var d = a; | |
| '''); | |
| driver.invalidate(partUri); | |
| KernelSequenceResult result = await driver.getKernelSequence(libUri); | |
| Library library = _getLibrary(result, libUri); | |
| expect(_getLibraryText(library), r''' | |
| library foo; | |
| import self as self; | |
| import "dart:core" as core; | |
| static field core::int a = 1; | |
| static field core::double c = self::b; | |
| static field core::double b = 2.3 /* from org-dartlang-test:///test/lib/bar.dart */; | |
| static field core::int d = self::a /* from org-dartlang-test:///test/lib/bar.dart */; | |
| static method main() → void {} | |
| '''); | |
| } | |
| // Update [a] in the library, the type is changed in the part and library. | |
| { | |
| writeFile(libPath, r''' | |
| library foo; | |
| part 'bar.dart'; | |
| var a = 'aaa'; | |
| var c = b; | |
| void main() {} | |
| '''); | |
| driver.invalidate(libUri); | |
| KernelSequenceResult result = await driver.getKernelSequence(libUri); | |
| Library library = _getLibrary(result, libUri); | |
| expect(_getLibraryText(library), r''' | |
| library foo; | |
| import self as self; | |
| import "dart:core" as core; | |
| static field core::String a = "aaa"; | |
| static field core::double c = self::b; | |
| static field core::double b = 2.3 /* from org-dartlang-test:///test/lib/bar.dart */; | |
| static field core::String d = self::a /* from org-dartlang-test:///test/lib/bar.dart */; | |
| static method main() → void {} | |
| '''); | |
| } | |
| } | |
| test_watch() async { | |
| writeFile('/test/.packages', 'test:lib/'); | |
| String aPath = '/test/lib/a.dart'; | |
| String bPath = '/test/lib/b.dart'; | |
| String cPath = '/test/lib/c.dart'; | |
| Uri aUri = writeFile(aPath, ''); | |
| Uri bUri = writeFile(bPath, ''); | |
| Uri cUri = writeFile(cPath, r''' | |
| import 'a.dart'; | |
| '''); | |
| var usedFiles = <Uri>[]; | |
| _createDriver(fileAddedFn: (Uri uri) { | |
| usedFiles.add(uri); | |
| return new Future.value(); | |
| }); | |
| { | |
| await driver.getKernelSequence(cUri); | |
| // We use at least c.dart and a.dart now. | |
| expect(usedFiles, contains(cUri)); | |
| expect(usedFiles, contains(aUri)); | |
| usedFiles.clear(); | |
| } | |
| // Update c.dart to reference also b.dart file. | |
| writeFile(cPath, r''' | |
| import 'a.dart'; | |
| import 'b.dart'; | |
| '''); | |
| driver.invalidate(cUri); | |
| { | |
| await driver.getKernelSequence(cUri); | |
| // The only new file is b.dart now. | |
| expect(usedFiles, [bUri]); | |
| usedFiles.clear(); | |
| } | |
| } | |
| /// Write the given [text] of the file with the given [path] into the | |
| /// virtual filesystem. Return the URI of the file. | |
| Uri writeFile(String path, String text) { | |
| Uri uri = Uri.parse('org-dartlang-test://$path'); | |
| fileSystem.entityForUri(uri).writeAsStringSync(text); | |
| return uri; | |
| } | |
| List<Library> _allLibraries(KernelSequenceResult result) { | |
| return result.results | |
| .map((cycle) => cycle.libraryResults.map((result) => result.library)) | |
| .expand((libraries) => libraries) | |
| .toList(); | |
| } | |
| void _assertCompiledUris( | |
| {Iterable<Uri> includes: const [], Iterable<Uri> excludes: const []}) { | |
| var compiledCycles = driver.test.compiledCycles; | |
| Set<Uri> compiledUris = compiledCycles | |
| .map((cycle) => cycle.libraries.map((file) => file.uri)) | |
| .expand((uris) => uris) | |
| .toSet(); | |
| for (var shouldInclude in includes) { | |
| expect(compiledUris, contains(shouldInclude)); | |
| } | |
| for (var shouldExclude in excludes) { | |
| expect(compiledUris, isNot(contains(shouldExclude))); | |
| } | |
| } | |
| void _assertKernelResult(KernelResult result, Uri libraryUri, | |
| {List<Uri> includes: const [], List<Uri> excludes: const []}) { | |
| expect(result.libraryResult?.library, isNotNull); | |
| expect(result.libraryResult.library.importUri, libraryUri); | |
| List<Uri> dependencyUris = []; | |
| for (var library in result.dependencies) { | |
| dependencyUris.add(library.importUri); | |
| } | |
| for (var shouldInclude in includes) { | |
| expect(dependencyUris, contains(shouldInclude)); | |
| } | |
| for (var shouldExclude in excludes) { | |
| expect(dependencyUris, isNot(contains(shouldExclude))); | |
| } | |
| } | |
| void _assertLibraryUris(KernelSequenceResult result, | |
| {List<Uri> includes: const [], List<Uri> excludes: const []}) { | |
| Map<Uri, Source> uriToSource = {}; | |
| List<Uri> libraryUris = []; | |
| for (LibraryCycleResult cycleResult in result.results) { | |
| uriToSource.addAll(cycleResult.uriToSource); | |
| for (var result in cycleResult.libraryResults) { | |
| libraryUris.add(result.library.importUri); | |
| } | |
| } | |
| for (var shouldInclude in includes) { | |
| expect(libraryUris, contains(shouldInclude)); | |
| var shouldIncludeFileUri = _resolveUriToFileUri(shouldInclude); | |
| expect(uriToSource.keys, contains(shouldIncludeFileUri)); | |
| } | |
| for (var shouldExclude in excludes) { | |
| expect(libraryUris, isNot(contains(shouldExclude))); | |
| var shouldExcludeFileUri = _resolveUriToFileUri(shouldExclude); | |
| expect(uriToSource.keys, isNot(contains(shouldExcludeFileUri))); | |
| } | |
| } | |
| Future<List<int>> _computeSdkOutlineBytes() async { | |
| var options = new CompilerOptions() | |
| ..fileSystem = fileSystem | |
| ..sdkRoot = Uri.parse('org-dartlang-test:///sdk/') | |
| ..compileSdk = true | |
| ..strongMode = true | |
| ..target = new NoneTarget(new TargetFlags(strongMode: true)); | |
| var inputs = [Uri.parse('dart:core')]; | |
| return summaryFor(inputs, options); | |
| } | |
| /// Create new [KernelDriver] instance and put it into the [driver] field. | |
| void _createDriver( | |
| {List<int> sdkOutlineBytes, | |
| Map<String, Uri> packages, | |
| KernelDriverFileAddedFn fileAddedFn}) { | |
| var uriTranslator = new UriTranslatorImpl( | |
| createSdkFiles(fileSystem), new MapPackages(packages)); | |
| var options = new CompilerOptions() | |
| ..logger = new PerformanceLog(null) | |
| ..fileSystem = fileSystem | |
| ..byteStore = new MemoryByteStore() | |
| ..strongMode = true | |
| ..target = new NoneTarget(new TargetFlags(strongMode: true)); | |
| driver = new KernelDriver( | |
| new ProcessedOptions(options), uriTranslator, new KernelErrorListener(), | |
| sdkOutlineBytes: sdkOutlineBytes, fileAddedFn: fileAddedFn); | |
| } | |
| Library _getLibrary(KernelSequenceResult result, Uri uri) { | |
| for (var cycleResult in result.results) { | |
| for (var result in cycleResult.libraryResults) { | |
| if (result.library.importUri == uri) return result.library; | |
| } | |
| } | |
| fail('No library found with URI "$uri"'); | |
| } | |
| Library _getLibraryFromComponent(Component component, Uri uri) { | |
| for (var library in component.libraries) { | |
| if (library.importUri == uri) return library; | |
| } | |
| fail('No library found with URI "$uri"'); | |
| } | |
| String _getLibraryText(Library library) { | |
| StringBuffer buffer = new StringBuffer(); | |
| new Printer(buffer, syntheticNames: new NameSystem()) | |
| .writeLibraryFile(library); | |
| return buffer.toString(); | |
| } | |
| /// Resolve the given `dart` or `package` [inputUri] into the corresponding | |
| /// file URI, or return the same URI if it is already a file URI. | |
| Uri _resolveUriToFileUri(Uri inputUri) { | |
| var translator = driver.uriTranslator; | |
| var outputUri = translator.translate(inputUri) ?? inputUri; | |
| return outputUri; | |
| } | |
| /// Return the [Uri] for the given Posix [path]. | |
| static Uri _folderUri(String path) { | |
| if (!path.endsWith('/')) path += '/'; | |
| return Uri.parse('org-dartlang-test://$path'); | |
| } | |
| } |