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 |
index a05464f29ffa61529b30cb5894526927b29202b5..3873b4824a012fb1e2530d04881cacdb626270bc 100644 |
--- a/pkg/kernel/test/class_hierarchy_test.dart |
+++ b/pkg/kernel/test/class_hierarchy_test.dart |
@@ -129,6 +129,13 @@ abstract class _ClassHierarchyTest { |
ClassHierarchy createClassHierarchy(Program program); |
+ Procedure newEmptyGetter(String name, |
+ {DartType returnType: const DynamicType()}) { |
+ var body = new Block([new ReturnStatement(new NullLiteral())]); |
+ return new Procedure(new Name(name), ProcedureKind.Getter, |
+ new FunctionNode(body, returnType: returnType)); |
+ } |
+ |
Procedure newEmptyMethod(String name, {bool isAbstract: false}) { |
var body = isAbstract ? null : new Block([]); |
return new Procedure(new Name(name), ProcedureKind.Method, |
@@ -136,14 +143,15 @@ abstract class _ClassHierarchyTest { |
isAbstract: isAbstract); |
} |
- Procedure newEmptySetter(String name, {bool abstract: false}) { |
+ Procedure newEmptySetter(String name, |
+ {bool abstract: false, DartType type: const DynamicType()}) { |
var body = abstract ? null : new Block([]); |
return new Procedure( |
new Name(name), |
ProcedureKind.Setter, |
new FunctionNode(body, |
returnType: const VoidType(), |
- positionalParameters: [new VariableDeclaration('_')])); |
+ positionalParameters: [new VariableDeclaration('_', type: type)])); |
} |
void setUp() { |
@@ -157,6 +165,88 @@ abstract class _ClassHierarchyTest { |
program.libraries.add(library); |
} |
+ void test_forEachOverridePair_crossGetterSetter_extends() { |
+ var int = coreTypes.intClass.rawType; |
+ var a = addClass(new Class(name: 'A', supertype: objectSuper, procedures: [ |
+ newEmptySetter('foo', type: int), |
+ newEmptyGetter('bar', returnType: int) |
+ ])); |
+ var b = addClass(new Class( |
+ name: 'B', |
+ supertype: a.asThisSupertype, |
+ procedures: [newEmptyGetter('foo'), newEmptySetter('bar')])); |
+ |
+ _assertTestLibraryText(''' |
+class A { |
+ set foo(core::int _) → void {} |
+ get bar() → core::int { |
+ return null; |
+ } |
+} |
+class B extends self::A { |
+ get foo() → dynamic { |
+ return null; |
+ } |
+ set bar(dynamic _) → void {} |
+} |
+'''); |
+ |
+ // No overrides of getters with getters, or setters with setters. |
+ _assertOverridePairs(b, []); |
+ |
+ // Has cross-overrides between getters and setters. |
+ _assertOverridePairs( |
+ b, |
+ [ |
+ 'test::B::foo overrides test::A::foo=', |
+ 'test::B::bar= overrides test::A::bar' |
+ ], |
+ crossGettersSetters: true); |
+ } |
+ |
+ void test_forEachOverridePair_crossGetterSetter_implements() { |
+ var int = coreTypes.intClass.rawType; |
+ var double = coreTypes.doubleClass.rawType; |
+ var a = addClass(new Class(name: 'A', supertype: objectSuper, procedures: [ |
+ newEmptySetter('foo', type: int), |
+ ])); |
+ var b = addClass(new Class(name: 'B', supertype: objectSuper, procedures: [ |
+ newEmptySetter('foo', type: double), |
+ ])); |
+ var c = addClass(new Class( |
+ name: 'C', |
+ supertype: objectSuper, |
+ implementedTypes: [a.asThisSupertype, b.asThisSupertype], |
+ procedures: [newEmptyGetter('foo')])); |
+ |
+ _assertTestLibraryText(''' |
+class A { |
+ set foo(core::int _) → void {} |
+} |
+class B { |
+ set foo(core::double _) → void {} |
+} |
+class C implements self::A, self::B { |
+ get foo() → dynamic { |
+ return null; |
+ } |
+} |
+'''); |
+ |
+ // No overrides of getters with getters, or setters with setters. |
+ _assertOverridePairs(c, []); |
+ |
+ // Has cross-overrides between getters and setters. |
+ // Even if these overrides are incompatible with each other. |
+ _assertOverridePairs( |
+ c, |
+ [ |
+ 'test::C::foo overrides test::A::foo=', |
+ 'test::C::foo overrides test::B::foo=', |
+ ], |
+ crossGettersSetters: true); |
+ } |
+ |
/// 2. A non-abstract member is inherited from a superclass, and in the |
/// context of this class, it overrides an abstract member inheritable through |
/// one of its superinterfaces. |
@@ -902,15 +992,25 @@ class B<T> extends self::A<self::B::T, core::bool> {} |
new InterfaceType(objectClass)); |
} |
- void _assertOverridePairs(Class class_, List<String> expected) { |
+ void _assertOverridePairs(Class class_, List<String> expected, |
+ {bool crossGettersSetters: false}) { |
List<String> overrideDescriptions = []; |
hierarchy.forEachOverridePair(class_, |
(Member declaredMember, Member interfaceMember, bool isSetter) { |
- String declaredName = '$declaredMember${isSetter ? '=': ''}'; |
- String interfaceName = '$interfaceMember${isSetter ? '=': ''}'; |
+ String declaredSuffix; |
+ String interfaceSuffix; |
+ if (crossGettersSetters) { |
+ declaredSuffix = _isSetter(declaredMember) ? '=' : ''; |
+ interfaceSuffix = _isSetter(interfaceMember) ? '=' : ''; |
+ } else { |
+ declaredSuffix = isSetter ? '=' : ''; |
+ interfaceSuffix = isSetter ? '=' : ''; |
+ } |
+ String declaredName = '$declaredMember$declaredSuffix'; |
+ String interfaceName = '$interfaceMember$interfaceSuffix'; |
var desc = '$declaredName overrides $interfaceName'; |
overrideDescriptions.add(desc); |
- }); |
+ }, crossGettersSetters: crossGettersSetters); |
expect(overrideDescriptions, unorderedEquals(expected)); |
} |
@@ -936,11 +1036,15 @@ import "dart:core" as core; |
actualText = actualText.replaceAll('{\n}', '{}'); |
actualText = actualText.replaceAll(' extends core::Object', ''); |
-// if (actualText != expectedText) { |
-// print('-------- Actual --------'); |
-// print(actualText + '------------------------'); |
-// } |
+ if (actualText != expectedText) { |
+ print('-------- Actual --------'); |
+ print(actualText + '------------------------'); |
+ } |
expect(actualText, expectedText); |
} |
+ |
+ static bool _isSetter(Member member) { |
+ return member is Procedure && member.kind == ProcedureKind.Setter; |
+ } |
} |