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 |