Chromium Code Reviews| Index: pkg/analyzer/lib/src/task/strong/checker.dart |
| diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart |
| index 568bf3069595ddaff612925f49439cd640106c25..86969f58d80dc6bb95991fdd6f593f61cdba3d8e 100644 |
| --- a/pkg/analyzer/lib/src/task/strong/checker.dart |
| +++ b/pkg/analyzer/lib/src/task/strong/checker.dart |
| @@ -380,6 +380,12 @@ class CodeChecker extends RecursiveAstVisitor { |
| } |
| @override |
| + void visitFunctionExpression(FunctionExpression node) { |
| + _checkForUnsafeBlockClosureInference(node); |
| + super.visitFunctionExpression(node); |
| + } |
| + |
| + @override |
| void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| checkFunctionApplication(node, node.function, node.argumentList); |
| node.visitChildren(this); |
| @@ -713,6 +719,71 @@ class CodeChecker extends RecursiveAstVisitor { |
| node.visitChildren(this); |
| } |
| + /** |
| + * Check if the closure [node] is unsafe due to dartbug.com/26947. If so, |
| + * issue a warning. |
| + * |
| + * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed. |
| + */ |
| + void _checkForUnsafeBlockClosureInference(FunctionExpression node) { |
| + if (node.body is! BlockFunctionBody) { |
| + return; |
| + } |
| + if (node.element.returnType.isDynamic) { |
| + return; |
| + } |
| + // Find the enclosing variable declaration whose inferred type might depend |
| + // on the inferred return type of the block closure (if any). |
| + VariableDeclaration decl = null; |
| + AstNode ancestor = node.parent; |
| + while (ancestor != null) { |
| + if (ancestor is BlockFunctionBody) { |
| + // node is inside another block function body; if that block |
| + // function body is unsafe, we've already warned about it. |
| + return; |
| + } |
| + if (ancestor is VariableDeclaration) { |
|
Leaf
2016/07/22 23:34:41
Might be a bit clearer just to make this part of t
Paul Berry
2016/07/23 16:18:18
Done.
|
| + decl = ancestor; |
| + break; |
| + } |
| + if (ancestor is InstanceCreationExpression) { |
|
Leaf
2016/07/22 23:34:41
Presumably this same logic could be applied to Lis
Paul Berry
2016/07/23 16:18:18
Done. PTAL.
|
| + // node appears inside an instance creation expression; we may be safe |
| + // if the type of the instance creation expression requires no |
| + // inference. |
| + TypeName typeName = ancestor.constructorName.type; |
| + DartType type = typeName.type; |
| + if (typeName.typeArguments != null) { |
| + // Type arguments were explicitly specified. We are safe. |
| + return; |
| + } |
| + if (!(type is ParameterizedType && type.typeParameters.isNotEmpty)) { |
| + // Type is not generic. We are safe. |
| + return; |
| + } |
| + } |
| + ancestor = ancestor.parent; |
| + } |
| + if (decl == null) { |
| + // node is not inside a variable declaration, so it is safe. |
| + return; |
| + } |
| + VariableElement declElement = decl.element; |
| + if (!declElement.hasImplicitType) { |
| + // Variable declaration has an explicit type, so it's safe. |
| + return; |
| + } |
| + if (declElement.type.isDynamic) { |
| + // No type was successfully inferred for this variable, so it's safe. |
| + return; |
| + } |
| + if (declElement.enclosingElement is ExecutableElement) { |
| + // Variable declaration is inside a function or method, so it's safe. |
| + return; |
| + } |
| + _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, |
| + [declElement.name]); |
| + } |
| + |
| void _checkReturnOrYield(Expression expression, AstNode node, |
| {bool yieldStar: false}) { |
| FunctionBody body = node.getAncestor((n) => n is FunctionBody); |