| 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 analyzer.src.task.strong_mode; | 5 library analyzer.src.task.strong_mode; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/element/element.dart'; |
| 10 import 'package:analyzer/dart/element/type.dart'; |
| 11 import 'package:analyzer/src/dart/element/element.dart'; |
| 12 import 'package:analyzer/src/dart/element/type.dart'; |
| 9 import 'package:analyzer/src/generated/ast.dart'; | 13 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; | |
| 11 import 'package:analyzer/src/generated/resolver.dart' | 14 import 'package:analyzer/src/generated/resolver.dart' |
| 12 show TypeProvider, InheritanceManager; | 15 show TypeProvider, InheritanceManager; |
| 13 import 'package:analyzer/src/generated/type_system.dart'; | 16 import 'package:analyzer/src/generated/type_system.dart'; |
| 14 import 'package:analyzer/src/generated/utilities_dart.dart'; | 17 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 15 | 18 |
| 16 /** | 19 /** |
| 17 * Set the type of the sole parameter of the given [element] to the given [type]
. | 20 * Set the type of the sole parameter of the given [element] to the given [type]
. |
| 18 */ | 21 */ |
| 19 void setParameterType(PropertyAccessorElement element, DartType type) { | 22 void setParameterType(PropertyAccessorElement element, DartType type) { |
| 20 if (element is PropertyAccessorElementImpl) { | 23 if (element is PropertyAccessorElementImpl) { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 try { | 133 try { |
| 131 _inferClass(classElement); | 134 _inferClass(classElement); |
| 132 } on _CycleException { | 135 } on _CycleException { |
| 133 // This is a short circuit return to prevent types that inherit from | 136 // This is a short circuit return to prevent types that inherit from |
| 134 // types containing a circular reference from being inferred. | 137 // types containing a circular reference from being inferred. |
| 135 } | 138 } |
| 136 }); | 139 }); |
| 137 } | 140 } |
| 138 | 141 |
| 139 /** | 142 /** |
| 143 * Return `true` if the list of [elements] contains only methods. |
| 144 */ |
| 145 bool _allSameElementKind( |
| 146 ExecutableElement element, List<ExecutableElement> elements) { |
| 147 return elements.every((e) => e.kind == element.kind); |
| 148 } |
| 149 |
| 150 /** |
| 140 * Compute the best type for the [parameter] at the given [index] that must be | 151 * Compute the best type for the [parameter] at the given [index] that must be |
| 141 * compatible with the types of the corresponding parameters of the given | 152 * compatible with the types of the corresponding parameters of the given |
| 142 * [overriddenMethods]. | 153 * [overriddenMethods]. |
| 143 * | 154 * |
| 144 * At the moment, this method will only return a type other than 'dynamic' if | 155 * At the moment, this method will only return a type other than 'dynamic' if |
| 145 * the types of all of the parameters are the same. In the future we might | 156 * the types of all of the parameters are the same. In the future we might |
| 146 * want to be smarter about it, such as by returning the least upper bound of | 157 * want to be smarter about it, such as by returning the least upper bound of |
| 147 * the parameter types. | 158 * the parameter types. |
| 148 */ | 159 */ |
| 149 DartType _computeParameterType(ParameterElement parameter, int index, | 160 DartType _computeParameterType(ParameterElement parameter, int index, |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 List<ParameterElement> methodParameters = method.parameters; | 217 List<ParameterElement> methodParameters = method.parameters; |
| 207 ParameterElement matchingParameter = null; | 218 ParameterElement matchingParameter = null; |
| 208 if (parameter.parameterKind == ParameterKind.NAMED) { | 219 if (parameter.parameterKind == ParameterKind.NAMED) { |
| 209 // | 220 // |
| 210 // If we're looking for a named parameter, only a named parameter with | 221 // If we're looking for a named parameter, only a named parameter with |
| 211 // the same name will be matched. | 222 // the same name will be matched. |
| 212 // | 223 // |
| 213 matchingParameter = methodParameters.lastWhere( | 224 matchingParameter = methodParameters.lastWhere( |
| 214 (ParameterElement methodParameter) => | 225 (ParameterElement methodParameter) => |
| 215 methodParameter.parameterKind == ParameterKind.NAMED && | 226 methodParameter.parameterKind == ParameterKind.NAMED && |
| 216 methodParameter.name == parameter.name, | 227 methodParameter.name == parameter.name, |
| 217 orElse: () => null); | 228 orElse: () => null); |
| 218 } else { | 229 } else { |
| 219 // | 230 // |
| 220 // If we're looking for a positional parameter we ignore the difference | 231 // If we're looking for a positional parameter we ignore the difference |
| 221 // between required and optional parameters. | 232 // between required and optional parameters. |
| 222 // | 233 // |
| 223 if (index < methodParameters.length) { | 234 if (index < methodParameters.length) { |
| 224 matchingParameter = methodParameters[index]; | 235 matchingParameter = methodParameters[index]; |
| 225 if (matchingParameter.parameterKind == ParameterKind.NAMED) { | 236 if (matchingParameter.parameterKind == ParameterKind.NAMED) { |
| 226 matchingParameter = null; | 237 matchingParameter = null; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 // field types are inferred. | 282 // field types are inferred. |
| 272 // | 283 // |
| 273 classElement.constructors.forEach(_inferConstructorFieldFormals); | 284 classElement.constructors.forEach(_inferConstructorFieldFormals); |
| 274 classElement.hasBeenInferred = true; | 285 classElement.hasBeenInferred = true; |
| 275 } finally { | 286 } finally { |
| 276 elementsBeingInferred.remove(classElement); | 287 elementsBeingInferred.remove(classElement); |
| 277 } | 288 } |
| 278 } | 289 } |
| 279 } | 290 } |
| 280 | 291 |
| 281 /** | 292 void _inferConstructorFieldFormals(ConstructorElement element) { |
| 282 * If the given [fieldElement] represents a non-synthetic instance field for | 293 for (ParameterElement p in element.parameters) { |
| 283 * which no type was provided, infer the type of the field. | 294 if (p is FieldFormalParameterElement) { |
| 284 */ | 295 _inferFieldFormalParameter(p); |
| 285 void _inferField(FieldElement fieldElement) { | |
| 286 if (!fieldElement.isSynthetic && | |
| 287 !fieldElement.isStatic && | |
| 288 fieldElement.hasImplicitType) { | |
| 289 // | |
| 290 // First look for overridden getters with the same name as the field. | |
| 291 // | |
| 292 List<ExecutableElement> overriddenGetters = inheritanceManager | |
| 293 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name); | |
| 294 DartType newType = null; | |
| 295 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { | |
| 296 newType = _computeReturnType(overriddenGetters); | |
| 297 List<ExecutableElement> overriddenSetters = inheritanceManager | |
| 298 .lookupOverrides( | |
| 299 fieldElement.enclosingElement, fieldElement.name + '='); | |
| 300 if (!_isCompatible(newType, overriddenSetters)) { | |
| 301 newType = null; | |
| 302 } | |
| 303 } | |
| 304 // | |
| 305 // If there is no overridden getter or if the overridden getter's type is | |
| 306 // dynamic, then we can infer the type from the initialization expression | |
| 307 // without breaking subtype rules. We could potentially infer a consistent | |
| 308 // return type even if the overridden getter's type was not dynamic, but | |
| 309 // choose not to for simplicity. The field is required to be final to | |
| 310 // prevent choosing a type that is inconsistent with assignments we cannot | |
| 311 // analyze. | |
| 312 // | |
| 313 if (newType == null || newType.isDynamic) { | |
| 314 if (fieldElement.initializer != null && | |
| 315 (fieldElement.isFinal || overriddenGetters.isEmpty)) { | |
| 316 newType = fieldElement.initializer.returnType; | |
| 317 } | |
| 318 } | |
| 319 if (newType == null || newType.isBottom) { | |
| 320 newType = typeProvider.dynamicType; | |
| 321 } | |
| 322 (fieldElement as FieldElementImpl).type = newType; | |
| 323 setReturnType(fieldElement.getter, newType); | |
| 324 if (!fieldElement.isFinal && !fieldElement.isConst) { | |
| 325 setParameterType(fieldElement.setter, newType); | |
| 326 } | 296 } |
| 327 } | 297 } |
| 328 } | 298 } |
| 329 | 299 |
| 330 /** | 300 /** |
| 331 * If the given [element] represents a non-synthetic instance method, | 301 * If the given [element] represents a non-synthetic instance method, |
| 332 * getter or setter, infer the return type and any parameter type(s) where | 302 * getter or setter, infer the return type and any parameter type(s) where |
| 333 * they were not provided. | 303 * they were not provided. |
| 334 */ | 304 */ |
| 335 void _inferExecutable(ExecutableElement element) { | 305 void _inferExecutable(ExecutableElement element) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 } | 340 } |
| 371 parameter.type = _computeParameterType(parameter, i, overriddenMethods); | 341 parameter.type = _computeParameterType(parameter, i, overriddenMethods); |
| 372 if (element is PropertyAccessorElement) { | 342 if (element is PropertyAccessorElement) { |
| 373 _updateSyntheticVariableType(element); | 343 _updateSyntheticVariableType(element); |
| 374 } | 344 } |
| 375 } | 345 } |
| 376 } | 346 } |
| 377 } | 347 } |
| 378 | 348 |
| 379 /** | 349 /** |
| 380 * If the given [element] is a non-synthetic getter or setter, update its | 350 * If the given [fieldElement] represents a non-synthetic instance field for |
| 381 * synthetic variable's type to match the getter's return type, or if no | 351 * which no type was provided, infer the type of the field. |
| 382 * corresponding getter exists, use the setter's parameter type. | |
| 383 * | |
| 384 * In general, the type of the synthetic variable should not be used, because | |
| 385 * getters and setters are independent methods. But this logic matches what | |
| 386 * `TypeResolverVisitor.visitMethodDeclaration` would fill in there. | |
| 387 */ | 352 */ |
| 388 void _updateSyntheticVariableType(PropertyAccessorElement element) { | 353 void _inferField(FieldElement fieldElement) { |
| 389 assert(!element.isSynthetic); | 354 if (!fieldElement.isSynthetic && |
| 390 PropertyAccessorElement getter = element; | 355 !fieldElement.isStatic && |
| 391 if (element.isSetter) { | 356 fieldElement.hasImplicitType) { |
| 392 // See if we can find any getter. | 357 // |
| 393 getter = element.correspondingGetter; | 358 // First look for overridden getters with the same name as the field. |
| 394 } | 359 // |
| 395 DartType newType; | 360 List<ExecutableElement> overriddenGetters = inheritanceManager |
| 396 if (getter != null) { | 361 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name); |
| 397 newType = getter.returnType; | 362 DartType newType = null; |
| 398 } else if (element.isSetter && element.parameters.isNotEmpty) { | 363 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { |
| 399 newType = element.parameters[0].type; | 364 newType = _computeReturnType(overriddenGetters); |
| 400 } | 365 List<ExecutableElement> overriddenSetters = |
| 401 if (newType != null) { | 366 inheritanceManager.lookupOverrides( |
| 402 (element.variable as VariableElementImpl).type = newType; | 367 fieldElement.enclosingElement, fieldElement.name + '='); |
| 368 if (!_isCompatible(newType, overriddenSetters)) { |
| 369 newType = null; |
| 370 } |
| 371 } |
| 372 // |
| 373 // If there is no overridden getter or if the overridden getter's type is |
| 374 // dynamic, then we can infer the type from the initialization expression |
| 375 // without breaking subtype rules. We could potentially infer a consistent |
| 376 // return type even if the overridden getter's type was not dynamic, but |
| 377 // choose not to for simplicity. The field is required to be final to |
| 378 // prevent choosing a type that is inconsistent with assignments we cannot |
| 379 // analyze. |
| 380 // |
| 381 if (newType == null || newType.isDynamic) { |
| 382 if (fieldElement.initializer != null && |
| 383 (fieldElement.isFinal || overriddenGetters.isEmpty)) { |
| 384 newType = fieldElement.initializer.returnType; |
| 385 } |
| 386 } |
| 387 if (newType == null || newType.isBottom) { |
| 388 newType = typeProvider.dynamicType; |
| 389 } |
| 390 (fieldElement as FieldElementImpl).type = newType; |
| 391 setReturnType(fieldElement.getter, newType); |
| 392 if (!fieldElement.isFinal && !fieldElement.isConst) { |
| 393 setParameterType(fieldElement.setter, newType); |
| 394 } |
| 403 } | 395 } |
| 404 } | 396 } |
| 405 | 397 |
| 398 void _inferFieldFormalParameter(FieldFormalParameterElement element) { |
| 399 FieldElement field = element.field; |
| 400 if (field != null && element.hasImplicitType) { |
| 401 (element as FieldFormalParameterElementImpl).type = field.type; |
| 402 } |
| 403 } |
| 404 |
| 406 /** | 405 /** |
| 407 * Infer type information for all of the instance members in the given | 406 * Infer type information for all of the instance members in the given |
| 408 * interface [type]. | 407 * interface [type]. |
| 409 */ | 408 */ |
| 410 void _inferType(InterfaceType type) { | 409 void _inferType(InterfaceType type) { |
| 411 if (type != null) { | 410 if (type != null) { |
| 412 ClassElement element = type.element; | 411 ClassElement element = type.element; |
| 413 if (element != null) { | 412 if (element != null) { |
| 414 _inferClass(element); | 413 _inferClass(element); |
| 415 } | 414 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 436 bool _onlyGetters(List<ExecutableElement> elements) { | 435 bool _onlyGetters(List<ExecutableElement> elements) { |
| 437 for (ExecutableElement element in elements) { | 436 for (ExecutableElement element in elements) { |
| 438 if (!(element is PropertyAccessorElement && element.isGetter)) { | 437 if (!(element is PropertyAccessorElement && element.isGetter)) { |
| 439 return false; | 438 return false; |
| 440 } | 439 } |
| 441 } | 440 } |
| 442 return true; | 441 return true; |
| 443 } | 442 } |
| 444 | 443 |
| 445 /** | 444 /** |
| 446 * Return `true` if the list of [elements] contains only methods. | 445 * If the given [element] is a non-synthetic getter or setter, update its |
| 446 * synthetic variable's type to match the getter's return type, or if no |
| 447 * corresponding getter exists, use the setter's parameter type. |
| 448 * |
| 449 * In general, the type of the synthetic variable should not be used, because |
| 450 * getters and setters are independent methods. But this logic matches what |
| 451 * `TypeResolverVisitor.visitMethodDeclaration` would fill in there. |
| 447 */ | 452 */ |
| 448 bool _allSameElementKind( | 453 void _updateSyntheticVariableType(PropertyAccessorElement element) { |
| 449 ExecutableElement element, List<ExecutableElement> elements) { | 454 assert(!element.isSynthetic); |
| 450 return elements.every((e) => e.kind == element.kind); | 455 PropertyAccessorElement getter = element; |
| 451 } | 456 if (element.isSetter) { |
| 452 | 457 // See if we can find any getter. |
| 453 void _inferConstructorFieldFormals(ConstructorElement element) { | 458 getter = element.correspondingGetter; |
| 454 for (ParameterElement p in element.parameters) { | |
| 455 if (p is FieldFormalParameterElement) { | |
| 456 _inferFieldFormalParameter(p); | |
| 457 } | |
| 458 } | 459 } |
| 459 } | 460 DartType newType; |
| 460 | 461 if (getter != null) { |
| 461 void _inferFieldFormalParameter(FieldFormalParameterElement element) { | 462 newType = getter.returnType; |
| 462 FieldElement field = element.field; | 463 } else if (element.isSetter && element.parameters.isNotEmpty) { |
| 463 if (field != null && element.hasImplicitType) { | 464 newType = element.parameters[0].type; |
| 464 (element as FieldFormalParameterElementImpl).type = field.type; | 465 } |
| 466 if (newType != null) { |
| 467 (element.variable as VariableElementImpl).type = newType; |
| 465 } | 468 } |
| 466 } | 469 } |
| 467 } | 470 } |
| 468 | 471 |
| 469 /** | 472 /** |
| 470 * A visitor that will gather all of the variables referenced within a given | 473 * A visitor that will gather all of the variables referenced within a given |
| 471 * AST structure. The collection can be restricted to contain only those | 474 * AST structure. The collection can be restricted to contain only those |
| 472 * variables that pass a specified filter. | 475 * variables that pass a specified filter. |
| 473 */ | 476 */ |
| 474 class VariableGatherer extends RecursiveAstVisitor { | 477 class VariableGatherer extends RecursiveAstVisitor { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 500 results.add(element); | 503 results.add(element); |
| 501 } | 504 } |
| 502 } | 505 } |
| 503 } | 506 } |
| 504 } | 507 } |
| 505 | 508 |
| 506 /** | 509 /** |
| 507 * A class of exception that is not used anywhere else. | 510 * A class of exception that is not used anywhere else. |
| 508 */ | 511 */ |
| 509 class _CycleException implements Exception {} | 512 class _CycleException implements Exception {} |
| OLD | NEW |