@@ -51,9 +51,10 @@ class _OverrideChecker {
51
51
var errorLocation = node.withClause.mixinTypes[i];
52
52
for (int j = i - 1 ; j >= 0 ; j-- ) {
53
53
_checkIndividualOverridesFromType (
54
- current, mixins[j], errorLocation, seen);
54
+ current, mixins[j], errorLocation, seen, true );
55
55
}
56
- _checkIndividualOverridesFromType (current, parent, errorLocation, seen);
56
+ _checkIndividualOverridesFromType (
57
+ current, parent, errorLocation, seen, true );
57
58
}
58
59
}
59
60
@@ -85,9 +86,9 @@ class _OverrideChecker {
85
86
var visited = new Set <InterfaceType >();
86
87
do {
87
88
visited.add (current);
88
- current.mixins.reversed
89
- . forEach (( m) => _checkIndividualOverridesFromClass (node, m, seen));
90
- _checkIndividualOverridesFromClass (node, current.superclass, seen);
89
+ current.mixins.reversed. forEach (
90
+ ( m) => _checkIndividualOverridesFromClass (node, m, seen, true ));
91
+ _checkIndividualOverridesFromClass (node, current.superclass, seen, true );
91
92
current = current.superclass;
92
93
} while (! current.isObject && ! visited.contains (current));
93
94
}
@@ -171,10 +172,10 @@ class _OverrideChecker {
171
172
// Check direct overrides on [type]
172
173
for (var interfaceType in interfaces) {
173
174
if (node != null ) {
174
- _checkIndividualOverridesFromClass (node, interfaceType, seen);
175
+ _checkIndividualOverridesFromClass (node, interfaceType, seen, false );
175
176
} else {
176
177
_checkIndividualOverridesFromType (
177
- type, interfaceType, errorLocation, seen);
178
+ type, interfaceType, errorLocation, seen, false );
178
179
}
179
180
}
180
181
@@ -186,7 +187,7 @@ class _OverrideChecker {
186
187
// We copy [seen] so we can report separately if more than one mixin or
187
188
// the base class have an invalid override.
188
189
_checkIndividualOverridesFromType (
189
- type.mixins[i], interfaceType, loc, new Set .from (seen));
190
+ type.mixins[i], interfaceType, loc, new Set .from (seen), false );
190
191
}
191
192
}
192
193
@@ -212,12 +213,16 @@ class _OverrideChecker {
212
213
/// is used when invoking this function multiple times when checking several
213
214
/// types in a class hierarchy. Errors are reported only the first time an
214
215
/// invalid override involving a specific member is encountered.
215
- _checkIndividualOverridesFromType (InterfaceType subType,
216
- InterfaceType baseType, AstNode errorLocation, Set <String > seen) {
216
+ _checkIndividualOverridesFromType (
217
+ InterfaceType subType,
218
+ InterfaceType baseType,
219
+ AstNode errorLocation,
220
+ Set <String > seen,
221
+ bool isSubclass) {
217
222
void checkHelper (ExecutableElement e) {
218
223
if (e.isStatic) return ;
219
224
if (seen.contains (e.name)) return ;
220
- if (_checkSingleOverride (e, baseType, null , errorLocation)) {
225
+ if (_checkSingleOverride (e, baseType, null , errorLocation, isSubclass )) {
221
226
seen.add (e.name);
222
227
}
223
228
}
@@ -230,8 +235,8 @@ class _OverrideChecker {
230
235
///
231
236
/// The [errorLocation] node indicates where errors are reported, see
232
237
/// [_checkSingleOverride] for more details.
233
- _checkIndividualOverridesFromClass (
234
- ClassDeclaration node, InterfaceType baseType, Set <String > seen) {
238
+ _checkIndividualOverridesFromClass (ClassDeclaration node,
239
+ InterfaceType baseType, Set <String > seen, bool isSubclass ) {
235
240
for (var member in node.members) {
236
241
if (member is ConstructorDeclaration ) continue ;
237
242
if (member is FieldDeclaration ) {
@@ -242,10 +247,12 @@ class _OverrideChecker {
242
247
if (seen.contains (name)) continue ;
243
248
var getter = element.getter;
244
249
var setter = element.setter;
245
- bool found = _checkSingleOverride (getter, baseType, variable, member);
250
+ bool found = _checkSingleOverride (
251
+ getter, baseType, variable, member, isSubclass);
246
252
if (! variable.isFinal &&
247
253
! variable.isConst &&
248
- _checkSingleOverride (setter, baseType, variable, member)) {
254
+ _checkSingleOverride (
255
+ setter, baseType, variable, member, isSubclass)) {
249
256
found = true ;
250
257
}
251
258
if (found) seen.add (name);
@@ -254,7 +261,8 @@ class _OverrideChecker {
254
261
if ((member as MethodDeclaration ).isStatic) continue ;
255
262
var method = (member as MethodDeclaration ).element;
256
263
if (seen.contains (method.name)) continue ;
257
- if (_checkSingleOverride (method, baseType, member, member)) {
264
+ if (_checkSingleOverride (
265
+ method, baseType, member, member, isSubclass)) {
258
266
seen.add (method.name);
259
267
}
260
268
}
@@ -288,14 +296,23 @@ class _OverrideChecker {
288
296
/// the AST node that defines [element] . This is used to determine whether the
289
297
/// type of the element could be inferred from the types in the super classes.
290
298
bool _checkSingleOverride (ExecutableElement element, InterfaceType type,
291
- AstNode node, AstNode errorLocation) {
299
+ AstNode node, AstNode errorLocation, bool isSubclass ) {
292
300
assert (! element.isStatic);
293
301
294
302
FunctionType subType = _rules.elementType (element);
295
303
// TODO(vsm): Test for generic
296
304
FunctionType baseType = _getMemberType (type, element);
297
-
298
305
if (baseType == null ) return false ;
306
+
307
+ if (isSubclass && element is PropertyAccessorElement ) {
308
+ // Disallow any overriding if the base class defines this member
309
+ // as a field. We effectively treat fields as final / non-virtual.
310
+ PropertyInducingElement field = _getMemberField (type, element);
311
+ if (field != null ) {
312
+ _recordMessage (new InvalidFieldOverride (
313
+ errorLocation, element, type, subType, baseType));
314
+ }
315
+ }
299
316
if (! _rules.isAssignable (subType, baseType)) {
300
317
// See whether non-assignable cases fit one of our common patterns:
301
318
//
@@ -948,6 +965,33 @@ class CodeChecker extends RecursiveAstVisitor {
948
965
}
949
966
}
950
967
968
+ // Return the field on type corresponding to member, or null if none
969
+ // exists or the "field" is actually a getter/setter.
970
+ PropertyInducingElement _getMemberField (
971
+ InterfaceType type, PropertyAccessorElement member) {
972
+ String memberName = member.name;
973
+ PropertyInducingElement field;
974
+ if (member.isGetter) {
975
+ // The subclass member is an explicit getter or a field
976
+ // - lookup the getter on the superclass.
977
+ var getter = type.getGetter (memberName);
978
+ if (getter == null || getter.isStatic) return null ;
979
+ field = getter.variable;
980
+ } else if (! member.isSynthetic) {
981
+ // The subclass member is an explicit setter
982
+ // - lookup the setter on the superclass.
983
+ // Note: an implicit (synthetic) setter would have already been flagged on
984
+ // the getter above.
985
+ var setter = type.getSetter (memberName);
986
+ if (setter == null || setter.isStatic) return null ;
987
+ field = setter.variable;
988
+ } else {
989
+ return null ;
990
+ }
991
+ if (field.isSynthetic) return null ;
992
+ return field;
993
+ }
994
+
951
995
/// Looks up the declaration that matches [member] in [type] and returns it's
952
996
/// declared type.
953
997
FunctionType _getMemberType (InterfaceType type, ExecutableElement member) =>
@@ -962,6 +1006,15 @@ _MemberTypeGetter _memberTypeGetter(ExecutableElement member) {
962
1006
963
1007
FunctionType f (InterfaceType type) {
964
1008
ExecutableElement baseMethod;
1009
+
1010
+ if (member.isPrivate) {
1011
+ var subtypeLibrary = member.library;
1012
+ var baseLibrary = type.element.library;
1013
+ if (baseLibrary != subtypeLibrary) {
1014
+ return null ;
1015
+ }
1016
+ }
1017
+
965
1018
try {
966
1019
if (isGetter) {
967
1020
assert (! isSetter);
0 commit comments