| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be | 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be |
| 6 // refactored to fit into analyzer. | 6 // refactored to fit into analyzer. |
| 7 library analyzer.src.task.strong.checker; | 7 library analyzer.src.task.strong.checker; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 node.visitChildren(this); | 290 node.visitChildren(this); |
| 291 } | 291 } |
| 292 | 292 |
| 293 @override | 293 @override |
| 294 void visitClassDeclaration(ClassDeclaration node) { | 294 void visitClassDeclaration(ClassDeclaration node) { |
| 295 _overrideChecker.check(node); | 295 _overrideChecker.check(node); |
| 296 super.visitClassDeclaration(node); | 296 super.visitClassDeclaration(node); |
| 297 } | 297 } |
| 298 | 298 |
| 299 @override | 299 @override |
| 300 void visitClassTypeAlias(ClassTypeAlias node) { |
| 301 _overrideChecker.check(node); |
| 302 super.visitClassTypeAlias(node); |
| 303 } |
| 304 |
| 305 @override |
| 300 void visitComment(Comment node) { | 306 void visitComment(Comment node) { |
| 301 // skip, no need to do typechecking inside comments (they may contain | 307 // skip, no need to do typechecking inside comments (they may contain |
| 302 // comment references which would require resolution). | 308 // comment references which would require resolution). |
| 303 } | 309 } |
| 304 | 310 |
| 305 @override | 311 @override |
| 306 void visitCompilationUnit(CompilationUnit node) { | 312 void visitCompilationUnit(CompilationUnit node) { |
| 307 _hasImplicitCasts = false; | 313 _hasImplicitCasts = false; |
| 308 node.visitChildren(this); | 314 node.visitChildren(this); |
| 309 setHasImplicitCasts(node, _hasImplicitCasts); | 315 setHasImplicitCasts(node, _hasImplicitCasts); |
| (...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1227 /// check overrides between classes and superclasses, interfaces, and mixin | 1233 /// check overrides between classes and superclasses, interfaces, and mixin |
| 1228 /// applications. | 1234 /// applications. |
| 1229 class _OverrideChecker { | 1235 class _OverrideChecker { |
| 1230 final StrongTypeSystemImpl rules; | 1236 final StrongTypeSystemImpl rules; |
| 1231 final CodeChecker _checker; | 1237 final CodeChecker _checker; |
| 1232 | 1238 |
| 1233 _OverrideChecker(CodeChecker checker) | 1239 _OverrideChecker(CodeChecker checker) |
| 1234 : _checker = checker, | 1240 : _checker = checker, |
| 1235 rules = checker.rules; | 1241 rules = checker.rules; |
| 1236 | 1242 |
| 1237 void check(ClassDeclaration node) { | 1243 void check(Declaration node) { |
| 1238 if (resolutionMap.elementDeclaredByClassDeclaration(node).type.isObject) | 1244 var element = |
| 1245 resolutionMap.elementDeclaredByDeclaration(node) as ClassElement; |
| 1246 if (element.type.isObject) { |
| 1239 return; | 1247 return; |
| 1240 _checkSuperOverrides(node); | 1248 } |
| 1241 _checkMixinApplicationOverrides(node); | 1249 _checkSuperOverrides(node, element); |
| 1242 _checkAllInterfaceOverrides(node); | 1250 _checkMixinApplicationOverrides(node, element); |
| 1251 _checkAllInterfaceOverrides(node, element); |
| 1243 } | 1252 } |
| 1244 | 1253 |
| 1245 /// Checks that implementations correctly override all reachable interfaces. | 1254 /// Checks that implementations correctly override all reachable interfaces. |
| 1246 /// In particular, we need to check these overrides for the definitions in | 1255 /// In particular, we need to check these overrides for the definitions in |
| 1247 /// the class itself and each its superclasses. If a superclass is not | 1256 /// the class itself and each its superclasses. If a superclass is not |
| 1248 /// abstract, then we can skip its transitive interfaces. For example, in: | 1257 /// abstract, then we can skip its transitive interfaces. For example, in: |
| 1249 /// | 1258 /// |
| 1250 /// B extends C implements G | 1259 /// B extends C implements G |
| 1251 /// A extends B with E, F implements H, I | 1260 /// A extends B with E, F implements H, I |
| 1252 /// | 1261 /// |
| 1253 /// we check: | 1262 /// we check: |
| 1254 /// | 1263 /// |
| 1255 /// C against G, H, and I | 1264 /// C against G, H, and I |
| 1256 /// B against G, H, and I | 1265 /// B against G, H, and I |
| 1257 /// E against H and I // no check against G because B is a concrete class | 1266 /// E against H and I // no check against G because B is a concrete class |
| 1258 /// F against H and I | 1267 /// F against H and I |
| 1259 /// A against H and I | 1268 /// A against H and I |
| 1260 void _checkAllInterfaceOverrides(ClassDeclaration node) { | 1269 void _checkAllInterfaceOverrides(Declaration node, ClassElement element) { |
| 1261 var seen = new Set<String>(); | 1270 var seen = new Set<String>(); |
| 1262 // Helper function to collect all reachable interfaces. | 1271 // Helper function to collect all reachable interfaces. |
| 1263 find(InterfaceType interfaceType, Set result) { | 1272 find(InterfaceType interfaceType, Set result) { |
| 1264 if (interfaceType == null || interfaceType.isObject) return; | 1273 if (interfaceType == null || interfaceType.isObject) return; |
| 1265 if (result.contains(interfaceType)) return; | 1274 if (result.contains(interfaceType)) return; |
| 1266 result.add(interfaceType); | 1275 result.add(interfaceType); |
| 1267 find(interfaceType.superclass, result); | 1276 find(interfaceType.superclass, result); |
| 1268 interfaceType.mixins.forEach((i) => find(i, result)); | 1277 interfaceType.mixins.forEach((i) => find(i, result)); |
| 1269 interfaceType.interfaces.forEach((i) => find(i, result)); | 1278 interfaceType.interfaces.forEach((i) => find(i, result)); |
| 1270 } | 1279 } |
| 1271 | 1280 |
| 1272 // Check all interfaces reachable from the `implements` clause in the | 1281 // Check all interfaces reachable from the `implements` clause in the |
| 1273 // current class against definitions here and in superclasses. | 1282 // current class against definitions here and in superclasses. |
| 1274 var localInterfaces = new Set<InterfaceType>(); | 1283 var localInterfaces = new Set<InterfaceType>(); |
| 1275 var type = resolutionMap.elementDeclaredByClassDeclaration(node).type; | 1284 var type = element.type; |
| 1276 type.interfaces.forEach((i) => find(i, localInterfaces)); | 1285 type.interfaces.forEach((i) => find(i, localInterfaces)); |
| 1277 _checkInterfacesOverrides(node, localInterfaces, seen, | 1286 _checkInterfacesOverrides(type, localInterfaces, seen, |
| 1278 includeParents: true); | 1287 includeParents: true, classNode: node); |
| 1279 | 1288 |
| 1280 // Check also how we override locally the interfaces from parent classes if | 1289 // Check also how we override locally the interfaces from parent classes if |
| 1281 // the parent class is abstract. Otherwise, these will be checked as | 1290 // the parent class is abstract. Otherwise, these will be checked as |
| 1282 // overrides on the concrete superclass. | 1291 // overrides on the concrete superclass. |
| 1283 var superInterfaces = new Set<InterfaceType>(); | 1292 var superInterfaces = new Set<InterfaceType>(); |
| 1284 var parent = type.superclass; | 1293 var parent = type.superclass; |
| 1285 // TODO(sigmund): we don't seem to be reporting the analyzer error that a | 1294 // TODO(sigmund): we don't seem to be reporting the analyzer error that a |
| 1286 // non-abstract class is not implementing an interface. See | 1295 // non-abstract class is not implementing an interface. See |
| 1287 // https://github.com/dart-lang/dart-dev-compiler/issues/25 | 1296 // https://github.com/dart-lang/dart-dev-compiler/issues/25 |
| 1288 while (parent != null && parent.element.isAbstract) { | 1297 while (parent != null && parent.element.isAbstract) { |
| 1289 parent.interfaces.forEach((i) => find(i, superInterfaces)); | 1298 parent.interfaces.forEach((i) => find(i, superInterfaces)); |
| 1290 parent = parent.superclass; | 1299 parent = parent.superclass; |
| 1291 } | 1300 } |
| 1292 _checkInterfacesOverrides(node, superInterfaces, seen, | 1301 _checkInterfacesOverrides(type, superInterfaces, seen, |
| 1293 includeParents: false); | 1302 includeParents: false, classNode: node); |
| 1294 } | 1303 } |
| 1295 | 1304 |
| 1296 /// Check that individual methods and fields in [node] correctly override | 1305 /// Check that individual methods and fields in [node] correctly override |
| 1297 /// the declarations in [baseType]. | 1306 /// the declarations in [baseType]. |
| 1298 /// | 1307 /// |
| 1299 /// The [errorLocation] node indicates where errors are reported, see | 1308 /// The [errorLocation] node indicates where errors are reported, see |
| 1300 /// [_checkSingleOverride] for more details. | 1309 /// [_checkSingleOverride] for more details. |
| 1301 _checkIndividualOverridesFromClass(ClassDeclaration node, | 1310 _checkIndividualOverridesFromClass(Declaration node, InterfaceType baseType, |
| 1302 InterfaceType baseType, Set<String> seen, bool isSubclass) { | 1311 Set<String> seen, bool isSubclass) { |
| 1303 for (var member in node.members) { | 1312 for (var member in _classMembers(node)) { |
| 1304 if (member is FieldDeclaration) { | 1313 if (member is FieldDeclaration) { |
| 1305 if (member.isStatic) { | 1314 if (member.isStatic) { |
| 1306 continue; | 1315 continue; |
| 1307 } | 1316 } |
| 1308 for (var variable in member.fields.variables) { | 1317 for (var variable in member.fields.variables) { |
| 1309 var element = variable.element as PropertyInducingElement; | 1318 var element = variable.element as PropertyInducingElement; |
| 1310 var name = element.name; | 1319 var name = element.name; |
| 1311 if (seen.contains(name)) { | 1320 if (seen.contains(name)) { |
| 1312 continue; | 1321 continue; |
| 1313 } | 1322 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 | 1382 |
| 1374 /// Checks that [cls] and its super classes (including mixins) correctly | 1383 /// Checks that [cls] and its super classes (including mixins) correctly |
| 1375 /// overrides each interface in [interfaces]. If [includeParents] is false, | 1384 /// overrides each interface in [interfaces]. If [includeParents] is false, |
| 1376 /// then mixins are still checked, but the base type and it's transitive | 1385 /// then mixins are still checked, but the base type and it's transitive |
| 1377 /// supertypes are not. | 1386 /// supertypes are not. |
| 1378 /// | 1387 /// |
| 1379 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For | 1388 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For |
| 1380 /// [ClassDeclaration]s errors are reported on the member that contains the | 1389 /// [ClassDeclaration]s errors are reported on the member that contains the |
| 1381 /// invalid override, for [InterfaceType]s we use [errorLocation] instead. | 1390 /// invalid override, for [InterfaceType]s we use [errorLocation] instead. |
| 1382 void _checkInterfacesOverrides( | 1391 void _checkInterfacesOverrides( |
| 1383 cls, Iterable<InterfaceType> interfaces, Set<String> seen, | 1392 InterfaceType type, Iterable<InterfaceType> interfaces, Set<String> seen, |
| 1384 {Set<InterfaceType> visited, | 1393 {Set<InterfaceType> visited, |
| 1385 bool includeParents: true, | 1394 bool includeParents: true, |
| 1386 AstNode errorLocation}) { | 1395 AstNode errorLocation, |
| 1387 var node = cls is ClassDeclaration ? cls : null; | 1396 Declaration classNode}) { |
| 1388 var type = cls is InterfaceType | |
| 1389 ? cls | |
| 1390 : resolutionMap.elementDeclaredByClassDeclaration(node).type; | |
| 1391 | |
| 1392 if (visited == null) { | 1397 if (visited == null) { |
| 1393 visited = new Set<InterfaceType>(); | 1398 visited = new Set<InterfaceType>(); |
| 1394 } else if (visited.contains(type)) { | 1399 } else if (visited.contains(type)) { |
| 1395 // Malformed type. | 1400 // Malformed type. |
| 1396 return; | 1401 return; |
| 1397 } else { | 1402 } else { |
| 1398 visited.add(type); | 1403 visited.add(type); |
| 1399 } | 1404 } |
| 1400 | 1405 |
| 1401 // Check direct overrides on [type] | 1406 // Check direct overrides on [type] |
| 1402 for (var interfaceType in interfaces) { | 1407 for (var interfaceType in interfaces) { |
| 1403 if (node != null) { | 1408 if (classNode != null) { |
| 1404 _checkIndividualOverridesFromClass(node, interfaceType, seen, false); | 1409 _checkIndividualOverridesFromClass( |
| 1410 classNode, interfaceType, seen, false); |
| 1405 } else { | 1411 } else { |
| 1406 _checkIndividualOverridesFromType( | 1412 _checkIndividualOverridesFromType( |
| 1407 type, interfaceType, errorLocation, seen, false); | 1413 type, interfaceType, errorLocation, seen, false); |
| 1408 } | 1414 } |
| 1409 } | 1415 } |
| 1410 | 1416 |
| 1411 // Check overrides from its mixins | 1417 // Check overrides from its mixins |
| 1412 for (int i = 0; i < type.mixins.length; i++) { | 1418 for (int i = 0; i < type.mixins.length; i++) { |
| 1413 var loc = errorLocation ?? node.withClause.mixinTypes[i]; | 1419 var loc = errorLocation ?? _withClause(classNode).mixinTypes[i]; |
| 1414 for (var interfaceType in interfaces) { | 1420 for (var interfaceType in interfaces) { |
| 1415 // We copy [seen] so we can report separately if more than one mixin or | 1421 // We copy [seen] so we can report separately if more than one mixin or |
| 1416 // the base class have an invalid override. | 1422 // the base class have an invalid override. |
| 1417 _checkIndividualOverridesFromType( | 1423 _checkIndividualOverridesFromType( |
| 1418 type.mixins[i], interfaceType, loc, new Set.from(seen), false); | 1424 type.mixins[i], interfaceType, loc, new Set.from(seen), false); |
| 1419 } | 1425 } |
| 1420 } | 1426 } |
| 1421 | 1427 |
| 1422 // Check overrides from its superclasses | 1428 // Check overrides from its superclasses |
| 1423 if (includeParents) { | 1429 if (includeParents) { |
| 1424 var parent = type.superclass; | 1430 var parent = type.superclass; |
| 1425 if (parent.isObject) { | 1431 if (parent.isObject) { |
| 1426 return; | 1432 return; |
| 1427 } | 1433 } |
| 1428 var loc = errorLocation ?? node.extendsClause; | 1434 var loc = errorLocation ?? _extendsErrorLocation(classNode); |
| 1429 // No need to copy [seen] here because we made copies above when reporting | 1435 // No need to copy [seen] here because we made copies above when reporting |
| 1430 // errors on mixins. | 1436 // errors on mixins. |
| 1431 _checkInterfacesOverrides(parent, interfaces, seen, | 1437 _checkInterfacesOverrides(parent, interfaces, seen, |
| 1432 visited: visited, includeParents: true, errorLocation: loc); | 1438 visited: visited, includeParents: true, errorLocation: loc); |
| 1433 } | 1439 } |
| 1434 } | 1440 } |
| 1435 | 1441 |
| 1436 /// Check overrides from mixin applications themselves. For example, in: | 1442 /// Check overrides from mixin applications themselves. For example, in: |
| 1437 /// | 1443 /// |
| 1438 /// A extends B with E, F | 1444 /// A extends B with E, F |
| 1439 /// | 1445 /// |
| 1440 /// we check: | 1446 /// we check: |
| 1441 /// | 1447 /// |
| 1442 /// B & E against B (equivalently how E overrides B) | 1448 /// B & E against B (equivalently how E overrides B) |
| 1443 /// B & E & F against B & E (equivalently how F overrides both B and E) | 1449 /// B & E & F against B & E (equivalently how F overrides both B and E) |
| 1444 void _checkMixinApplicationOverrides(ClassDeclaration node) { | 1450 void _checkMixinApplicationOverrides(Declaration node, ClassElement element) { |
| 1445 var type = resolutionMap.elementDeclaredByClassDeclaration(node).type; | 1451 var type = element.type; |
| 1446 var parent = type.superclass; | 1452 var parent = type.superclass; |
| 1447 var mixins = type.mixins; | 1453 var mixins = type.mixins; |
| 1448 | 1454 |
| 1449 // Check overrides from applying mixins | 1455 // Check overrides from applying mixins |
| 1450 for (int i = 0; i < mixins.length; i++) { | 1456 for (int i = 0; i < mixins.length; i++) { |
| 1451 var seen = new Set<String>(); | 1457 var seen = new Set<String>(); |
| 1452 var current = mixins[i]; | 1458 var current = mixins[i]; |
| 1453 var errorLocation = node.withClause.mixinTypes[i]; | 1459 var errorLocation = _withClause(node).mixinTypes[i]; |
| 1454 for (int j = i - 1; j >= 0; j--) { | 1460 for (int j = i - 1; j >= 0; j--) { |
| 1455 _checkIndividualOverridesFromType( | 1461 _checkIndividualOverridesFromType( |
| 1456 current, mixins[j], errorLocation, seen, true); | 1462 current, mixins[j], errorLocation, seen, true); |
| 1457 } | 1463 } |
| 1458 _checkIndividualOverridesFromType( | 1464 _checkIndividualOverridesFromType( |
| 1459 current, parent, errorLocation, seen, true); | 1465 current, parent, errorLocation, seen, true); |
| 1460 } | 1466 } |
| 1461 } | 1467 } |
| 1462 | 1468 |
| 1463 /// Checks that [element] correctly overrides its corresponding member in | 1469 /// Checks that [element] correctly overrides its corresponding member in |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1506 element.enclosingElement.name, | 1512 element.enclosingElement.name, |
| 1507 element.name, | 1513 element.name, |
| 1508 subType, | 1514 subType, |
| 1509 type, | 1515 type, |
| 1510 baseType | 1516 baseType |
| 1511 ]); | 1517 ]); |
| 1512 } | 1518 } |
| 1513 } | 1519 } |
| 1514 if (!rules.isOverrideSubtypeOf(subType, baseType)) { | 1520 if (!rules.isOverrideSubtypeOf(subType, baseType)) { |
| 1515 ErrorCode errorCode; | 1521 ErrorCode errorCode; |
| 1516 if (errorLocation is ExtendsClause) { | 1522 var parent = errorLocation?.parent; |
| 1523 if (errorLocation is ExtendsClause || |
| 1524 parent is ClassTypeAlias && parent.superclass == errorLocation) { |
| 1517 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_BASE; | 1525 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_BASE; |
| 1518 } else if (errorLocation.parent is WithClause) { | 1526 } else if (parent is WithClause) { |
| 1519 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_MIXIN; | 1527 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_MIXIN; |
| 1520 } else { | 1528 } else { |
| 1521 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE; | 1529 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE; |
| 1522 } | 1530 } |
| 1523 | 1531 |
| 1524 _checker._recordMessage(errorLocation, errorCode, [ | 1532 _checker._recordMessage(errorLocation, errorCode, [ |
| 1525 element.enclosingElement.name, | 1533 element.enclosingElement.name, |
| 1526 element.name, | 1534 element.name, |
| 1527 subType, | 1535 subType, |
| 1528 type, | 1536 type, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1552 /// | 1560 /// |
| 1553 /// class Grandparent { | 1561 /// class Grandparent { |
| 1554 /// m(A a) {} | 1562 /// m(A a) {} |
| 1555 /// } | 1563 /// } |
| 1556 /// class Parent extends Grandparent { | 1564 /// class Parent extends Grandparent { |
| 1557 /// m(A a) {} | 1565 /// m(A a) {} |
| 1558 /// } | 1566 /// } |
| 1559 /// class Test extends Parent { | 1567 /// class Test extends Parent { |
| 1560 /// m(B a) {} // invalid override | 1568 /// m(B a) {} // invalid override |
| 1561 /// } | 1569 /// } |
| 1562 void _checkSuperOverrides(ClassDeclaration node) { | 1570 void _checkSuperOverrides(Declaration node, ClassElement element) { |
| 1563 var seen = new Set<String>(); | 1571 var seen = new Set<String>(); |
| 1564 var current = resolutionMap.elementDeclaredByClassDeclaration(node).type; | 1572 var current = element.type; |
| 1565 var visited = new Set<InterfaceType>(); | 1573 var visited = new Set<InterfaceType>(); |
| 1566 do { | 1574 do { |
| 1567 visited.add(current); | 1575 visited.add(current); |
| 1568 current.mixins.reversed.forEach( | 1576 current.mixins.reversed.forEach( |
| 1569 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1577 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1570 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1578 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1571 current = current.superclass; | 1579 current = current.superclass; |
| 1572 } while (!current.isObject && !visited.contains(current)); | 1580 } while (!current.isObject && !visited.contains(current)); |
| 1573 } | 1581 } |
| 1582 |
| 1583 /// If node is a [ClassDeclaration] returns its members, otherwise if node is |
| 1584 /// a [ClassTypeAlias] this returns an empty list. |
| 1585 Iterable<ClassMember> _classMembers(Declaration node) { |
| 1586 return node is ClassDeclaration ? node.members : []; |
| 1587 } |
| 1588 |
| 1589 /// If node is a [ClassDeclaration] returns its members, otherwise if node is |
| 1590 /// a [ClassTypeAlias] this returns an empty list. |
| 1591 WithClause _withClause(Declaration node) { |
| 1592 return node is ClassDeclaration |
| 1593 ? node.withClause |
| 1594 : (node as ClassTypeAlias).withClause; |
| 1595 } |
| 1596 |
| 1597 /// If node is a [ClassDeclaration] returns its members, otherwise if node is |
| 1598 /// a [ClassTypeAlias] this returns an empty list. |
| 1599 AstNode _extendsErrorLocation(Declaration node) { |
| 1600 return node is ClassDeclaration |
| 1601 ? node.extendsClause |
| 1602 : (node as ClassTypeAlias).superclass; |
| 1603 } |
| 1574 } | 1604 } |
| OLD | NEW |