| 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 library dev_compiler.src.checker.checker; | 5 library dev_compiler.src.checker.checker; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
| 8 import 'package:analyzer/src/generated/ast.dart'; | 8 import 'package:analyzer/src/generated/ast.dart'; |
| 9 import 'package:analyzer/src/generated/element.dart'; | 9 import 'package:analyzer/src/generated/element.dart'; |
| 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; | 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 /// } | 76 /// } |
| 77 /// class Parent extends Grandparent { | 77 /// class Parent extends Grandparent { |
| 78 /// m(A a) {} | 78 /// m(A a) {} |
| 79 /// } | 79 /// } |
| 80 /// class Test extends Parent { | 80 /// class Test extends Parent { |
| 81 /// m(B a) {} // invalid override | 81 /// m(B a) {} // invalid override |
| 82 /// } | 82 /// } |
| 83 void _checkSuperOverrides(ClassDeclaration node) { | 83 void _checkSuperOverrides(ClassDeclaration node) { |
| 84 var seen = new Set<String>(); | 84 var seen = new Set<String>(); |
| 85 var current = node.element.type; | 85 var current = node.element.type; |
| 86 var visited = new Set<InterfaceType>(); |
| 86 do { | 87 do { |
| 88 visited.add(current); |
| 87 current.mixins.reversed | 89 current.mixins.reversed |
| 88 .forEach((m) => _checkIndividualOverridesFromClass(node, m, seen)); | 90 .forEach((m) => _checkIndividualOverridesFromClass(node, m, seen)); |
| 89 _checkIndividualOverridesFromClass(node, current.superclass, seen); | 91 _checkIndividualOverridesFromClass(node, current.superclass, seen); |
| 90 current = current.superclass; | 92 current = current.superclass; |
| 91 } while (!current.isObject); | 93 } while (!current.isObject && !visited.contains(current)); |
| 92 } | 94 } |
| 93 | 95 |
| 94 /// Checks that implementations correctly override all reachable interfaces. | 96 /// Checks that implementations correctly override all reachable interfaces. |
| 95 /// In particular, we need to check these overrides for the definitions in | 97 /// In particular, we need to check these overrides for the definitions in |
| 96 /// the class itself and each its superclasses. If a superclass is not | 98 /// the class itself and each its superclasses. If a superclass is not |
| 97 /// abstract, then we can skip its transitive interfaces. For example, in: | 99 /// abstract, then we can skip its transitive interfaces. For example, in: |
| 98 /// | 100 /// |
| 99 /// B extends C implements G | 101 /// B extends C implements G |
| 100 /// A extends B with E, F implements H, I | 102 /// A extends B with E, F implements H, I |
| 101 /// | 103 /// |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 /// Checks that [cls] and its super classes (including mixins) correctly | 147 /// Checks that [cls] and its super classes (including mixins) correctly |
| 146 /// overrides each interface in [interfaces]. If [includeParents] is false, | 148 /// overrides each interface in [interfaces]. If [includeParents] is false, |
| 147 /// then mixins are still checked, but the base type and it's transitive | 149 /// then mixins are still checked, but the base type and it's transitive |
| 148 /// supertypes are not. | 150 /// supertypes are not. |
| 149 /// | 151 /// |
| 150 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For | 152 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For |
| 151 /// [ClassDeclaration]s errors are reported on the member that contains the | 153 /// [ClassDeclaration]s errors are reported on the member that contains the |
| 152 /// invalid override, for [InterfaceType]s we use [errorLocation] instead. | 154 /// invalid override, for [InterfaceType]s we use [errorLocation] instead. |
| 153 void _checkInterfacesOverrides( | 155 void _checkInterfacesOverrides( |
| 154 cls, Iterable<InterfaceType> interfaces, Set<String> seen, | 156 cls, Iterable<InterfaceType> interfaces, Set<String> seen, |
| 155 {bool includeParents: true, AstNode errorLocation}) { | 157 {Set<InterfaceType> visited, |
| 158 bool includeParents: true, |
| 159 AstNode errorLocation}) { |
| 156 var node = cls is ClassDeclaration ? cls : null; | 160 var node = cls is ClassDeclaration ? cls : null; |
| 157 var type = cls is InterfaceType ? cls : node.element.type; | 161 var type = cls is InterfaceType ? cls : node.element.type; |
| 158 | 162 |
| 163 if (visited == null) { |
| 164 visited = new Set<InterfaceType>(); |
| 165 } else if (visited.contains(type)) { |
| 166 // Malformed type. |
| 167 return; |
| 168 } else { |
| 169 visited.add(type); |
| 170 } |
| 171 |
| 159 // Check direct overrides on [type] | 172 // Check direct overrides on [type] |
| 160 for (var interfaceType in interfaces) { | 173 for (var interfaceType in interfaces) { |
| 161 if (node != null) { | 174 if (node != null) { |
| 162 _checkIndividualOverridesFromClass(node, interfaceType, seen); | 175 _checkIndividualOverridesFromClass(node, interfaceType, seen); |
| 163 } else { | 176 } else { |
| 164 _checkIndividualOverridesFromType( | 177 _checkIndividualOverridesFromType( |
| 165 type, interfaceType, errorLocation, seen); | 178 type, interfaceType, errorLocation, seen); |
| 166 } | 179 } |
| 167 } | 180 } |
| 168 | 181 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 179 } | 192 } |
| 180 | 193 |
| 181 // Check overrides from its superclasses | 194 // Check overrides from its superclasses |
| 182 if (includeParents) { | 195 if (includeParents) { |
| 183 var parent = type.superclass; | 196 var parent = type.superclass; |
| 184 if (parent.isObject) return; | 197 if (parent.isObject) return; |
| 185 var loc = errorLocation != null ? errorLocation : node.extendsClause; | 198 var loc = errorLocation != null ? errorLocation : node.extendsClause; |
| 186 // No need to copy [seen] here because we made copies above when reporting | 199 // No need to copy [seen] here because we made copies above when reporting |
| 187 // errors on mixins. | 200 // errors on mixins. |
| 188 _checkInterfacesOverrides(parent, interfaces, seen, | 201 _checkInterfacesOverrides(parent, interfaces, seen, |
| 189 includeParents: true, errorLocation: loc); | 202 visited: visited, includeParents: true, errorLocation: loc); |
| 190 } | 203 } |
| 191 } | 204 } |
| 192 | 205 |
| 193 /// Check that individual methods and fields in [subType] correctly override | 206 /// Check that individual methods and fields in [subType] correctly override |
| 194 /// the declarations in [baseType]. | 207 /// the declarations in [baseType]. |
| 195 /// | 208 /// |
| 196 /// The [errorLocation] node indicates where errors are reported, see | 209 /// The [errorLocation] node indicates where errors are reported, see |
| 197 /// [_checkSingleOverride] for more details. | 210 /// [_checkSingleOverride] for more details. |
| 198 /// | 211 /// |
| 199 /// The set [seen] is used to avoid reporting overrides more than once. It | 212 /// The set [seen] is used to avoid reporting overrides more than once. It |
| (...skipping 25 matching lines...) Expand all Loading... |
| 225 if (member is FieldDeclaration) { | 238 if (member is FieldDeclaration) { |
| 226 if (member.isStatic) continue; | 239 if (member.isStatic) continue; |
| 227 for (var variable in member.fields.variables) { | 240 for (var variable in member.fields.variables) { |
| 228 var element = variable.element as PropertyInducingElement; | 241 var element = variable.element as PropertyInducingElement; |
| 229 var name = element.name; | 242 var name = element.name; |
| 230 if (seen.contains(name)) continue; | 243 if (seen.contains(name)) continue; |
| 231 var getter = element.getter; | 244 var getter = element.getter; |
| 232 var setter = element.setter; | 245 var setter = element.setter; |
| 233 bool found = _checkSingleOverride(getter, baseType, variable, member); | 246 bool found = _checkSingleOverride(getter, baseType, variable, member); |
| 234 if (!variable.isFinal && | 247 if (!variable.isFinal && |
| 248 !variable.isConst && |
| 235 _checkSingleOverride(setter, baseType, variable, member)) { | 249 _checkSingleOverride(setter, baseType, variable, member)) { |
| 236 found = true; | 250 found = true; |
| 237 } | 251 } |
| 238 if (found) seen.add(name); | 252 if (found) seen.add(name); |
| 239 } | 253 } |
| 240 } else { | 254 } else { |
| 241 if ((member as MethodDeclaration).isStatic) continue; | 255 if ((member as MethodDeclaration).isStatic) continue; |
| 242 var method = (member as MethodDeclaration).element; | 256 var method = (member as MethodDeclaration).element; |
| 243 if (seen.contains(method.name)) continue; | 257 if (seen.contains(method.name)) continue; |
| 244 if (_checkSingleOverride(method, baseType, member, member)) { | 258 if (_checkSingleOverride(method, baseType, member, member)) { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 | 396 |
| 383 @override | 397 @override |
| 384 void visitForEachStatement(ForEachStatement node) { | 398 void visitForEachStatement(ForEachStatement node) { |
| 385 // Check that the expression is an Iterable. | 399 // Check that the expression is an Iterable. |
| 386 var expr = node.iterable; | 400 var expr = node.iterable; |
| 387 var iterableType = node.awaitKeyword != null | 401 var iterableType = node.awaitKeyword != null |
| 388 ? rules.provider.streamType | 402 ? rules.provider.streamType |
| 389 : rules.provider.iterableType; | 403 : rules.provider.iterableType; |
| 390 var loopVariable = node.identifier != null | 404 var loopVariable = node.identifier != null |
| 391 ? node.identifier | 405 ? node.identifier |
| 392 : node.loopVariable.identifier; | 406 : node.loopVariable?.identifier; |
| 393 var iteratorType = loopVariable.staticType; | 407 if (loopVariable != null) { |
| 394 var checkedType = iterableType.substitute4([iteratorType]); | 408 var iteratorType = loopVariable.staticType; |
| 395 checkAssignment(expr, checkedType); | 409 var checkedType = iterableType.substitute4([iteratorType]); |
| 410 checkAssignment(expr, checkedType); |
| 411 } |
| 396 node.visitChildren(this); | 412 node.visitChildren(this); |
| 397 } | 413 } |
| 398 | 414 |
| 399 @override | 415 @override |
| 400 void visitForStatement(ForStatement node) { | 416 void visitForStatement(ForStatement node) { |
| 401 if (node.condition != null) { | 417 if (node.condition != null) { |
| 402 checkBoolean(node.condition); | 418 checkBoolean(node.condition); |
| 403 } | 419 } |
| 404 node.visitChildren(this); | 420 node.visitChildren(this); |
| 405 } | 421 } |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 if (info is CoercionInfo) { | 934 if (info is CoercionInfo) { |
| 919 // TODO(jmesserly): if we're run again on the same AST, we'll produce the | 935 // TODO(jmesserly): if we're run again on the same AST, we'll produce the |
| 920 // same annotations. This should be harmless. This might go away once | 936 // same annotations. This should be harmless. This might go away once |
| 921 // CodeChecker is integrated better with analyzer, as it will know that | 937 // CodeChecker is integrated better with analyzer, as it will know that |
| 922 // checking has already been performed. | 938 // checking has already been performed. |
| 923 // assert(CoercionInfo.get(info.node) == null); | 939 // assert(CoercionInfo.get(info.node) == null); |
| 924 CoercionInfo.set(info.node, info); | 940 CoercionInfo.set(info.node, info); |
| 925 } | 941 } |
| 926 } | 942 } |
| 927 } | 943 } |
| OLD | NEW |