Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Unified Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 1430953004: Check field overrides (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: fix typo Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/task/strong/info.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/task/strong/checker.dart
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index d43a594a660f443a5420865bb3ec5a571c15f276..5a6bcaa262e94275f2ccbac1c23eb0771392b4f0 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -51,9 +51,10 @@ class _OverrideChecker {
var errorLocation = node.withClause.mixinTypes[i];
for (int j = i - 1; j >= 0; j--) {
_checkIndividualOverridesFromType(
- current, mixins[j], errorLocation, seen);
+ current, mixins[j], errorLocation, seen, true);
}
- _checkIndividualOverridesFromType(current, parent, errorLocation, seen);
+ _checkIndividualOverridesFromType(
+ current, parent, errorLocation, seen, true);
}
}
@@ -85,9 +86,9 @@ class _OverrideChecker {
var visited = new Set<InterfaceType>();
do {
visited.add(current);
- current.mixins.reversed
- .forEach((m) => _checkIndividualOverridesFromClass(node, m, seen));
- _checkIndividualOverridesFromClass(node, current.superclass, seen);
+ current.mixins.reversed.forEach(
+ (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
+ _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
current = current.superclass;
} while (!current.isObject && !visited.contains(current));
}
@@ -171,10 +172,10 @@ class _OverrideChecker {
// Check direct overrides on [type]
for (var interfaceType in interfaces) {
if (node != null) {
- _checkIndividualOverridesFromClass(node, interfaceType, seen);
+ _checkIndividualOverridesFromClass(node, interfaceType, seen, false);
} else {
_checkIndividualOverridesFromType(
- type, interfaceType, errorLocation, seen);
+ type, interfaceType, errorLocation, seen, false);
}
}
@@ -186,7 +187,7 @@ class _OverrideChecker {
// We copy [seen] so we can report separately if more than one mixin or
// the base class have an invalid override.
_checkIndividualOverridesFromType(
- type.mixins[i], interfaceType, loc, new Set.from(seen));
+ type.mixins[i], interfaceType, loc, new Set.from(seen), false);
}
}
@@ -212,12 +213,16 @@ class _OverrideChecker {
/// is used when invoking this function multiple times when checking several
/// types in a class hierarchy. Errors are reported only the first time an
/// invalid override involving a specific member is encountered.
- _checkIndividualOverridesFromType(InterfaceType subType,
- InterfaceType baseType, AstNode errorLocation, Set<String> seen) {
+ _checkIndividualOverridesFromType(
+ InterfaceType subType,
+ InterfaceType baseType,
+ AstNode errorLocation,
+ Set<String> seen,
+ bool isSubclass) {
void checkHelper(ExecutableElement e) {
if (e.isStatic) return;
if (seen.contains(e.name)) return;
- if (_checkSingleOverride(e, baseType, null, errorLocation)) {
+ if (_checkSingleOverride(e, baseType, null, errorLocation, isSubclass)) {
seen.add(e.name);
}
}
@@ -230,8 +235,8 @@ class _OverrideChecker {
///
/// The [errorLocation] node indicates where errors are reported, see
/// [_checkSingleOverride] for more details.
- _checkIndividualOverridesFromClass(
- ClassDeclaration node, InterfaceType baseType, Set<String> seen) {
+ _checkIndividualOverridesFromClass(ClassDeclaration node,
+ InterfaceType baseType, Set<String> seen, bool isSubclass) {
for (var member in node.members) {
if (member is ConstructorDeclaration) continue;
if (member is FieldDeclaration) {
@@ -242,10 +247,12 @@ class _OverrideChecker {
if (seen.contains(name)) continue;
var getter = element.getter;
var setter = element.setter;
- bool found = _checkSingleOverride(getter, baseType, variable, member);
+ bool found = _checkSingleOverride(
+ getter, baseType, variable, member, isSubclass);
if (!variable.isFinal &&
!variable.isConst &&
- _checkSingleOverride(setter, baseType, variable, member)) {
+ _checkSingleOverride(
+ setter, baseType, variable, member, isSubclass)) {
found = true;
}
if (found) seen.add(name);
@@ -254,7 +261,8 @@ class _OverrideChecker {
if ((member as MethodDeclaration).isStatic) continue;
var method = (member as MethodDeclaration).element;
if (seen.contains(method.name)) continue;
- if (_checkSingleOverride(method, baseType, member, member)) {
+ if (_checkSingleOverride(
+ method, baseType, member, member, isSubclass)) {
seen.add(method.name);
}
}
@@ -288,14 +296,23 @@ class _OverrideChecker {
/// the AST node that defines [element]. This is used to determine whether the
/// type of the element could be inferred from the types in the super classes.
bool _checkSingleOverride(ExecutableElement element, InterfaceType type,
- AstNode node, AstNode errorLocation) {
+ AstNode node, AstNode errorLocation, bool isSubclass) {
assert(!element.isStatic);
FunctionType subType = _rules.elementType(element);
// TODO(vsm): Test for generic
FunctionType baseType = _getMemberType(type, element);
-
if (baseType == null) return false;
+
+ if (isSubclass && element is PropertyAccessorElement) {
+ // Disallow any overriding if the base class defines this member
+ // as a field. We effectively treat fields as final / non-virtual.
+ PropertyInducingElement field = _getMemberField(type, element);
+ if (field != null) {
+ _recordMessage(new InvalidFieldOverride(
+ errorLocation, element, type, subType, baseType));
+ }
+ }
if (!_rules.isAssignable(subType, baseType)) {
// See whether non-assignable cases fit one of our common patterns:
//
@@ -948,6 +965,33 @@ class CodeChecker extends RecursiveAstVisitor {
}
}
+// Return the field on type corresponding to member, or null if none
+// exists or the "field" is actually a getter/setter.
+PropertyInducingElement _getMemberField(
+ InterfaceType type, PropertyAccessorElement member) {
+ String memberName = member.name;
+ PropertyInducingElement field;
+ if (member.isGetter) {
+ // The subclass member is an explicit getter or a field
+ // - lookup the getter on the superclass.
+ var getter = type.getGetter(memberName);
+ if (getter == null || getter.isStatic) return null;
+ field = getter.variable;
+ } else if (!member.isSynthetic) {
+ // The subclass member is an explicit setter
+ // - lookup the setter on the superclass.
+ // Note: an implicit (synthetic) setter would have already been flagged on
+ // the getter above.
+ var setter = type.getSetter(memberName);
+ if (setter == null || setter.isStatic) return null;
+ field = setter.variable;
+ } else {
+ return null;
+ }
+ if (field.isSynthetic) return null;
+ return field;
+}
+
/// Looks up the declaration that matches [member] in [type] and returns it's
/// declared type.
FunctionType _getMemberType(InterfaceType type, ExecutableElement member) =>
@@ -962,6 +1006,15 @@ _MemberTypeGetter _memberTypeGetter(ExecutableElement member) {
FunctionType f(InterfaceType type) {
ExecutableElement baseMethod;
+
+ if (member.isPrivate) {
+ var subtypeLibrary = member.library;
+ var baseLibrary = type.element.library;
+ if (baseLibrary != subtypeLibrary) {
+ return null;
+ }
+ }
+
try {
if (isGetter) {
assert(!isSetter);
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/task/strong/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698