Index: pkg/analyzer/lib/src/task/strong_mode.dart |
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart |
index 7958f7a4655fdcf4c372f810fb4ff164ef9d4906..fda0467196890f37256e54695ff78c5b10af7379 100644 |
--- a/pkg/analyzer/lib/src/task/strong_mode.dart |
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart |
@@ -9,6 +9,7 @@ import 'dart:collection'; |
import 'package:analyzer/src/generated/ast.dart'; |
import 'package:analyzer/src/generated/element.dart'; |
import 'package:analyzer/src/generated/resolver.dart'; |
+import 'package:analyzer/src/generated/utilities_dart.dart'; |
/** |
* An object used to find static variables whose types should be inferred and |
@@ -164,6 +165,32 @@ class InstanceMemberInferrer { |
} |
/** |
+ * Compute the best type for the [parameter] at the given [index] that must be |
+ * compatible with the types of the corresponding parameters of the given |
+ * [overriddenMethods]. |
+ * |
+ * At the moment, this method will only return a type other than 'dynamic' if |
+ * the types of all of the parameters are the same. In the future we might |
+ * want to be smarter about it, such as by returning the least upper bound of |
+ * the parameter types. |
+ */ |
+ DartType _computeParameterType(ParameterElement parameter, int index, |
+ List<ExecutableElement> overriddenMethods) { |
+ DartType parameterType = null; |
+ int length = overriddenMethods.length; |
+ for (int i = 0; i < length; i++) { |
+ DartType type = _getTypeOfCorrespondingParameter( |
+ parameter, index, overriddenMethods[i]); |
+ if (parameterType == null) { |
+ parameterType = type; |
+ } else if (parameterType != type) { |
+ return typeProvider.dynamicType; |
+ } |
+ } |
+ return parameterType == null ? typeProvider.dynamicType : parameterType; |
+ } |
+ |
+ /** |
* Compute the best return type for a method that must be compatible with the |
* return types of each of the given [overriddenMethods]. |
* |
@@ -209,6 +236,49 @@ class InstanceMemberInferrer { |
} |
/** |
+ * Given a [method], return the type of the parameter in the method that |
+ * corresponds to the given [parameter]. If the parameter is positional, then |
+ * it appears at the given [index] in it's enclosing element's list of |
Leaf
2015/08/26 17:11:09
it's -> its.
Brian Wilkerson
2015/08/26 17:36:15
Done
|
+ * parameters. |
+ */ |
+ DartType _getTypeOfCorrespondingParameter( |
+ ParameterElement parameter, int index, ExecutableElement method) { |
+ // |
+ // Find the corresponding parameter. |
+ // |
+ List<ParameterElement> methodParameters = method.parameters; |
+ ParameterElement matchingParameter = null; |
+ if (parameter.parameterKind == ParameterKind.NAMED) { |
+ // |
+ // If we're looking for a named parameter, only a named parameter with |
+ // the same name will be matched. |
+ // |
+ matchingParameter = methodParameters.lastWhere( |
+ (ParameterElement methodParameter) => |
+ methodParameter.parameterKind == ParameterKind.NAMED && |
+ methodParameter.name == parameter.name, |
+ orElse: () => null); |
+ } else { |
+ // |
+ // If we're looking for a positional parameter we ignore the difference |
+ // between required and optional parameters. |
+ // |
+ if (index < methodParameters.length) { |
+ matchingParameter = methodParameters[index]; |
+ if (matchingParameter.parameterKind == ParameterKind.NAMED) { |
+ matchingParameter = null; |
+ } |
+ } |
+ } |
+ // |
+ // Then return the type of the parameter. |
+ // |
+ return matchingParameter == null |
+ ? typeProvider.dynamicType |
+ : matchingParameter.type; |
+ } |
+ |
+ /** |
* If the given [accessorElement] represents a non-synthetic instance getter |
* for which no return type was provided, infer the return type of the getter. |
*/ |
@@ -324,15 +394,43 @@ class InstanceMemberInferrer { |
* for which no return type was provided, infer the return type of the method. |
*/ |
void _inferMethod(MethodElement methodElement) { |
- if (!methodElement.isSynthetic && |
- !methodElement.isStatic && |
- methodElement.hasImplicitReturnType && |
+ if (methodElement.isSynthetic || methodElement.isStatic) { |
+ return; |
+ } |
+ List<ExecutableElement> overriddenMethods = null; |
+ // |
+ // Infer the return type. |
+ // |
+ if (methodElement.hasImplicitReturnType && |
_getReturnType(methodElement).isDynamic) { |
- List<ExecutableElement> overriddenMethods = inheritanceManager |
- .lookupOverrides(methodElement.enclosingElement, methodElement.name); |
- if (overriddenMethods.isNotEmpty && _onlyMethods(overriddenMethods)) { |
- MethodElementImpl element = methodElement as MethodElementImpl; |
- _setReturnType(element, _computeReturnType(overriddenMethods)); |
+ overriddenMethods = inheritanceManager.lookupOverrides( |
+ methodElement.enclosingElement, methodElement.name); |
+ if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { |
+ return; |
+ } |
+ MethodElementImpl element = methodElement as MethodElementImpl; |
+ _setReturnType(element, _computeReturnType(overriddenMethods)); |
+ } |
+ // |
+ // Infer the parameter types. |
+ // |
+ List<ParameterElement> parameters = methodElement.parameters; |
+ var length = parameters.length; |
+ for (int i = 0; i < length; ++i) { |
+ ParameterElement parameter = parameters[i]; |
+ if (parameter.hasImplicitType && parameter.type.isDynamic) { |
+ overriddenMethods = overriddenMethods ?? |
vicb
2015/08/29 06:10:42
If the analyzer is supposed to work with SDK v1.11
Brian Wilkerson
2015/08/29 16:15:05
If only we had a tool that could tell us when we m
|
+ inheritanceManager.lookupOverrides( |
+ methodElement.enclosingElement, methodElement.name); |
+ if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { |
+ return; |
+ } |
+ DartType type = _computeParameterType(parameter, i, overriddenMethods); |
+ if (!type.isDynamic) { |
+ if (parameter is ParameterElementImpl) { |
+ parameter.type = type; |
+ } |
+ } |
} |
} |
} |