Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(705)

Side by Side Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 2176693003: Issue a strong mode warning for type inference that is unsafe with AST-based summaries. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address code review comments. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
6 // refactored to fit into analyzer. 6 // refactored to fit into analyzer.
7 library analyzer.src.task.strong.checker; 7 library analyzer.src.task.strong.checker;
8 8
9 import 'package:analyzer/analyzer.dart'; 9 import 'package:analyzer/analyzer.dart';
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 373
374 @override 374 @override
375 void visitForStatement(ForStatement node) { 375 void visitForStatement(ForStatement node) {
376 if (node.condition != null) { 376 if (node.condition != null) {
377 checkBoolean(node.condition); 377 checkBoolean(node.condition);
378 } 378 }
379 node.visitChildren(this); 379 node.visitChildren(this);
380 } 380 }
381 381
382 @override 382 @override
383 void visitFunctionExpression(FunctionExpression node) {
384 _checkForUnsafeBlockClosureInference(node);
385 super.visitFunctionExpression(node);
386 }
387
388 @override
383 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { 389 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
384 checkFunctionApplication(node, node.function, node.argumentList); 390 checkFunctionApplication(node, node.function, node.argumentList);
385 node.visitChildren(this); 391 node.visitChildren(this);
386 } 392 }
387 393
388 @override 394 @override
389 void visitIfStatement(IfStatement node) { 395 void visitIfStatement(IfStatement node) {
390 checkBoolean(node.condition); 396 checkBoolean(node.condition);
391 node.visitChildren(this); 397 node.visitChildren(this);
392 } 398 }
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 } 712 }
707 713
708 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { 714 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
709 if ((_isDynamicTarget(target) || field.staticElement == null) && 715 if ((_isDynamicTarget(target) || field.staticElement == null) &&
710 !_isObjectProperty(target, field)) { 716 !_isObjectProperty(target, field)) {
711 _recordDynamicInvoke(node, target); 717 _recordDynamicInvoke(node, target);
712 } 718 }
713 node.visitChildren(this); 719 node.visitChildren(this);
714 } 720 }
715 721
722 /**
723 * Check if the closure [node] is unsafe due to dartbug.com/26947. If so,
724 * issue a warning.
725 *
726 * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed.
727 */
728 void _checkForUnsafeBlockClosureInference(FunctionExpression node) {
729 if (node.body is! BlockFunctionBody) {
730 return;
731 }
732 if (node.element.returnType.isDynamic) {
733 return;
734 }
735 // Find the enclosing variable declaration whose inferred type might depend
736 // on the inferred return type of the block closure (if any).
737 AstNode prevAncestor = node;
738 AstNode ancestor = node.parent;
739 while (ancestor != null && ancestor is! VariableDeclaration) {
740 if (ancestor is BlockFunctionBody) {
741 // node is inside another block function body; if that block
742 // function body is unsafe, we've already warned about it.
743 return;
744 }
745 if (ancestor is InstanceCreationExpression) {
746 // node appears inside an instance creation expression; we may be safe
747 // if the type of the instance creation expression requires no
748 // inference.
749 TypeName typeName = ancestor.constructorName.type;
750 if (typeName.typeArguments != null) {
751 // Type arguments were explicitly specified. We are safe.
752 return;
753 }
754 DartType type = typeName.type;
755 if (!(type is ParameterizedType && type.typeParameters.isNotEmpty)) {
756 // Type is not generic. We are safe.
757 return;
758 }
759 }
760 if (ancestor is MethodInvocation) {
761 // node appears inside a method or function invocation; we may be safe
762 // if the type of the method or function requires no inference.
763 if (ancestor.typeArguments != null) {
764 // Type arguments were explicitly specified. We are safe.
765 return;
766 }
767 Element methodElement = ancestor.methodName.staticElement;
768 if (!(methodElement is ExecutableElement &&
769 methodElement.typeParameters.isNotEmpty)) {
770 // Method is not generic. We are safe.
771 return;
772 }
773 }
774 if (ancestor is FunctionExpressionInvocation &&
775 !identical(prevAncestor, ancestor.function)) {
776 // node appears inside an argument to a function expression invocation;
777 // we may be safe if the type of the function expression requires no
778 // inference.
779 if (ancestor.typeArguments != null) {
780 // Type arguments were explicitly specified. We are safe.
781 return;
782 }
783 DartType type = ancestor.function.staticType;
784 if (!(type is FunctionTypeImpl && type.typeFormals.isNotEmpty)) {
785 // Type is not generic or has had its type parameters instantiated.
786 // We are safe.
787 return;
788 }
789 }
790 if ((ancestor is ListLiteral && ancestor.typeArguments != null) ||
791 (ancestor is MapLiteral && ancestor.typeArguments != null)) {
792 // node appears inside a list or map literal with an explicit type. We
793 // are safe because no type inference is required.
794 return;
795 }
796 prevAncestor = ancestor;
797 ancestor = ancestor.parent;
798 }
799 if (ancestor == null) {
800 // node is not inside a variable declaration, so it is safe.
801 return;
802 }
803 VariableDeclaration decl = ancestor;
804 VariableElement declElement = decl.element;
805 if (!declElement.hasImplicitType) {
806 // Variable declaration has an explicit type, so it's safe.
807 return;
808 }
809 if (declElement.type.isDynamic) {
810 // No type was successfully inferred for this variable, so it's safe.
811 return;
812 }
813 if (declElement.enclosingElement is ExecutableElement) {
814 // Variable declaration is inside a function or method, so it's safe.
815 return;
816 }
817 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE,
818 [declElement.name]);
819 }
820
716 void _checkReturnOrYield(Expression expression, AstNode node, 821 void _checkReturnOrYield(Expression expression, AstNode node,
717 {bool yieldStar: false}) { 822 {bool yieldStar: false}) {
718 FunctionBody body = node.getAncestor((n) => n is FunctionBody); 823 FunctionBody body = node.getAncestor((n) => n is FunctionBody);
719 var type = _getExpectedReturnType(body, yieldStar: yieldStar); 824 var type = _getExpectedReturnType(body, yieldStar: yieldStar);
720 if (type == null) { 825 if (type == null) {
721 // We have a type mismatch: the async/async*/sync* modifier does 826 // We have a type mismatch: the async/async*/sync* modifier does
722 // not match the return or yield type. We should have already gotten an 827 // not match the return or yield type. We should have already gotten an
723 // analyzer error in this case. 828 // analyzer error in this case.
724 return; 829 return;
725 } 830 }
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
1370 var visited = new Set<InterfaceType>(); 1475 var visited = new Set<InterfaceType>();
1371 do { 1476 do {
1372 visited.add(current); 1477 visited.add(current);
1373 current.mixins.reversed.forEach( 1478 current.mixins.reversed.forEach(
1374 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); 1479 (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
1375 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); 1480 _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
1376 current = current.superclass; 1481 current = current.superclass;
1377 } while (!current.isObject && !visited.contains(current)); 1482 } while (!current.isObject && !visited.contains(current));
1378 } 1483 }
1379 } 1484 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698