Chromium Code Reviews| 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/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/visitor.dart'; | 10 import 'package:analyzer/dart/ast/visitor.dart'; |
| 11 import 'package:analyzer/dart/element/element.dart'; | 11 import 'package:analyzer/dart/element/element.dart'; |
| 12 import 'package:analyzer/dart/element/type.dart'; | 12 import 'package:analyzer/dart/element/type.dart'; |
| 13 import 'package:analyzer/src/dart/element/element.dart'; | 13 import 'package:analyzer/src/dart/element/element.dart'; |
| 14 import 'package:analyzer/src/generated/resolver.dart' | 14 import 'package:analyzer/src/generated/resolver.dart' |
| 15 show TypeProvider, InheritanceManager; | 15 show TypeProvider, InheritanceManager; |
| 16 import 'package:analyzer/src/generated/type_system.dart'; | 16 import 'package:analyzer/src/generated/type_system.dart'; |
| 17 import 'package:analyzer/src/generated/utilities_dart.dart'; | 17 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 18 import 'package:analyzer/src/dart/element/type.dart'; | |
| 18 | 19 |
| 19 /** | 20 /** |
| 20 * Sets the type of the field. This is stored in the field itself, and the | 21 * Sets the type of the field. This is stored in the field itself, and the |
| 21 * synthetic getter/setter types. | 22 * synthetic getter/setter types. |
| 22 */ | 23 */ |
| 23 void setFieldType(VariableElement field, DartType newType) { | 24 void setFieldType(VariableElement field, DartType newType) { |
| 24 (field as VariableElementImpl).type = newType; | 25 (field as VariableElementImpl).type = newType; |
| 25 if (field.initializer != null) { | 26 if (field.initializer != null) { |
| 26 (field.initializer as ExecutableElementImpl).returnType = newType; | 27 (field.initializer as ExecutableElementImpl).returnType = newType; |
| 27 } | 28 } |
| 28 if (field is PropertyInducingElementImpl) { | 29 if (field is PropertyInducingElementImpl) { |
| 29 (field.getter as ExecutableElementImpl).returnType = newType; | 30 (field.getter as ExecutableElementImpl).returnType = newType; |
| 30 if (!field.isFinal && !field.isConst) { | 31 if (!field.isFinal && !field.isConst) { |
| 31 (field.setter.parameters[0] as ParameterElementImpl).type = | 32 (field.setter.parameters[0] as ParameterElementImpl).type = newType; |
| 32 newType; | |
| 33 } | 33 } |
| 34 } | 34 } |
| 35 } | 35 } |
| 36 | 36 |
| 37 /** | 37 /** |
| 38 * Return the element for the single parameter of the given [setter], or `null` | 38 * Return the element for the single parameter of the given [setter], or `null` |
| 39 * if the executable element is not a setter or does not have a single | 39 * if the executable element is not a setter or does not have a single |
| 40 * parameter. | 40 * parameter. |
| 41 */ | 41 */ |
| 42 ParameterElement _getParameter(ExecutableElement setter) { | 42 ParameterElement _getParameter(ExecutableElement setter) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 115 * Compute the best type for the [parameter] at the given [index] that must be | 115 * Compute the best type for the [parameter] at the given [index] that must be |
| 116 * compatible with the types of the corresponding parameters of the given | 116 * compatible with the types of the corresponding parameters of the given |
| 117 * [overriddenMethods]. | 117 * [overriddenMethods]. |
| 118 * | 118 * |
| 119 * At the moment, this method will only return a type other than 'dynamic' if | 119 * At the moment, this method will only return a type other than 'dynamic' if |
| 120 * the types of all of the parameters are the same. In the future we might | 120 * the types of all of the parameters are the same. In the future we might |
| 121 * want to be smarter about it, such as by returning the least upper bound of | 121 * want to be smarter about it, such as by returning the least upper bound of |
| 122 * the parameter types. | 122 * the parameter types. |
| 123 */ | 123 */ |
| 124 DartType _computeParameterType(ParameterElement parameter, int index, | 124 DartType _computeParameterType(ParameterElement parameter, int index, |
| 125 List<ExecutableElement> overriddenMethods) { | 125 List<FunctionType> overriddenTypes) { |
| 126 DartType parameterType = null; | 126 DartType parameterType = null; |
| 127 int length = overriddenMethods.length; | 127 int length = overriddenTypes.length; |
| 128 for (int i = 0; i < length; i++) { | 128 for (int i = 0; i < length; i++) { |
| 129 DartType type = _getTypeOfCorrespondingParameter( | 129 DartType type = _getTypeOfCorrespondingParameter( |
| 130 parameter, index, overriddenMethods[i]); | 130 parameter, index, overriddenTypes[i].parameters); |
| 131 if (parameterType == null) { | 131 if (parameterType == null) { |
| 132 parameterType = type; | 132 parameterType = type; |
| 133 } else if (parameterType != type) { | 133 } else if (parameterType != type) { |
| 134 return typeProvider.dynamicType; | 134 return typeProvider.dynamicType; |
| 135 } | 135 } |
| 136 } | 136 } |
| 137 return parameterType == null ? typeProvider.dynamicType : parameterType; | 137 return parameterType ?? typeProvider.dynamicType; |
| 138 } | 138 } |
| 139 | 139 |
| 140 /** | 140 /** |
| 141 * Compute the best return type for a method that must be compatible with the | 141 * Compute the best return type for a method that must be compatible with the |
| 142 * return types of each of the given [overriddenMethods]. | 142 * return types of each of the given [overriddenTypes]. |
|
vsm
2016/02/03 23:16:15
s/overriddenTypes/overriddenReturnTypes/ to match
Jennifer Messerly
2016/02/04 18:18:51
Done.
| |
| 143 * | 143 * |
| 144 * At the moment, this method will only return a type other than 'dynamic' if | 144 * At the moment, this method will only return a type other than 'dynamic' if |
| 145 * the return types of all of the methods are the same. In the future we might | 145 * the return types of all of the methods are the same. In the future we might |
| 146 * want to be smarter about it. | 146 * want to be smarter about it. |
| 147 */ | 147 */ |
| 148 DartType _computeReturnType(List<ExecutableElement> overriddenMethods) { | 148 DartType _computeReturnType(Iterable<DartType> overriddenReturnTypes) { |
| 149 DartType returnType = null; | 149 DartType returnType = null; |
| 150 int length = overriddenMethods.length; | 150 for (DartType type in overriddenReturnTypes) { |
| 151 for (int i = 0; i < length; i++) { | 151 if (type == null) { |
| 152 DartType type = _getReturnType(overriddenMethods[i]); | 152 type = typeProvider.dynamicType; |
| 153 } | |
| 153 if (returnType == null) { | 154 if (returnType == null) { |
| 154 returnType = type; | 155 returnType = type; |
| 155 } else if (returnType != type) { | 156 } else if (returnType != type) { |
| 156 return typeProvider.dynamicType; | 157 return typeProvider.dynamicType; |
| 157 } | 158 } |
| 158 } | 159 } |
| 159 return returnType == null ? typeProvider.dynamicType : returnType; | 160 return returnType ?? typeProvider.dynamicType; |
| 160 } | |
| 161 | |
| 162 DartType _getReturnType(ExecutableElement element) { | |
| 163 DartType returnType = element.returnType; | |
| 164 if (returnType == null) { | |
| 165 return typeProvider.dynamicType; | |
| 166 } | |
| 167 return returnType; | |
| 168 } | 161 } |
| 169 | 162 |
| 170 /** | 163 /** |
| 171 * Given a [method], return the type of the parameter in the method that | 164 * Given a [method], return the type of the parameter in the method that |
| 172 * corresponds to the given [parameter]. If the parameter is positional, then | 165 * corresponds to the given [parameter]. If the parameter is positional, then |
| 173 * it appears at the given [index] in its enclosing element's list of | 166 * it appears at the given [index] in its enclosing element's list of |
| 174 * parameters. | 167 * parameters. |
| 175 */ | 168 */ |
| 176 DartType _getTypeOfCorrespondingParameter( | 169 DartType _getTypeOfCorrespondingParameter(ParameterElement parameter, |
| 177 ParameterElement parameter, int index, ExecutableElement method) { | 170 int index, List<ParameterElement> methodParameters) { |
| 178 // | 171 // |
| 179 // Find the corresponding parameter. | 172 // Find the corresponding parameter. |
| 180 // | 173 // |
| 181 List<ParameterElement> methodParameters = method.parameters; | |
| 182 ParameterElement matchingParameter = null; | 174 ParameterElement matchingParameter = null; |
| 183 if (parameter.parameterKind == ParameterKind.NAMED) { | 175 if (parameter.parameterKind == ParameterKind.NAMED) { |
| 184 // | 176 // |
| 185 // If we're looking for a named parameter, only a named parameter with | 177 // If we're looking for a named parameter, only a named parameter with |
| 186 // the same name will be matched. | 178 // the same name will be matched. |
| 187 // | 179 // |
| 188 matchingParameter = methodParameters.lastWhere( | 180 matchingParameter = methodParameters.lastWhere( |
| 189 (ParameterElement methodParameter) => | 181 (ParameterElement methodParameter) => |
| 190 methodParameter.parameterKind == ParameterKind.NAMED && | 182 methodParameter.parameterKind == ParameterKind.NAMED && |
| 191 methodParameter.name == parameter.name, | 183 methodParameter.name == parameter.name, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 263 | 255 |
| 264 /** | 256 /** |
| 265 * If the given [element] represents a non-synthetic instance method, | 257 * If the given [element] represents a non-synthetic instance method, |
| 266 * getter or setter, infer the return type and any parameter type(s) where | 258 * getter or setter, infer the return type and any parameter type(s) where |
| 267 * they were not provided. | 259 * they were not provided. |
| 268 */ | 260 */ |
| 269 void _inferExecutable(ExecutableElement element) { | 261 void _inferExecutable(ExecutableElement element) { |
| 270 if (element.isSynthetic || element.isStatic) { | 262 if (element.isSynthetic || element.isStatic) { |
| 271 return; | 263 return; |
| 272 } | 264 } |
| 273 List<ExecutableElement> overriddenMethods = null; | 265 List<ExecutableElement> overriddenMethods = inheritanceManager |
| 266 .lookupOverrides(element.enclosingElement, element.name); | |
| 267 if (overriddenMethods.isEmpty || | |
| 268 !_allSameElementKind(element, overriddenMethods)) { | |
| 269 return; | |
| 270 } | |
| 271 | |
| 272 // | |
| 273 // Overridden methods must have the same number of generic type parameters | |
| 274 // as this method, or none. | |
| 275 // | |
| 276 // If we do have generic type parameters on the element we're inferring, | |
| 277 // we must express its parameter and return types in terms of its own | |
| 278 // parameters. For example, given `m<T>(t)` overriding `m<S>(S s)` we | |
| 279 // should infer this as `m<T>(T t)`. | |
| 280 // | |
| 281 List<DartType> typeFormals = | |
| 282 TypeParameterTypeImpl.getTypes(element.type.typeFormals); | |
| 283 | |
| 284 List<FunctionType> overriddenTypes = new List<FunctionType>(); | |
| 285 for (ExecutableElement overriddenMethod in overriddenMethods) { | |
| 286 FunctionType overriddenType = overriddenMethod.type; | |
| 287 if (overriddenType.typeFormals.isNotEmpty && | |
| 288 overriddenType.typeFormals.length != typeFormals.length) { | |
| 289 return; | |
| 290 } | |
| 291 overriddenTypes.add(overriddenType.instantiate(typeFormals)); | |
| 292 } | |
| 293 | |
| 274 // | 294 // |
| 275 // Infer the return type. | 295 // Infer the return type. |
| 276 // | 296 // |
| 277 if (element.hasImplicitReturnType) { | 297 if (element.hasImplicitReturnType) { |
| 278 overriddenMethods = inheritanceManager.lookupOverrides( | |
| 279 element.enclosingElement, element.name); | |
| 280 if (overriddenMethods.isEmpty || | |
| 281 !_allSameElementKind(element, overriddenMethods)) { | |
| 282 return; | |
| 283 } | |
| 284 (element as ExecutableElementImpl).returnType = | 298 (element as ExecutableElementImpl).returnType = |
| 285 _computeReturnType(overriddenMethods); | 299 _computeReturnType(overriddenTypes.map((t) => t.returnType)); |
| 286 if (element is PropertyAccessorElement) { | 300 if (element is PropertyAccessorElement) { |
| 287 _updateSyntheticVariableType(element); | 301 _updateSyntheticVariableType(element); |
| 288 } | 302 } |
| 289 } | 303 } |
| 290 // | 304 // |
| 291 // Infer the parameter types. | 305 // Infer the parameter types. |
| 292 // | 306 // |
| 293 List<ParameterElement> parameters = element.parameters; | 307 List<ParameterElement> parameters = element.parameters; |
| 294 int length = parameters.length; | 308 int length = parameters.length; |
| 295 for (int i = 0; i < length; ++i) { | 309 for (int i = 0; i < length; ++i) { |
| 296 ParameterElement parameter = parameters[i]; | 310 ParameterElement parameter = parameters[i]; |
| 297 if (parameter is ParameterElementImpl && parameter.hasImplicitType) { | 311 if (parameter is ParameterElementImpl && parameter.hasImplicitType) { |
| 298 if (overriddenMethods == null) { | 312 parameter.type = _computeParameterType(parameter, i, overriddenTypes); |
| 299 overriddenMethods = inheritanceManager.lookupOverrides( | |
| 300 element.enclosingElement, element.name); | |
| 301 } | |
| 302 if (overriddenMethods.isEmpty || | |
| 303 !_allSameElementKind(element, overriddenMethods)) { | |
| 304 return; | |
| 305 } | |
| 306 parameter.type = _computeParameterType(parameter, i, overriddenMethods); | |
| 307 if (element is PropertyAccessorElement) { | 313 if (element is PropertyAccessorElement) { |
| 308 _updateSyntheticVariableType(element); | 314 _updateSyntheticVariableType(element); |
| 309 } | 315 } |
| 310 } | 316 } |
| 311 } | 317 } |
| 312 } | 318 } |
| 313 | 319 |
| 314 /** | 320 /** |
| 315 * If the given [fieldElement] represents a non-synthetic instance field for | 321 * If the given [fieldElement] represents a non-synthetic instance field for |
| 316 * which no type was provided, infer the type of the field. | 322 * which no type was provided, infer the type of the field. |
| 317 */ | 323 */ |
| 318 void _inferField(FieldElement fieldElement) { | 324 void _inferField(FieldElement fieldElement) { |
| 319 if (!fieldElement.isSynthetic && | 325 if (!fieldElement.isSynthetic && |
| 320 !fieldElement.isStatic && | 326 !fieldElement.isStatic && |
| 321 fieldElement.hasImplicitType) { | 327 fieldElement.hasImplicitType) { |
| 322 // | 328 // |
| 323 // First look for overridden getters with the same name as the field. | 329 // First look for overridden getters with the same name as the field. |
| 324 // | 330 // |
| 325 List<ExecutableElement> overriddenGetters = inheritanceManager | 331 List<ExecutableElement> overriddenGetters = inheritanceManager |
| 326 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name); | 332 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name); |
| 327 DartType newType = null; | 333 DartType newType = null; |
| 328 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { | 334 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { |
| 329 newType = _computeReturnType(overriddenGetters); | 335 newType = |
| 336 _computeReturnType(overriddenGetters.map((e) => e.returnType)); | |
| 330 List<ExecutableElement> overriddenSetters = | 337 List<ExecutableElement> overriddenSetters = |
| 331 inheritanceManager.lookupOverrides( | 338 inheritanceManager.lookupOverrides( |
| 332 fieldElement.enclosingElement, fieldElement.name + '='); | 339 fieldElement.enclosingElement, fieldElement.name + '='); |
| 333 if (!_isCompatible(newType, overriddenSetters)) { | 340 if (!_isCompatible(newType, overriddenSetters)) { |
| 334 newType = null; | 341 newType = null; |
| 335 } | 342 } |
| 336 } | 343 } |
| 337 // | 344 // |
| 338 // If there is no overridden getter or if the overridden getter's type is | 345 // If there is no overridden getter or if the overridden getter's type is |
| 339 // dynamic, then we can infer the type from the initialization expression | 346 // dynamic, then we can infer the type from the initialization expression |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 results.add(element); | 471 results.add(element); |
| 465 } | 472 } |
| 466 } | 473 } |
| 467 } | 474 } |
| 468 } | 475 } |
| 469 | 476 |
| 470 /** | 477 /** |
| 471 * A class of exception that is not used anywhere else. | 478 * A class of exception that is not used anywhere else. |
| 472 */ | 479 */ |
| 473 class _CycleException implements Exception {} | 480 class _CycleException implements Exception {} |
| OLD | NEW |