| // Copyright (c) 2016, 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 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/summary/format.dart'; |
| import 'package:analyzer/src/summary/idl.dart'; |
| import 'package:analyzer/src/summary/link.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'summarize_ast_test.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(LinkerUnitTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class LinkerUnitTest extends SummaryLinkerTest { |
| Linker linker; |
| |
| LinkerInputs linkerInputs; |
| LibraryElementInBuildUnit _testLibrary; |
| @override |
| bool get allowMissingFiles => false; |
| |
| Matcher get isUndefined => new isInstanceOf<UndefinedElementForLink>(); |
| |
| LibraryElementInBuildUnit get testLibrary => _testLibrary ??= |
| linker.getLibrary(linkerInputs.testDartUri) as LibraryElementInBuildUnit; |
| |
| void createLinker(String text, {String path: '/test.dart'}) { |
| linkerInputs = createLinkerInputs(text, path: path); |
| Map<String, LinkedLibraryBuilder> linkedLibraries = setupForLink( |
| linkerInputs.linkedLibraries, |
| linkerInputs.getUnit, |
| linkerInputs.getDeclaredVariable); |
| linker = new Linker(linkedLibraries, linkerInputs.getDependency, |
| linkerInputs.getUnit, true); |
| } |
| |
| LibraryElementForLink getLibrary(String uri) { |
| return linker.getLibrary(Uri.parse(uri)); |
| } |
| |
| void test_apiSignature_apiChanges() { |
| var bundle0 = |
| createPackageBundle('f(int i) { print(i); }', path: '/test.dart'); |
| var bundle1 = |
| createPackageBundle('f(String s) { print(s); }', path: '/test.dart'); |
| expect(bundle0.apiSignature, isNotEmpty); |
| expect(bundle1.apiSignature, isNotEmpty); |
| expect(bundle0.apiSignature, isNot(bundle1.apiSignature)); |
| } |
| |
| void test_apiSignature_localChanges() { |
| var bundle0 = createPackageBundle('f() { print(0); }', path: '/test.dart'); |
| var bundle1 = createPackageBundle('f() { print(1); }', path: '/test.dart'); |
| expect(bundle0.apiSignature, isNotEmpty); |
| expect(bundle1.apiSignature, isNotEmpty); |
| expect(bundle0.apiSignature, bundle1.apiSignature); |
| } |
| |
| void test_apiSignature_orderChange() { |
| // A change to the order in which files are processed should not affect the |
| // API signature. |
| addNamedSource('/a.dart', 'class A {}'); |
| var bundle0 = createPackageBundle('class B {}', path: '/b.dart'); |
| addNamedSource('/b.dart', 'class B {}'); |
| var bundle1 = createPackageBundle('class A {}', path: '/a.dart'); |
| expect(bundle0.apiSignature, isNotEmpty); |
| expect(bundle1.apiSignature, isNotEmpty); |
| expect(bundle0.apiSignature, bundle1.apiSignature); |
| } |
| |
| void test_apiSignature_unlinkedOnly() { |
| // The API signature of a package bundle should only contain unlinked |
| // information. In this test, the linked information for bundle2 and |
| // bundle3 refer to class C as existing in different files. But the |
| // unlinked information for bundle2 and bundle3 should be the same, so their |
| // API signatures should be the same. |
| addNamedSource('/a.dart', 'class C {}'); |
| var bundle0 = createPackageBundle('', path: '/b.dart'); |
| addNamedSource('/a.dart', ''); |
| var bundle1 = createPackageBundle('class C {}', path: '/b.dart'); |
| var text = ''' |
| import 'a.dart'; |
| import 'b.dart'; |
| class D extends C {} |
| '''; |
| addBundle('/bundle0.ds', bundle0); |
| var bundle2 = createPackageBundle(text, path: '/c.dart'); |
| addBundle('/bundle1.ds', bundle1); |
| var bundle3 = createPackageBundle(text, path: '/c.dart'); |
| expect(bundle2.apiSignature, isNotEmpty); |
| expect(bundle3.apiSignature, isNotEmpty); |
| expect(bundle2.apiSignature, bundle3.apiSignature); |
| } |
| |
| void test_baseClass_genericWithAccessor() { |
| createLinker(''' |
| class B<T> { |
| int get i => null; |
| } |
| class C<U> extends B<U> { |
| var j; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_baseClass_genericWithField() { |
| createLinker(''' |
| class B<T> { |
| int i = 0; |
| } |
| class C<T> extends B<T> { |
| void f() {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_baseClass_genericWithFunctionTypedParameter() { |
| createLinker(''' |
| class B<T> { |
| void f(void g(T t)); |
| } |
| class C<U> extends B<U> { |
| void f(g) {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_baseClass_genericWithGenericMethod() { |
| createLinker(''' |
| class B<T> { |
| List<U> f<U>(U u) => null; |
| } |
| class C<V> extends B<V> { |
| var j; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_baseClass_genericWithGenericMethod_returnsGenericFuture() { |
| createLinker(''' |
| import 'dart:async'; |
| class B<T> { |
| Future<T> f() => null; |
| } |
| class C<T> extends B<T> { |
| Future<T> f() => null; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_baseClass_genericWithStaticFinal() { |
| createLinker(''' |
| class B<T> { |
| static final int i = 0; |
| } |
| class C<T> extends B<T> { |
| void f() {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| } |
| |
| void test_baseClass_withPrivateField() { |
| createLinker(''' |
| class B { |
| var _b; |
| } |
| class C extends B { |
| var c; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_bundle_refers_to_bundle() { |
| var bundle1 = createPackageBundle(''' |
| var x = 0; |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle1); |
| var bundle2 = createPackageBundle(''' |
| import "a.dart"; |
| var y = x; |
| ''', path: '/b.dart'); |
| addBundle('/a.ds', bundle1); |
| addBundle('/b.ds', bundle2); |
| createLinker(''' |
| import "b.dart"; |
| var z = y; |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| expect(_getVariable(library.getContainedName('z')).inferredType.toString(), |
| 'int'); |
| } |
| |
| void test_constCycle_viaLength() { |
| createLinker(''' |
| class C { |
| final y; |
| const C() : y = x.length; |
| } |
| const x = [const C()]; |
| '''); |
| testLibrary.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink classC = testLibrary.getContainedName('C'); |
| expect(classC.unnamedConstructor.isCycleFree, false); |
| } |
| |
| void test_covariance() { |
| // Note: due to dartbug.com/27393, the keyword "checked" is identified by |
| // its presence in a library called "meta". If that bug is fixed, this test |
| // may need to be changed. |
| createLinker(''' |
| library meta; |
| const checked = null; |
| class A<T> { |
| void f(@checked T t) {} |
| } |
| class B<T> extends A<T> { |
| void f(T t) {} |
| } |
| '''); |
| testLibrary.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink classA = testLibrary.getContainedName('A'); |
| MethodElementForLink methodAF = classA.getContainedName('f'); |
| ParameterElementForLink parameterAFT = methodAF.parameters[0]; |
| expect(parameterAFT.isCovariant, isTrue); |
| expect(parameterAFT.inheritsCovariant, isFalse); |
| ClassElementForLink classB = testLibrary.getContainedName('B'); |
| MethodElementForLink methodBF = classB.getContainedName('f'); |
| ParameterElementForLink parameterBFT = methodBF.parameters[0]; |
| expect(parameterAFT.isCovariant, isTrue); |
| expect(parameterBFT.inheritsCovariant, isTrue); |
| } |
| |
| void test_createPackageBundle_withPackageUri() { |
| PackageBundle bundle = createPackageBundle(''' |
| class B { |
| void f(int i) {} |
| } |
| class C extends B { |
| f(i) {} // Inferred param type: int |
| } |
| ''', uri: 'package:foo/bar.dart'); |
| UnlinkedExecutable cf = bundle.unlinkedUnits[0].classes[1].executables[0]; |
| UnlinkedParam cfi = cf.parameters[0]; |
| expect(cfi.inferredTypeSlot, isNot(0)); |
| EntityRef typeRef = _lookupInferredType( |
| bundle.linkedLibraries[0].units[0], cfi.inferredTypeSlot); |
| expect(typeRef, isNotNull); |
| expect(bundle.unlinkedUnits[0].references[typeRef.reference].name, 'int'); |
| } |
| |
| void test_genericTypeAlias_fromBundle() { |
| var bundle = createPackageBundle(''' |
| typedef F<S> = S Function(num); |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| |
| createLinker(''' |
| import 'a.dart'; |
| class A { |
| F<int> f; |
| } |
| class B implements A { |
| F<int> f; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| |
| ClassElementForLink_Class B = library.getContainedName('B'); |
| expect(B.fields, hasLength(1)); |
| FieldElementForLink f = B.fields[0]; |
| expect(f.type.toString(), '(num) → int'); |
| } |
| |
| void test_getContainedName_nonStaticField() { |
| createLinker('class C { var f; }'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| ClassElementForLink_Class c = library.getContainedName('C'); |
| expect(c.getContainedName('f'), isNot(isUndefined)); |
| } |
| |
| void test_getContainedName_nonStaticGetter() { |
| createLinker('class C { get g => null; }'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| ClassElementForLink_Class c = library.getContainedName('C'); |
| expect(c.getContainedName('g'), isNot(isUndefined)); |
| } |
| |
| void test_getContainedName_nonStaticMethod() { |
| createLinker('class C { m() {} }'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| ClassElementForLink_Class c = library.getContainedName('C'); |
| expect(c.getContainedName('m'), isNot(isUndefined)); |
| } |
| |
| void test_getContainedName_nonStaticSetter() { |
| createLinker('class C { void set s(value) {} }'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| ClassElementForLink_Class c = library.getContainedName('C'); |
| expect(c.getContainedName('s='), isNot(isUndefined)); |
| } |
| |
| void test_inferredType_closure_fromBundle() { |
| var bundle = createPackageBundle(''' |
| var x = () {}; |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| var y = x; |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| expect(_getVariable(library.getContainedName('y')).inferredType.toString(), |
| '() → dynamic'); |
| } |
| |
| void test_inferredType_closure_fromBundle_identifierSequence() { |
| var bundle = createPackageBundle(''' |
| class C { |
| static final x = (D d) => d.e; |
| } |
| class D { |
| E e; |
| } |
| class E {} |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| var y = C.x; |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| expect(_getVariable(library.getContainedName('y')).inferredType.toString(), |
| '(D) → E'); |
| } |
| |
| void test_inferredType_implicitFunctionTypeIndices() { |
| var bundle = createPackageBundle(''' |
| class A { |
| void foo(void bar(int arg)) {} |
| } |
| class B extends A { |
| void foo(bar) {} |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| class C extends B { |
| void foo(bar) {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('C'); |
| expect(cls.methods, hasLength(1)); |
| MethodElementForLink foo = cls.methods[0]; |
| expect(foo.parameters, hasLength(1)); |
| FunctionType barType = foo.parameters[0].type; |
| expect(barType.parameters[0].type.toString(), 'int'); |
| } |
| |
| void test_inferredType_instanceField_conditional_genericFunctions() { |
| createLinker(''' |
| class C { |
| final f = true ? <T>(T t) => 0 : <T>(T t) => 1; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('C'); |
| expect(cls.fields, hasLength(1)); |
| var field = cls.fields[0]; |
| expect(field.type.toString(), '(<bottom>) → dynamic'); |
| } |
| |
| void test_inferredType_instanceField_dynamic() { |
| createLinker(''' |
| var x; |
| class C { |
| var f = x; // Inferred type: dynamic |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('C'); |
| expect(cls.fields, hasLength(1)); |
| var field = cls.fields[0]; |
| expect(field.type.toString(), 'dynamic'); |
| } |
| |
| void test_inferredType_methodParamType_dynamic() { |
| createLinker(''' |
| clas B { |
| void f(dynamic x) {} |
| } |
| class C extends B { |
| f(x) {} // Inferred param type: dynamic |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('C'); |
| expect(cls.methods, hasLength(1)); |
| var method = cls.methods[0]; |
| expect(method.parameters, hasLength(1)); |
| expect(method.parameters[0].type.toString(), 'dynamic'); |
| } |
| |
| void test_inferredType_methodReturnType_dynamic() { |
| createLinker(''' |
| class B { |
| dynamic f() {} |
| } |
| class C extends B { |
| f() {} // Inferred return type: dynamic |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('C'); |
| expect(cls.methods, hasLength(1)); |
| expect(cls.methods[0].returnType.toString(), 'dynamic'); |
| } |
| |
| void test_inferredType_methodReturnType_void() { |
| createLinker(''' |
| class B { |
| void f() {} |
| } |
| class C extends B { |
| f() {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('C'); |
| expect(cls.methods, hasLength(1)); |
| expect(cls.methods[0].returnType.toString(), 'void'); |
| } |
| |
| void test_inferredType_parameter_genericFunctionType() { |
| var bundle = createPackageBundle(''' |
| class A<T> { |
| A<R> map<R>(R Function(T) f) => null; |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| class C extends A<int> { |
| map<R2>(f) => null; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class c = library.getContainedName('C'); |
| expect(c.methods, hasLength(1)); |
| MethodElementForLink map = c.methods[0]; |
| expect(map.parameters, hasLength(1)); |
| FunctionType fType = map.parameters[0].type; |
| expect(fType.returnType.toString(), 'R2'); |
| expect(fType.parameters[0].type.toString(), 'int'); |
| } |
| |
| @failingTest |
| void test_inferredType_parameter_genericFunctionType_asTypeArgument() { |
| var bundle = createPackageBundle(''' |
| class A<T> { |
| A<R> map<R>(List<R Function(T)> fs) => null; |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| class C extends A<int> { |
| map<R2>(fs) => null; |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class c = library.getContainedName('C'); |
| expect(c.methods, hasLength(1)); |
| MethodElementForLink map = c.methods[0]; |
| expect(map.parameters, hasLength(1)); |
| InterfaceType iType = map.parameters[0].type; |
| expect(iType.typeArguments, hasLength(1)); |
| FunctionType fType = iType.typeArguments[0]; |
| expect(fType.returnType.toString(), 'R2'); |
| expect(fType.parameters[0].type.toString(), 'int'); |
| } |
| |
| void test_inferredType_staticField_dynamic() { |
| createLinker(''' |
| dynamic x = null; |
| class C { |
| static var y = x; |
| } |
| '''); |
| expect( |
| _getVariable(linker |
| .getLibrary(linkerInputs.testDartUri) |
| .getContainedName('C') |
| .getContainedName('y')) |
| .inferredType |
| .toString(), |
| 'dynamic'); |
| } |
| |
| void test_inferredType_topLevelVariable_dynamic() { |
| createLinker(''' |
| dynamic x = null; |
| var y = x; |
| '''); |
| expect( |
| _getVariable(linker |
| .getLibrary(linkerInputs.testDartUri) |
| .getContainedName('y')) |
| .inferredType |
| .toString(), |
| 'dynamic'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_dynamic() { |
| var bundle = createPackageBundle(''' |
| var x; |
| var y = x; // Inferred type: dynamic |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| var z = y; // Inferred type: dynamic |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| expect(_getVariable(library.getContainedName('z')).inferredType.toString(), |
| 'dynamic'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_instanceField() { |
| var bundle = createPackageBundle(''' |
| class C { |
| var f = 0; // Inferred type: int |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| var x = new C().f; // Inferred type: int |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| expect(_getVariable(library.getContainedName('x')).inferredType.toString(), |
| 'int'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_instanceField_toInstanceField() { |
| var bundle = createPackageBundle(''' |
| class C { |
| var f = 0; // Inferred type: int |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| class D { |
| var g = new C().f; // Inferred type: int |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| ClassElementForLink_Class classD = library.getContainedName('D'); |
| expect(classD.fields[0].inferredType.toString(), 'int'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_methodParamType_viaInheritance() { |
| var bundle = createPackageBundle(''' |
| class B { |
| void f(int i) {} |
| } |
| class C extends B { |
| f(i) {} // Inferred param type: int |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| class D extends C { |
| f(i) {} // Inferred param type: int |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('D'); |
| expect(cls.methods, hasLength(1)); |
| var method = cls.methods[0]; |
| expect(method.parameters, hasLength(1)); |
| expect(method.parameters[0].type.toString(), 'int'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_methodReturnType_viaCall() { |
| var bundle = createPackageBundle(''' |
| class B { |
| int f() => 0; |
| } |
| class C extends B { |
| f() => 1; // Inferred return type: int |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| var x = new C().f(); // Inferred type: int |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| expect(_getVariable(library.getContainedName('x')).inferredType.toString(), |
| 'int'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_methodReturnType_viaInheritance() { |
| var bundle = createPackageBundle(''' |
| class B { |
| int f() => 0; |
| } |
| class C extends B { |
| f() => 1; // Inferred return type: int |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker(''' |
| import 'a.dart'; |
| class D extends C { |
| f() => 2; //Inferred return type: int |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| ClassElementForLink_Class cls = library.getContainedName('D'); |
| expect(cls.methods, hasLength(1)); |
| expect(cls.methods[0].returnType.toString(), 'int'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_staticField() { |
| var bundle = |
| createPackageBundle('class C { static var f = 0; }', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker('import "a.dart"; var x = C.f;', path: '/b.dart'); |
| expect( |
| _getVariable(linker |
| .getLibrary(linkerInputs.testDartUri) |
| .getContainedName('x')) |
| .inferredType |
| .toString(), |
| 'int'); |
| } |
| |
| void test_inferredTypeFromOutsideBuildUnit_topLevelVariable() { |
| var bundle = createPackageBundle('var a = 0;', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| createLinker('import "a.dart"; var b = a;', path: '/b.dart'); |
| expect( |
| _getVariable(linker |
| .getLibrary(linkerInputs.testDartUri) |
| .getContainedName('b')) |
| .inferredType |
| .toString(), |
| 'int'); |
| } |
| |
| void test_inheritsCovariant_fromBundle() { |
| var bundle = createPackageBundle(''' |
| class X1 {} |
| class X2 extends X1 {} |
| class A { |
| void foo(covariant X1 x) {} |
| } |
| class B extends A { |
| void foo(X2 x) {} |
| } |
| ''', path: '/a.dart'); |
| addBundle('/a.ds', bundle); |
| |
| // C.foo.x must inherit covariance from B.foo.x, even though it is |
| // resynthesized from the bundle. |
| createLinker(''' |
| import 'a.dart'; |
| class C extends B { |
| void foo(X2 x) {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| |
| ClassElementForLink_Class C = library.getContainedName('C'); |
| expect(C.methods, hasLength(1)); |
| MethodElementForLink foo = C.methods[0]; |
| expect(foo.parameters, hasLength(1)); |
| expect(foo.parameters[0].isCovariant, isTrue); |
| } |
| |
| void test_instantiate_param_of_param_to_bounds() { |
| createLinker(''' |
| class C<T> {} |
| class D<T extends num> {} |
| final x = new C<D>(); |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| PropertyAccessorElementForLink_Variable x = library.getContainedName('x'); |
| ParameterizedType type1 = x.returnType; |
| expect(type1.element.name, 'C'); |
| expect(type1.typeArguments, hasLength(1)); |
| ParameterizedType type2 = type1.typeArguments[0]; |
| expect(type2.element.name, 'D'); |
| expect(type2.typeArguments, hasLength(1)); |
| DartType type3 = type2.typeArguments[0]; |
| expect(type3.toString(), 'num'); |
| } |
| |
| void test_instantiate_param_to_bounds_class() { |
| createLinker(''' |
| class C<T extends num> {} |
| final x = new C(); |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| PropertyAccessorElementForLink_Variable x = library.getContainedName('x'); |
| ParameterizedType type1 = x.returnType; |
| expect(type1.element.name, 'C'); |
| expect(type1.typeArguments, hasLength(1)); |
| DartType type2 = type1.typeArguments[0]; |
| expect(type2.toString(), 'num'); |
| } |
| |
| void test_instantiate_param_to_bounds_typedef() { |
| createLinker(''' |
| typedef T F<T extends num>(); |
| final x = new List<F>(); |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| PropertyAccessorElementForLink_Variable x = library.getContainedName('x'); |
| ParameterizedType type1 = x.returnType; |
| expect(type1.element.name, 'List'); |
| expect(type1.typeArguments, hasLength(1)); |
| FunctionType type2 = type1.typeArguments[0]; |
| expect(type2.element.name, 'F'); |
| expect(type2.returnType.toString(), 'num'); |
| } |
| |
| void test_leastUpperBound_functionAndClass() { |
| createLinker(''' |
| class C {} |
| void f() {} |
| var x = { |
| 'C': C, |
| 'f': f |
| }; |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_libraryCycle_ignoresDependenciesOutsideBuildUnit() { |
| createLinker('import "dart:async";'); |
| LibraryCycleForLink libraryCycle = testLibrary.libraryCycleForLink; |
| expect(libraryCycle.dependencies, isEmpty); |
| expect(libraryCycle.libraries, [testLibrary]); |
| } |
| |
| void test_libraryCycle_linkEnsuresDependenciesLinked() { |
| addNamedSource('/a.dart', 'import "b.dart";'); |
| addNamedSource('/b.dart', ''); |
| addNamedSource('/c.dart', ''); |
| createLinker('import "a.dart"; import "c.dart";'); |
| LibraryElementForLink libA = getLibrary('file:///a.dart'); |
| LibraryElementForLink libB = getLibrary('file:///b.dart'); |
| LibraryElementForLink libC = getLibrary('file:///c.dart'); |
| expect(libA.libraryCycleForLink.node.isEvaluated, isFalse); |
| expect(libB.libraryCycleForLink.node.isEvaluated, isFalse); |
| expect(libC.libraryCycleForLink.node.isEvaluated, isFalse); |
| libA.libraryCycleForLink.ensureLinked(); |
| expect(libA.libraryCycleForLink.node.isEvaluated, isTrue); |
| expect(libB.libraryCycleForLink.node.isEvaluated, isTrue); |
| expect(libC.libraryCycleForLink.node.isEvaluated, isFalse); |
| } |
| |
| void test_libraryCycle_nontrivial() { |
| addNamedSource('/a.dart', 'import "b.dart";'); |
| addNamedSource('/b.dart', 'import "a.dart";'); |
| createLinker(''); |
| LibraryElementForLink libA = getLibrary('file:///a.dart'); |
| LibraryElementForLink libB = getLibrary('file:///b.dart'); |
| LibraryCycleForLink libraryCycle = libA.libraryCycleForLink; |
| expect(libB.libraryCycleForLink, same(libraryCycle)); |
| expect(libraryCycle.dependencies, isEmpty); |
| expect(libraryCycle.libraries, unorderedEquals([libA, libB])); |
| } |
| |
| void test_libraryCycle_nontrivial_dependencies() { |
| addNamedSource('/a.dart', ''); |
| addNamedSource('/b.dart', ''); |
| addNamedSource('/c.dart', 'import "a.dart"; import "d.dart";'); |
| addNamedSource('/d.dart', 'import "b.dart"; import "c.dart";'); |
| createLinker(''); |
| LibraryElementForLink libA = getLibrary('file:///a.dart'); |
| LibraryElementForLink libB = getLibrary('file:///b.dart'); |
| LibraryElementForLink libC = getLibrary('file:///c.dart'); |
| LibraryElementForLink libD = getLibrary('file:///d.dart'); |
| LibraryCycleForLink libraryCycle = libC.libraryCycleForLink; |
| expect(libD.libraryCycleForLink, same(libraryCycle)); |
| expect(libraryCycle.dependencies, |
| unorderedEquals([libA.libraryCycleForLink, libB.libraryCycleForLink])); |
| expect(libraryCycle.libraries, unorderedEquals([libC, libD])); |
| } |
| |
| void test_libraryCycle_nontrivial_via_export() { |
| addNamedSource('/a.dart', 'export "b.dart";'); |
| addNamedSource('/b.dart', 'export "a.dart";'); |
| createLinker(''); |
| LibraryElementForLink libA = getLibrary('file:///a.dart'); |
| LibraryElementForLink libB = getLibrary('file:///b.dart'); |
| LibraryCycleForLink libraryCycle = libA.libraryCycleForLink; |
| expect(libB.libraryCycleForLink, same(libraryCycle)); |
| expect(libraryCycle.dependencies, isEmpty); |
| expect(libraryCycle.libraries, unorderedEquals([libA, libB])); |
| } |
| |
| void test_libraryCycle_trivial() { |
| createLinker(''); |
| LibraryCycleForLink libraryCycle = testLibrary.libraryCycleForLink; |
| expect(libraryCycle.dependencies, isEmpty); |
| expect(libraryCycle.libraries, [testLibrary]); |
| } |
| |
| void test_libraryCycle_trivial_dependencies() { |
| addNamedSource('/a.dart', ''); |
| addNamedSource('/b.dart', ''); |
| createLinker('import "a.dart"; import "b.dart";'); |
| LibraryElementForLink libA = getLibrary('file:///a.dart'); |
| LibraryElementForLink libB = getLibrary('file:///b.dart'); |
| LibraryCycleForLink libraryCycle = testLibrary.libraryCycleForLink; |
| expect(libraryCycle.dependencies, |
| unorderedEquals([libA.libraryCycleForLink, libB.libraryCycleForLink])); |
| expect(libraryCycle.libraries, [testLibrary]); |
| } |
| |
| void test_multiplyInheritedExecutable_differentSignatures() { |
| createLinker(''' |
| class B { |
| void f() {} |
| } |
| abstract class I { |
| f(); |
| } |
| class C extends B with I {} |
| class D extends C { |
| void f() {} |
| } |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| library.libraryCycleForLink.ensureLinked(); |
| // No assertions--just make sure it doesn't crash. |
| } |
| |
| void test_parameterParentElementForLink_implicitFunctionTypeIndices() { |
| createLinker('void f(a, void g(b, c, d, void h())) {}'); |
| TopLevelFunctionElementForLink f = testLibrary.getContainedName('f'); |
| expect(f.implicitFunctionTypeIndices, []); |
| ParameterElementForLink g = f.parameters[1]; |
| FunctionType gType = g.type; |
| FunctionElementForLink_FunctionTypedParam gTypeElement = gType.element; |
| expect(gTypeElement.implicitFunctionTypeIndices, [1]); |
| ParameterElementForLink h = gTypeElement.parameters[3]; |
| FunctionType hType = h.type; |
| FunctionElementForLink_FunctionTypedParam hTypeElement = hType.element; |
| expect(hTypeElement.implicitFunctionTypeIndices, [1, 3]); |
| } |
| |
| void test_parameterParentElementForLink_innermostExecutable() { |
| createLinker('void f(void g(void h())) {}'); |
| TopLevelFunctionElementForLink f = testLibrary.getContainedName('f'); |
| expect(f.typeParameterContext, same(f)); |
| ParameterElementForLink g = f.parameters[0]; |
| FunctionType gType = g.type; |
| FunctionElementForLink_FunctionTypedParam gTypeElement = gType.element; |
| expect(gTypeElement.typeParameterContext, same(f)); |
| ParameterElementForLink h = gTypeElement.parameters[0]; |
| FunctionType hType = h.type; |
| FunctionElementForLink_FunctionTypedParam hTypeElement = hType.element; |
| expect(hTypeElement.typeParameterContext, same(f)); |
| } |
| |
| void test_topLevelFunction_isStatic() { |
| createLinker('f() {}'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| TopLevelFunctionElementForLink f = library.getContainedName('f'); |
| expect(f.isStatic, true); |
| } |
| |
| void test_topLevelGetter_isStatic() { |
| createLinker('get x => null;'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| PropertyAccessorElementForLink_Executable x = library.getContainedName('x'); |
| expect(x.isStatic, true); |
| } |
| |
| void test_topLevelSetter_isStatic() { |
| createLinker('void set x(value) {}'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| PropertyAccessorElementForLink_Executable x = |
| library.getContainedName('x='); |
| expect(x.isStatic, true); |
| } |
| |
| void test_topLevelVariable_isStatic() { |
| createLinker('var x;'); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| PropertyAccessorElementForLink_Variable x = library.getContainedName('x'); |
| expect(x.isStatic, true); |
| expect(x.variable.isStatic, true); |
| } |
| |
| void test_typeParameter_isTypeParameterInScope_direct() { |
| createLinker('class C<T, U> {}'); |
| ClassElementForLink_Class c = testLibrary.getContainedName('C'); |
| TypeParameterElementImpl t = c.typeParameters[0]; |
| TypeParameterElementImpl u = c.typeParameters[1]; |
| expect(c.isTypeParameterInScope(t), true); |
| expect(c.isTypeParameterInScope(u), true); |
| } |
| |
| void test_typeParameter_isTypeParameterInScope_indirect() { |
| createLinker('class C<T, U> { f<V, W>() {} }'); |
| ClassElementForLink_Class c = testLibrary.getContainedName('C'); |
| MethodElementForLink f = c.methods[0]; |
| TypeParameterElementImpl t = c.typeParameters[0]; |
| TypeParameterElementImpl u = c.typeParameters[1]; |
| expect(f.isTypeParameterInScope(t), true); |
| expect(f.isTypeParameterInScope(u), true); |
| } |
| |
| void test_typeParameter_isTypeParameterInScope_reversed() { |
| createLinker('class C<T, U> { f<V, W>() {} }'); |
| ClassElementForLink_Class c = testLibrary.getContainedName('C'); |
| MethodElementForLink f = c.methods[0]; |
| TypeParameterElementImpl v = f.typeParameters[0]; |
| TypeParameterElementImpl w = f.typeParameters[1]; |
| expect(c.isTypeParameterInScope(v), false); |
| expect(c.isTypeParameterInScope(w), false); |
| } |
| |
| void test_typeParameter_isTypeParameterInScope_unrelated() { |
| createLinker('class C<T, U> {} class D<V, W> {}'); |
| ClassElementForLink_Class c = testLibrary.getContainedName('C'); |
| ClassElementForLink_Class d = testLibrary.getContainedName('D'); |
| TypeParameterElementImpl t = c.typeParameters[0]; |
| TypeParameterElementImpl u = c.typeParameters[1]; |
| TypeParameterElementImpl v = d.typeParameters[0]; |
| TypeParameterElementImpl w = d.typeParameters[1]; |
| expect(c.isTypeParameterInScope(v), false); |
| expect(c.isTypeParameterInScope(w), false); |
| expect(d.isTypeParameterInScope(t), false); |
| expect(d.isTypeParameterInScope(u), false); |
| } |
| |
| void test_variable_initializer_presence() { |
| // Any variable declaration with an initializer should have a non-null value |
| // for `initializer`, regardless of whether it is constant and regardless of |
| // whether it has an explicit type. |
| createLinker(''' |
| const int c = 0; |
| int i = 0; |
| int j; |
| var v = 0; |
| '''); |
| LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri); |
| PropertyAccessorElementForLink_Variable c = library.getContainedName('c'); |
| expect(c.variable.initializer, isNotNull); |
| PropertyAccessorElementForLink_Variable i = library.getContainedName('i'); |
| expect(i.variable.initializer, isNotNull); |
| PropertyAccessorElementForLink_Variable j = library.getContainedName('j'); |
| expect(j.variable.initializer, isNull); |
| PropertyAccessorElementForLink_Variable v = library.getContainedName('v'); |
| expect(v.variable.initializer, isNotNull); |
| } |
| |
| VariableElementForLink _getVariable(ReferenceableElementForLink element) { |
| return (element as PropertyAccessorElementForLink_Variable).variable; |
| } |
| |
| /** |
| * Finds the first inferred type stored in [unit] whose slot matches [slot]. |
| */ |
| EntityRef _lookupInferredType(LinkedUnit unit, int slot) { |
| for (EntityRef ref in unit.types) { |
| if (ref.slot == slot) { |
| return ref; |
| } |
| } |
| return null; |
| } |
| } |