Index: pkg/kernel/test/class_hierarchy_test.dart |
diff --git a/pkg/kernel/test/class_hierarchy_test.dart b/pkg/kernel/test/class_hierarchy_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e9b0fdc768beb9be197e29f18f9cb68d8de8ffe7 |
--- /dev/null |
+++ b/pkg/kernel/test/class_hierarchy_test.dart |
@@ -0,0 +1,657 @@ |
+// 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 'package:kernel/ast.dart'; |
+import 'package:kernel/class_hierarchy.dart'; |
+import 'package:kernel/core_types.dart'; |
+import 'package:kernel/testing/mock_sdk_program.dart'; |
+import 'package:test/test.dart'; |
+import 'package:test_reflective_loader/test_reflective_loader.dart'; |
+ |
+main() { |
+ defineReflectiveSuite(() { |
+ defineReflectiveTests(ClosedWorldClassHierarchyTest); |
+ }); |
+} |
+ |
+@reflectiveTest |
+class ClosedWorldClassHierarchyTest extends _ClassHierarchyTest { |
+ ClassHierarchy createClassHierarchy(Program program) { |
+ return new ClosedWorldClassHierarchy(program); |
+ } |
+} |
+ |
+abstract class _ClassHierarchyTest { |
+ Program program; |
+ CoreTypes coreTypes; |
+ |
+ /// The test library. |
+ Library library; |
+ |
+ ClassHierarchy _hierarchy; |
+ |
+ /// Return the new or existing instance of [ClassHierarchy]. |
+ ClassHierarchy get hierarchy { |
+ return _hierarchy ??= createClassHierarchy(program); |
+ } |
+ |
+ Class get objectClass => coreTypes.objectClass; |
+ |
+ Supertype get objectSuper => coreTypes.objectClass.asThisSupertype; |
+ |
+ Class addClass(Class c) { |
+ if (_hierarchy != null) { |
+ fail('The classs hierarchy has already been created.'); |
+ } |
+ library.addClass(c); |
+ return c; |
+ } |
+ |
+ /// Add a new generic class with the given [name] and [typeParameterNames]. |
+ /// The [TypeParameterType]s corresponding to [typeParameterNames] are |
+ /// passed to optional [extends_] and [implements_] callbacks. |
+ Class addGenericClass(String name, List<String> typeParameterNames, |
+ {Supertype extends_(List<DartType> typeParameterTypes), |
+ List<Supertype> implements_(List<DartType> typeParameterTypes)}) { |
+ var typeParameters = typeParameterNames |
+ .map((name) => new TypeParameter(name, objectClass.rawType)) |
+ .toList(); |
+ var typeParameterTypes = typeParameters |
+ .map((parameter) => new TypeParameterType(parameter)) |
+ .toList(); |
+ var supertype = |
+ extends_ != null ? extends_(typeParameterTypes) : objectSuper; |
+ var implementedTypes = |
+ implements_ != null ? implements_(typeParameterTypes) : []; |
+ return addClass(new Class( |
+ name: name, |
+ typeParameters: typeParameters, |
+ supertype: supertype, |
+ implementedTypes: implementedTypes)); |
+ } |
+ |
+ /// Add a new class with the given [name] that extends `Object` and |
+ /// [implements_] the given classes. |
+ Class addImplementsClass(String name, List<Class> implements_) { |
+ return addClass(new Class( |
+ name: name, |
+ supertype: objectSuper, |
+ implementedTypes: implements_.map((c) => c.asThisSupertype).toList())); |
+ } |
+ |
+ ClassHierarchy createClassHierarchy(Program program); |
+ |
+ Procedure newEmptyMethod(String name, {bool abstract: false}) { |
+ var body = abstract ? null : new Block([]); |
+ return new Procedure( |
+ new Name(name), ProcedureKind.Method, new FunctionNode(body)); |
+ } |
+ |
+ Procedure newEmptySetter(String name) { |
+ return new Procedure( |
+ new Name(name), |
+ ProcedureKind.Setter, |
+ new FunctionNode(new Block([]), |
+ positionalParameters: [new VariableDeclaration('_')])); |
+ } |
+ |
+ void setUp() { |
+ // Start with mock SDK libraries. |
+ program = createMockSdkProgram(); |
+ coreTypes = new CoreTypes(program); |
+ |
+ // Add the test library. |
+ library = new Library(Uri.parse('org-dartlang:///test.dart'), name: 'test'); |
+ library.parent = program; |
+ program.libraries.add(library); |
+ } |
+ |
+ void test_forEachOverridePair_overrideSupertype() { |
+ // Create the class hierarchy: |
+ // |
+ // abstract class A extends Object { |
+ // foo() {} |
+ // bar() {} |
+ // } |
+ // class B extends A { |
+ // foo() {} |
+ // } |
+ // class C extends B { |
+ // bar() {} |
+ // } |
+ var aFoo = newEmptyMethod('foo'); |
+ var aBar = newEmptyMethod('bar'); |
+ var bFoo = newEmptyMethod('foo'); |
+ var cBar = newEmptyMethod('bar'); |
+ var a = addClass( |
+ new Class(name: 'A', supertype: objectSuper, procedures: [aFoo, aBar])); |
+ var b = addClass( |
+ new Class(name: 'B', supertype: a.asThisSupertype, procedures: [bFoo])); |
+ var c = addClass( |
+ new Class(name: 'C', supertype: b.asThisSupertype, procedures: [cBar])); |
+ |
+ _assertOverridePairs(b, ['test::B::foo overrides test::A::foo']); |
+ _assertOverridePairs(c, ['test::C::bar overrides test::A::bar']); |
+ } |
+ |
+ void test_getClassAsInstanceOf_generic_extends() { |
+ // Create the class hierarchy: |
+ // |
+ // class A<T, U> extends Object {} |
+ // class B<T> extends A<T, bool> {} |
+ // class C extends B<int> {} |
+ var int = coreTypes.intClass.rawType; |
+ var bool = coreTypes.boolClass.rawType; |
+ |
+ var a = addGenericClass('A', ['T', 'U']); |
+ |
+ var bT = new TypeParameter('T', objectClass.rawType); |
+ var bTT = new TypeParameterType(bT); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ typeParameters: [bT], |
+ supertype: new Supertype(a, [bTT, bool]))); |
+ |
+ var c = addClass(new Class(name: 'C', supertype: new Supertype(b, [int]))); |
+ |
+ expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); |
+ expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(b, a), new Supertype(a, [bTT, bool])); |
+ expect(hierarchy.getClassAsInstanceOf(c, b), new Supertype(b, [int])); |
+ expect(hierarchy.getClassAsInstanceOf(c, a), new Supertype(a, [int, bool])); |
+ } |
+ |
+ void test_getClassAsInstanceOf_generic_implements() { |
+ // Create the class hierarchy: |
+ // |
+ // class A<T, U> extends Object {} |
+ // class B<T> extends Object implements A<T, bool> {} |
+ // class C extends Object implements B<int> {} |
+ var int = coreTypes.intClass.rawType; |
+ var bool = coreTypes.boolClass.rawType; |
+ |
+ var a = addGenericClass('A', ['T', 'U']); |
+ |
+ var bT = new TypeParameter('T', objectClass.rawType); |
+ var bTT = new TypeParameterType(bT); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ typeParameters: [bT], |
+ supertype: objectSuper, |
+ implementedTypes: [ |
+ new Supertype(a, [bTT, bool]) |
+ ])); |
+ |
+ var c = addClass( |
+ new Class(name: 'C', supertype: objectSuper, implementedTypes: [ |
+ new Supertype(b, [int]) |
+ ])); |
+ |
+ expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); |
+ expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(b, a), new Supertype(a, [bTT, bool])); |
+ expect(hierarchy.getClassAsInstanceOf(c, b), new Supertype(b, [int])); |
+ expect(hierarchy.getClassAsInstanceOf(c, a), new Supertype(a, [int, bool])); |
+ } |
+ |
+ void test_getClassAsInstanceOf_generic_with() { |
+ // Create the class hierarchy: |
+ // |
+ // class A<T, U> extends Object {} |
+ // class B<T> extends Object with A<T, bool> {} |
+ // class C extends Object with B<int> {} |
+ var int = coreTypes.intClass.rawType; |
+ var bool = coreTypes.boolClass.rawType; |
+ |
+ var a = addGenericClass('A', ['T', 'U']); |
+ |
+ var bT = new TypeParameter('T', objectClass.rawType); |
+ var bTT = new TypeParameterType(bT); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ typeParameters: [bT], |
+ supertype: objectSuper, |
+ mixedInType: new Supertype(a, [bTT, bool]))); |
+ |
+ var c = addClass(new Class( |
+ name: 'C', |
+ supertype: objectSuper, |
+ mixedInType: new Supertype(b, [int]))); |
+ |
+ expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); |
+ expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(b, a), new Supertype(a, [bTT, bool])); |
+ expect(hierarchy.getClassAsInstanceOf(c, b), new Supertype(b, [int])); |
+ expect(hierarchy.getClassAsInstanceOf(c, a), new Supertype(a, [int, bool])); |
+ } |
+ |
+ void test_getClassAsInstanceOf_notGeneric_extends() { |
+ // Create the class hierarchy: |
+ // |
+ // class A extends Object {} |
+ // class B extends A {} |
+ // class C extends B {} |
+ // class Z extends Object {} |
+ var a = addClass(new Class(name: 'A', supertype: objectSuper)); |
+ var b = addClass(new Class(name: 'B', supertype: a.asThisSupertype)); |
+ var c = addClass(new Class(name: 'C', supertype: b.asThisSupertype)); |
+ var z = addClass(new Class(name: 'Z', supertype: objectSuper)); |
+ |
+ expect(hierarchy.getClassAsInstanceOf(a, objectClass), objectSuper); |
+ expect(hierarchy.getClassAsInstanceOf(a, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(b, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(c, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(c, b), b.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(z, a), null); |
+ expect(hierarchy.getClassAsInstanceOf(z, objectClass), objectSuper); |
+ } |
+ |
+ void test_getClassAsInstanceOf_notGeneric_implements() { |
+ // Create the class hierarchy: |
+ // |
+ // class A extends Object {} |
+ // class B extends Object {} |
+ // class C extends Object implements A {} |
+ // class D extends Object implements C {} |
+ // class E extends A implements B {} |
+ // class Z extends Object {} |
+ var a = addClass(new Class(name: 'A', supertype: objectSuper)); |
+ var b = addClass(new Class(name: 'B', supertype: objectSuper)); |
+ var c = addClass(new Class( |
+ name: 'C', |
+ supertype: objectSuper, |
+ implementedTypes: [a.asThisSupertype])); |
+ var d = addClass(new Class( |
+ name: 'D', |
+ supertype: objectSuper, |
+ implementedTypes: [c.asThisSupertype])); |
+ var e = addClass(new Class( |
+ name: 'D', |
+ supertype: a.asThisSupertype, |
+ implementedTypes: [b.asThisSupertype])); |
+ var z = addClass(new Class(name: 'Z', supertype: objectSuper)); |
+ |
+ expect(hierarchy.getClassAsInstanceOf(c, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(d, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(d, c), c.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(e, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(e, b), b.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(z, a), null); |
+ } |
+ |
+ void test_getClassAsInstanceOf_notGeneric_with() { |
+ // Create the class hierarchy: |
+ // |
+ // class A extends Object {} |
+ // class B extends Object with A {} |
+ // class Z extends Object {} |
+ var a = addClass(new Class(name: 'A', supertype: objectSuper)); |
+ var b = addClass(new Class( |
+ name: 'B', supertype: objectSuper, mixedInType: a.asThisSupertype)); |
+ var z = addClass(new Class(name: 'Z', supertype: objectSuper)); |
+ |
+ expect(hierarchy.getClassAsInstanceOf(b, objectClass), objectSuper); |
+ expect(hierarchy.getClassAsInstanceOf(b, a), a.asThisSupertype); |
+ expect(hierarchy.getClassAsInstanceOf(z, a), null); |
+ } |
+ |
+ void test_getClassDepth() { |
+ var base = addClass(new Class(name: 'base', supertype: objectSuper)); |
+ var extends_ = |
+ addClass(new Class(name: 'extends_', supertype: base.asThisSupertype)); |
+ var with_ = addClass(new Class( |
+ name: 'with_', |
+ supertype: objectSuper, |
+ mixedInType: base.asThisSupertype)); |
+ var implements_ = addClass(new Class( |
+ name: 'implements_', |
+ supertype: objectSuper, |
+ implementedTypes: [base.asThisSupertype])); |
+ |
+ expect(hierarchy.getClassDepth(objectClass), 0); |
+ expect(hierarchy.getClassDepth(base), 1); |
+ expect(hierarchy.getClassDepth(extends_), 2); |
+ expect(hierarchy.getClassDepth(with_), 2); |
+ expect(hierarchy.getClassDepth(implements_), 2); |
+ } |
+ |
+ void test_getClassicLeastUpperBound_generic() { |
+ var int = coreTypes.intClass.rawType; |
+ var double = coreTypes.doubleClass.rawType; |
+ var bool = coreTypes.boolClass.rawType; |
+ |
+ // Create the class hierarchy: |
+ // |
+ // Object |
+ // | |
+ // A |
+ // / \ |
+ // B<T> C<U> |
+ // \ / |
+ // D<T,U> |
+ // / \ |
+ // E F |
+ // |
+ // Where E implements D<int, double> and F implements D<int, bool>. |
+ var a = addGenericClass('A', []); |
+ var b = |
+ addGenericClass('B', ['T'], implements_: (_) => [a.asThisSupertype]); |
+ var c = |
+ addGenericClass('C', ['U'], implements_: (_) => [a.asThisSupertype]); |
+ var d = addGenericClass('D', ['T', 'U'], implements_: (typeParameterTypes) { |
+ var t = typeParameterTypes[0]; |
+ var u = typeParameterTypes[1]; |
+ return [ |
+ new Supertype(b, [t]), |
+ new Supertype(c, [u]) |
+ ]; |
+ }); |
+ var e = addGenericClass('E', [], |
+ implements_: (_) => [ |
+ new Supertype(d, [int, double]) |
+ ]); |
+ var f = addGenericClass('F', [], |
+ implements_: (_) => [ |
+ new Supertype(d, [int, bool]) |
+ ]); |
+ |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), |
+ new InterfaceType(d, [int, double])), |
+ new InterfaceType(d, [int, double])); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), |
+ new InterfaceType(d, [int, bool])), |
+ new InterfaceType(b, [int])); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), |
+ new InterfaceType(d, [bool, double])), |
+ new InterfaceType(c, [double])); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(new InterfaceType(d, [int, double]), |
+ new InterfaceType(d, [bool, int])), |
+ a.rawType); |
+ expect(hierarchy.getClassicLeastUpperBound(e.rawType, f.rawType), |
+ new InterfaceType(b, [int])); |
+ } |
+ |
+ void test_getClassicLeastUpperBound_nonGeneric() { |
+ // Create the class hierarchy: |
+ // |
+ // Object |
+ // / \ |
+ // A B |
+ // /|\ |
+ // C D E |
+ // |X|/ |
+ // FG HI |
+ // |
+ // (F and G both implement (C, D); H and I both implement (C, D, E). |
+ var a = addImplementsClass('A', []); |
+ var b = addImplementsClass('B', []); |
+ var c = addImplementsClass('C', [a]); |
+ var d = addImplementsClass('D', [a]); |
+ var e = addImplementsClass('E', [a]); |
+ var f = addImplementsClass('F', [c, d]); |
+ var g = addImplementsClass('G', [c, d]); |
+ var h = addImplementsClass('H', [c, d, e]); |
+ var i = addImplementsClass('I', [c, d, e]); |
+ var hierarchy = new ClassHierarchy(program); |
+ |
+ expect(hierarchy.getClassicLeastUpperBound(a.rawType, b.rawType), |
+ objectClass.rawType); |
+ expect(hierarchy.getClassicLeastUpperBound(a.rawType, objectClass.rawType), |
+ objectClass.rawType); |
+ expect(hierarchy.getClassicLeastUpperBound(objectClass.rawType, b.rawType), |
+ objectClass.rawType); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(c.rawType, d.rawType), a.rawType); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(c.rawType, a.rawType), a.rawType); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(a.rawType, d.rawType), a.rawType); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(f.rawType, g.rawType), a.rawType); |
+ expect( |
+ hierarchy.getClassicLeastUpperBound(h.rawType, i.rawType), a.rawType); |
+ } |
+ |
+ void test_getDispatchTarget() { |
+ // Create the class hierarchy: |
+ // |
+ // class A extends Object { |
+ // aMethod() {} |
+ // void set aSetter(_) {} |
+ // } |
+ // class B extends A { |
+ // bMethod() {} |
+ // void set bSetter(_) {} |
+ // } |
+ // class C extends B {} |
+ var aMethod = newEmptyMethod('aMethod'); |
+ var aSetter = newEmptySetter('aSetter'); |
+ var bMethod = newEmptyMethod('bMethod'); |
+ var bSetter = newEmptySetter('bSetter'); |
+ var a = addClass(new Class( |
+ name: 'A', supertype: objectSuper, procedures: [aMethod, aSetter])); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ supertype: a.asThisSupertype, |
+ procedures: [bMethod, bSetter])); |
+ var c = addClass(new Class(name: 'C', supertype: b.asThisSupertype)); |
+ |
+ var aMethodName = new Name('aMethod'); |
+ var aSetterName = new Name('aSetter'); |
+ var bMethodName = new Name('bMethod'); |
+ var bSetterName = new Name('bSetter'); |
+ expect(hierarchy.getDispatchTarget(a, aMethodName), aMethod); |
+ expect(hierarchy.getDispatchTarget(a, bMethodName), isNull); |
+ expect(hierarchy.getDispatchTarget(a, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getDispatchTarget(a, bSetterName, setter: true), isNull); |
+ expect(hierarchy.getDispatchTarget(b, aMethodName), aMethod); |
+ expect(hierarchy.getDispatchTarget(b, bMethodName), bMethod); |
+ expect(hierarchy.getDispatchTarget(b, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getDispatchTarget(b, bSetterName, setter: true), bSetter); |
+ expect(hierarchy.getDispatchTarget(c, aMethodName), aMethod); |
+ expect(hierarchy.getDispatchTarget(c, bMethodName), bMethod); |
+ expect(hierarchy.getDispatchTarget(c, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getDispatchTarget(c, bSetterName, setter: true), bSetter); |
+ } |
+ |
+ void test_getDispatchTarget_abstract() { |
+ // Create the class hierarchy: |
+ // |
+ // abstract class A extends Object { |
+ // aMethodAbstract(); |
+ // aMethodConcrete() {} |
+ // } |
+ // abstract class B extends A { |
+ // aMethodConcrete(); |
+ // bMethodAbstract(); |
+ // bMethodConcrete() {} |
+ // } |
+ // class C extends B {} |
+ var aMethodConcrete = newEmptyMethod('aMethodConcrete'); |
+ var bMethodConcrete = newEmptyMethod('aMethodConcrete'); |
+ var a = addClass(new Class(name: 'A', supertype: objectSuper, procedures: [ |
+ newEmptyMethod('aMethodAbstract', abstract: true), |
+ aMethodConcrete |
+ ])); |
+ var b = addClass( |
+ new Class(name: 'B', supertype: a.asThisSupertype, procedures: [ |
+ newEmptyMethod('aMethodConcrete', abstract: true), |
+ newEmptyMethod('bMethodAbstract', abstract: true), |
+ bMethodConcrete |
+ ])); |
+ addClass(new Class(name: 'C', supertype: b.asThisSupertype)); |
+ |
+ expect(hierarchy.getDispatchTarget(a, new Name('aMethodConcrete')), |
+ aMethodConcrete); |
+ // TODO(scheglov): The next two commented statements verify the behavior |
+ // documented as "If the class is abstract, abstract members are ignored and |
+ // the dispatch is resolved if the class was not abstract.". Unfortunately |
+ // the implementation does not follow the documentation. We need to fix |
+ // either documentation, or implementation. |
+// expect(hierarchy.getDispatchTarget(c, new Name('aMethodConcrete')), |
+// aMethodConcrete); |
+// expect(hierarchy.getDispatchTarget(b, new Name('aMethodConcrete')), |
+// aMethodConcrete); |
+ } |
+ |
+ void test_getInterfaceMember_extends() { |
+ // Create the class hierarchy: |
+ // |
+ // class A extends Object { |
+ // aMethod() {} |
+ // void set aSetter(_) {} |
+ // } |
+ // class B extends A { |
+ // bMethod() {} |
+ // void set bSetter(_) {} |
+ // } |
+ // class C extends B {} |
+ var aMethod = newEmptyMethod('aMethod'); |
+ var aSetter = newEmptySetter('aSetter'); |
+ var bMethod = newEmptyMethod('bMethod'); |
+ var bSetter = newEmptySetter('bSetter'); |
+ var a = addClass(new Class( |
+ name: 'A', supertype: objectSuper, procedures: [aMethod, aSetter])); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ supertype: a.asThisSupertype, |
+ procedures: [bMethod, bSetter])); |
+ var c = addClass(new Class(name: 'C', supertype: b.asThisSupertype)); |
+ |
+ var aMethodName = new Name('aMethod'); |
+ var aSetterName = new Name('aSetter'); |
+ var bMethodName = new Name('bMethod'); |
+ var bSetterName = new Name('bSetter'); |
+ expect(hierarchy.getInterfaceMember(a, aMethodName), aMethod); |
+ expect(hierarchy.getInterfaceMember(a, bMethodName), isNull); |
+ expect(hierarchy.getInterfaceMember(a, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getInterfaceMember(a, bSetterName, setter: true), isNull); |
+ expect(hierarchy.getInterfaceMember(b, aMethodName), aMethod); |
+ expect(hierarchy.getInterfaceMember(b, bMethodName), bMethod); |
+ expect(hierarchy.getInterfaceMember(b, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getInterfaceMember(b, bSetterName, setter: true), bSetter); |
+ expect(hierarchy.getInterfaceMember(c, aMethodName), aMethod); |
+ expect(hierarchy.getInterfaceMember(c, bMethodName), bMethod); |
+ expect(hierarchy.getInterfaceMember(c, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getInterfaceMember(c, bSetterName, setter: true), bSetter); |
+ } |
+ |
+ void test_getInterfaceMember_implements() { |
+ // Create the class hierarchy: |
+ // |
+ // class A extends Object { |
+ // aMethod() {} |
+ // void set aSetter(_) {} |
+ // } |
+ // class B extends Object implements A { |
+ // bMethod() {} |
+ // void set bSetter(_) {} |
+ // } |
+ // class C extends Object implements B {} |
+ var aMethod = newEmptyMethod('aMethod'); |
+ var aSetter = newEmptySetter('aSetter'); |
+ var bMethod = newEmptyMethod('bMethod'); |
+ var bSetter = newEmptySetter('bSetter'); |
+ var a = addClass(new Class( |
+ name: 'A', supertype: objectSuper, procedures: [aMethod, aSetter])); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ supertype: objectSuper, |
+ implementedTypes: [a.asThisSupertype], |
+ procedures: [bMethod, bSetter])); |
+ var c = addClass(new Class( |
+ name: 'C', |
+ supertype: objectSuper, |
+ implementedTypes: [b.asThisSupertype])); |
+ |
+ var aMethodName = new Name('aMethod'); |
+ var aSetterName = new Name('aSetter'); |
+ var bMethodName = new Name('bMethod'); |
+ var bSetterName = new Name('bSetter'); |
+ expect(hierarchy.getInterfaceMember(a, aMethodName), aMethod); |
+ expect(hierarchy.getInterfaceMember(a, bMethodName), isNull); |
+ expect(hierarchy.getInterfaceMember(a, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getInterfaceMember(a, bSetterName, setter: true), isNull); |
+ expect(hierarchy.getInterfaceMember(b, aMethodName), aMethod); |
+ expect(hierarchy.getInterfaceMember(b, bMethodName), bMethod); |
+ expect(hierarchy.getInterfaceMember(b, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getInterfaceMember(b, bSetterName, setter: true), bSetter); |
+ expect(hierarchy.getInterfaceMember(c, aMethodName), aMethod); |
+ expect(hierarchy.getInterfaceMember(c, bMethodName), bMethod); |
+ expect(hierarchy.getInterfaceMember(c, aSetterName, setter: true), aSetter); |
+ expect(hierarchy.getInterfaceMember(c, bSetterName, setter: true), bSetter); |
+ } |
+ |
+ void test_getRankedSuperclasses() { |
+ // Create the class hierarchy: |
+ // |
+ // Object |
+ // | |
+ // A |
+ // / \ |
+ // B C |
+ // | | |
+ // | D |
+ // \ / |
+ // E |
+ var a = addImplementsClass('A', []); |
+ var b = addImplementsClass('B', [a]); |
+ var c = addImplementsClass('C', [a]); |
+ var d = addImplementsClass('D', [c]); |
+ var e = addImplementsClass('E', [b, d]); |
+ |
+ expect(hierarchy.getRankedSuperclasses(a), [a, objectClass]); |
+ expect(hierarchy.getRankedSuperclasses(b), [b, a, objectClass]); |
+ expect(hierarchy.getRankedSuperclasses(c), [c, a, objectClass]); |
+ expect(hierarchy.getRankedSuperclasses(d), [d, c, a, objectClass]); |
+ if (hierarchy.getClassIndex(b) < hierarchy.getClassIndex(c)) { |
+ expect(hierarchy.getRankedSuperclasses(e), [e, d, b, c, a, objectClass]); |
+ } else { |
+ expect(hierarchy.getRankedSuperclasses(e), [e, d, c, b, a, objectClass]); |
+ } |
+ } |
+ |
+ void test_getTypeAsInstanceOf_generic_extends() { |
+ // Create the class hierarchy: |
+ // |
+ // class A<T, U> extends Object {} |
+ // class B<T> extends A<T, bool> {} |
+ var int = coreTypes.intClass.rawType; |
+ var bool = coreTypes.boolClass.rawType; |
+ |
+ var a = addGenericClass('A', ['T', 'U']); |
+ |
+ var bT = new TypeParameter('T', objectClass.rawType); |
+ var bTT = new TypeParameterType(bT); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ typeParameters: [bT], |
+ supertype: new Supertype(a, [bTT, bool]))); |
+ |
+ var b_int = new InterfaceType(b, [int]); |
+ expect(hierarchy.getTypeAsInstanceOf(b_int, a), |
+ new InterfaceType(a, [int, bool])); |
+ expect(hierarchy.getTypeAsInstanceOf(b_int, objectClass), |
+ new InterfaceType(objectClass)); |
+ } |
+ |
+ void test_rootClass() { |
+ addClass(new Class(name: 'A', supertype: objectSuper)); |
+ expect(hierarchy.rootClass, objectClass); |
+ } |
+ |
+ void _assertOverridePairs(Class class_, List<String> expected) { |
+ List<String> overrideDescriptions = []; |
+ hierarchy.forEachOverridePair(class_, |
+ (Member declaredMember, Member interfaceMember, bool isSetter) { |
+ var desc = '$declaredMember overrides $interfaceMember'; |
+ overrideDescriptions.add(desc); |
+ }); |
+ expect(overrideDescriptions, unorderedEquals(expected)); |
+ } |
+} |