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

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

Issue 2342733002: Break up another large file (Closed)
Patch Set: fixed floating comment Created 4 years, 3 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';
11 import 'package:analyzer/dart/ast/token.dart' show TokenType; 11 import 'package:analyzer/dart/ast/token.dart' show TokenType;
12 import 'package:analyzer/dart/ast/token.dart'; 12 import 'package:analyzer/dart/ast/token.dart';
13 import 'package:analyzer/dart/ast/visitor.dart'; 13 import 'package:analyzer/dart/ast/visitor.dart';
14 import 'package:analyzer/dart/element/element.dart'; 14 import 'package:analyzer/dart/element/element.dart';
15 import 'package:analyzer/dart/element/type.dart'; 15 import 'package:analyzer/dart/element/type.dart';
16 import 'package:analyzer/src/dart/element/type.dart'; 16 import 'package:analyzer/src/dart/element/type.dart';
17 import 'package:analyzer/src/error/codes.dart' show StrongModeCode;
17 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; 18 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
18 import 'package:analyzer/src/generated/error.dart' show StrongModeCode;
19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; 19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
20 import 'package:analyzer/src/generated/type_system.dart'; 20 import 'package:analyzer/src/generated/type_system.dart';
21 21
22 import 'ast_properties.dart'; 22 import 'ast_properties.dart';
23 23
24 bool isKnownFunction(Expression expression) {
25 var element = _getKnownElement(expression);
26 // First class functions and static methods, where we know the original
27 // declaration, will have an exact type, so we know a downcast will fail.
28 return element is FunctionElement ||
29 element is MethodElement && element.isStatic;
30 }
31
32 /// Given an [expression] and a corresponding [typeSystem] and [typeProvider], 24 /// Given an [expression] and a corresponding [typeSystem] and [typeProvider],
33 /// gets the known static type of the expression. 25 /// gets the known static type of the expression.
34 /// 26 ///
35 /// Normally when we ask for an expression's type, we get the type of the 27 /// Normally when we ask for an expression's type, we get the type of the
36 /// storage slot that would contain it. For function types, this is necessarily 28 /// storage slot that would contain it. For function types, this is necessarily
37 /// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're 29 /// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're
38 /// interested in the expression's own type, it can often be a "strict arrow" 30 /// interested in the expression's own type, it can often be a "strict arrow"
39 /// because we know it evaluates to a specific, concrete function, and we can 31 /// because we know it evaluates to a specific, concrete function, and we can
40 /// treat "dynamic" as top for that case, which is more permissive. 32 /// treat "dynamic" as top for that case, which is more permissive.
41 DartType getDefiniteType( 33 DartType getDefiniteType(
42 Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) { 34 Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) {
43 DartType type = expression.staticType ?? DynamicTypeImpl.instance; 35 DartType type = expression.staticType ?? DynamicTypeImpl.instance;
44 if (typeSystem is StrongTypeSystemImpl && 36 if (typeSystem is StrongTypeSystemImpl &&
45 type is FunctionType && 37 type is FunctionType &&
46 _hasStrictArrow(expression)) { 38 _hasStrictArrow(expression)) {
47 // Remove fuzzy arrow if possible. 39 // Remove fuzzy arrow if possible.
48 return typeSystem.functionTypeToConcreteType(typeProvider, type); 40 return typeSystem.functionTypeToConcreteType(typeProvider, type);
49 } 41 }
50 return type; 42 return type;
51 } 43 }
52 44
53 bool _hasStrictArrow(Expression expression) { 45 bool isKnownFunction(Expression expression) {
54 var element = _getKnownElement(expression); 46 var element = _getKnownElement(expression);
55 return element is FunctionElement || element is MethodElement; 47 // First class functions and static methods, where we know the original
48 // declaration, will have an exact type, so we know a downcast will fail.
49 return element is FunctionElement ||
50 element is MethodElement && element.isStatic;
51 }
52
53 DartType _elementType(Element e) {
54 if (e == null) {
55 // Malformed code - just return dynamic.
56 return DynamicTypeImpl.instance;
57 }
58 return (e as dynamic).type;
56 } 59 }
57 60
58 Element _getKnownElement(Expression expression) { 61 Element _getKnownElement(Expression expression) {
59 if (expression is ParenthesizedExpression) { 62 if (expression is ParenthesizedExpression) {
60 expression = (expression as ParenthesizedExpression).expression; 63 expression = (expression as ParenthesizedExpression).expression;
61 } 64 }
62 if (expression is FunctionExpression) { 65 if (expression is FunctionExpression) {
63 return expression.element; 66 return expression.element;
64 } else if (expression is PropertyAccess) { 67 } else if (expression is PropertyAccess) {
65 return expression.propertyName.staticElement; 68 return expression.propertyName.staticElement;
66 } else if (expression is Identifier) { 69 } else if (expression is Identifier) {
67 return expression.staticElement; 70 return expression.staticElement;
68 } 71 }
69 return null; 72 return null;
70 } 73 }
71 74
72 DartType _elementType(Element e) { 75 /// Return the field on type corresponding to member, or null if none
73 if (e == null) { 76 /// exists or the "field" is actually a getter/setter.
74 // Malformed code - just return dynamic.
75 return DynamicTypeImpl.instance;
76 }
77 return (e as dynamic).type;
78 }
79
80 // Return the field on type corresponding to member, or null if none
81 // exists or the "field" is actually a getter/setter.
82 PropertyInducingElement _getMemberField( 77 PropertyInducingElement _getMemberField(
83 InterfaceType type, PropertyAccessorElement member) { 78 InterfaceType type, PropertyAccessorElement member) {
84 String memberName = member.name; 79 String memberName = member.name;
85 PropertyInducingElement field; 80 PropertyInducingElement field;
86 if (member.isGetter) { 81 if (member.isGetter) {
87 // The subclass member is an explicit getter or a field 82 // The subclass member is an explicit getter or a field
88 // - lookup the getter on the superclass. 83 // - lookup the getter on the superclass.
89 var getter = type.getGetter(memberName); 84 var getter = type.getGetter(memberName);
90 if (getter == null || getter.isStatic) return null; 85 if (getter == null || getter.isStatic) return null;
91 field = getter.variable; 86 field = getter.variable;
(...skipping 10 matching lines...) Expand all
102 } 97 }
103 if (field.isSynthetic) return null; 98 if (field.isSynthetic) return null;
104 return field; 99 return field;
105 } 100 }
106 101
107 /// Looks up the declaration that matches [member] in [type] and returns it's 102 /// Looks up the declaration that matches [member] in [type] and returns it's
108 /// declared type. 103 /// declared type.
109 FunctionType _getMemberType(InterfaceType type, ExecutableElement member) => 104 FunctionType _getMemberType(InterfaceType type, ExecutableElement member) =>
110 _memberTypeGetter(member)(type); 105 _memberTypeGetter(member)(type);
111 106
107 bool _hasStrictArrow(Expression expression) {
108 var element = _getKnownElement(expression);
109 return element is FunctionElement || element is MethodElement;
110 }
111
112 _MemberTypeGetter _memberTypeGetter(ExecutableElement member) { 112 _MemberTypeGetter _memberTypeGetter(ExecutableElement member) {
113 String memberName = member.name; 113 String memberName = member.name;
114 final isGetter = member is PropertyAccessorElement && member.isGetter; 114 final isGetter = member is PropertyAccessorElement && member.isGetter;
115 final isSetter = member is PropertyAccessorElement && member.isSetter; 115 final isSetter = member is PropertyAccessorElement && member.isSetter;
116 116
117 FunctionType f(InterfaceType type) { 117 FunctionType f(InterfaceType type) {
118 ExecutableElement baseMethod; 118 ExecutableElement baseMethod;
119 119
120 if (member.isPrivate) { 120 if (member.isPrivate) {
121 var subtypeLibrary = member.library; 121 var subtypeLibrary = member.library;
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 @override 633 @override
634 void visitSwitchStatement(SwitchStatement node) { 634 void visitSwitchStatement(SwitchStatement node) {
635 // SwitchStatement defines a boolean conversion to check the result of the 635 // SwitchStatement defines a boolean conversion to check the result of the
636 // case value == the switch value, but in dev_compiler we require a boolean 636 // case value == the switch value, but in dev_compiler we require a boolean
637 // return type from an overridden == operator (because Object.==), so 637 // return type from an overridden == operator (because Object.==), so
638 // checking in SwitchStatement shouldn't be necessary. 638 // checking in SwitchStatement shouldn't be necessary.
639 node.visitChildren(this); 639 node.visitChildren(this);
640 } 640 }
641 641
642 @override 642 @override
643 Object visitVariableDeclaration(VariableDeclaration node) {
644 if (!node.isConst &&
645 !node.isFinal &&
646 node.initializer == null &&
647 rules.isNonNullableType(node?.element?.type)) {
648 _recordMessage(
649 node,
650 StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED,
651 [node.name, node?.element?.type]);
652 }
653 return super.visitVariableDeclaration(node);
654 }
655
656 @override
643 void visitVariableDeclarationList(VariableDeclarationList node) { 657 void visitVariableDeclarationList(VariableDeclarationList node) {
644 TypeName type = node.type; 658 TypeName type = node.type;
645 if (type == null) { 659 if (type == null) {
646 // No checks are needed when the type is var. Although internally the 660 // No checks are needed when the type is var. Although internally the
647 // typing rules may have inferred a more precise type for the variable 661 // typing rules may have inferred a more precise type for the variable
648 // based on the initializer. 662 // based on the initializer.
649 } else { 663 } else {
650 for (VariableDeclaration variable in node.variables) { 664 for (VariableDeclaration variable in node.variables) {
651 var initializer = variable.initializer; 665 var initializer = variable.initializer;
652 if (initializer != null) { 666 if (initializer != null) {
653 checkAssignment(initializer, type.type); 667 checkAssignment(initializer, type.type);
654 } 668 }
655 } 669 }
656 } 670 }
657 node.visitChildren(this); 671 node.visitChildren(this);
658 } 672 }
659 673
660 @override 674 @override
661 Object visitVariableDeclaration(VariableDeclaration node) {
662 if (!node.isConst &&
663 !node.isFinal &&
664 node.initializer == null &&
665 rules.isNonNullableType(node?.element?.type)) {
666 _recordMessage(
667 node,
668 StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED,
669 [node.name, node?.element?.type]);
670 }
671 return super.visitVariableDeclaration(node);
672 }
673
674 @override
675 void visitWhileStatement(WhileStatement node) { 675 void visitWhileStatement(WhileStatement node) {
676 checkBoolean(node.condition); 676 checkBoolean(node.condition);
677 node.visitChildren(this); 677 node.visitChildren(this);
678 } 678 }
679 679
680 @override 680 @override
681 void visitYieldStatement(YieldStatement node) { 681 void visitYieldStatement(YieldStatement node) {
682 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); 682 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null);
683 node.visitChildren(this); 683 node.visitChildren(this);
684 } 684 }
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
870 // Variable declaration is inside a function or method, so it's safe. 870 // Variable declaration is inside a function or method, so it's safe.
871 return; 871 return;
872 } 872 }
873 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, 873 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE,
874 [declElement.name]); 874 [declElement.name]);
875 } 875 }
876 876
877 /// Checks if the assignment is valid with respect to non-nullable types. 877 /// Checks if the assignment is valid with respect to non-nullable types.
878 /// Returns `false` if a nullable expression is assigned to a variable of 878 /// Returns `false` if a nullable expression is assigned to a variable of
879 /// non-nullable type and `true` otherwise. 879 /// non-nullable type and `true` otherwise.
880 bool _checkNonNullAssignment(Expression expression, DartType to, DartType from ) { 880 bool _checkNonNullAssignment(
881 Expression expression, DartType to, DartType from) {
881 if (rules.isNonNullableType(to) && rules.isNullableType(from)) { 882 if (rules.isNonNullableType(to) && rules.isNullableType(from)) {
882 _recordMessage(expression, StaticTypeWarningCode.INVALID_ASSIGNMENT, 883 _recordMessage(
883 [from, to]); 884 expression, StaticTypeWarningCode.INVALID_ASSIGNMENT, [from, to]);
884 return false; 885 return false;
885 } 886 }
886 return true; 887 return true;
887 } 888 }
888 889
889 void _checkReturnOrYield(Expression expression, AstNode node, 890 void _checkReturnOrYield(Expression expression, AstNode node,
890 {bool yieldStar: false}) { 891 {bool yieldStar: false}) {
891 FunctionBody body = node.getAncestor((n) => n is FunctionBody); 892 FunctionBody body = node.getAncestor((n) => n is FunctionBody);
892 var type = _getExpectedReturnType(body, yieldStar: yieldStar); 893 var type = _getExpectedReturnType(body, yieldStar: yieldStar);
893 if (type == null) { 894 if (type == null) {
(...skipping 22 matching lines...) Expand all
916 op.type == TokenType.MINUS_MINUS) { 917 op.type == TokenType.MINUS_MINUS) {
917 if (element == null) { 918 if (element == null) {
918 _recordDynamicInvoke(node, node.operand); 919 _recordDynamicInvoke(node, node.operand);
919 } 920 }
920 // For ++ and --, even if it is not dynamic, we still need to check 921 // For ++ and --, even if it is not dynamic, we still need to check
921 // that the user defined method accepts an `int` as the RHS. 922 // that the user defined method accepts an `int` as the RHS.
922 // We assume Analyzer has done this already. 923 // We assume Analyzer has done this already.
923 } 924 }
924 } 925 }
925 926
927 DartType _getDefiniteType(Expression expr) =>
928 getDefiniteType(expr, rules, typeProvider);
929
926 /// Gets the expected return type of the given function [body], either from 930 /// Gets the expected return type of the given function [body], either from
927 /// a normal return/yield, or from a yield*. 931 /// a normal return/yield, or from a yield*.
928 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { 932 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
929 FunctionType functionType; 933 FunctionType functionType;
930 var parent = body.parent; 934 var parent = body.parent;
931 if (parent is Declaration) { 935 if (parent is Declaration) {
932 functionType = _elementType(parent.element); 936 functionType = _elementType(parent.element);
933 } else { 937 } else {
934 assert(parent is FunctionExpression); 938 assert(parent is FunctionExpression);
935 functionType = 939 functionType =
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 if (type.isDynamic) { 974 if (type.isDynamic) {
971 return type; 975 return type;
972 } else if (type is InterfaceType && type.element == expectedType.element) { 976 } else if (type is InterfaceType && type.element == expectedType.element) {
973 return type.typeArguments[0]; 977 return type.typeArguments[0];
974 } else { 978 } else {
975 // Malformed type - fallback on analyzer error. 979 // Malformed type - fallback on analyzer error.
976 return null; 980 return null;
977 } 981 }
978 } 982 }
979 983
980 DartType _getDefiniteType(Expression expr) =>
981 getDefiniteType(expr, rules, typeProvider);
982
983 /// Given an expression, return its type assuming it is 984 /// Given an expression, return its type assuming it is
984 /// in the caller position of a call (that is, accounting 985 /// in the caller position of a call (that is, accounting
985 /// for the possibility of a call method). Returns null 986 /// for the possibility of a call method). Returns null
986 /// if expression is not statically callable. 987 /// if expression is not statically callable.
987 FunctionType _getTypeAsCaller(InvocationExpression node) { 988 FunctionType _getTypeAsCaller(InvocationExpression node) {
988 DartType type = node.staticInvokeType; 989 DartType type = node.staticInvokeType;
989 if (type is FunctionType) { 990 if (type is FunctionType) {
990 return type; 991 return type;
991 } else if (type is InterfaceType) { 992 } else if (type is InterfaceType) {
992 return rules.getCallMethodType(type); 993 return rules.getCallMethodType(type);
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after
1462 var visited = new Set<InterfaceType>(); 1463 var visited = new Set<InterfaceType>();
1463 do { 1464 do {
1464 visited.add(current); 1465 visited.add(current);
1465 current.mixins.reversed.forEach( 1466 current.mixins.reversed.forEach(
1466 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); 1467 (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
1467 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); 1468 _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
1468 current = current.superclass; 1469 current = current.superclass;
1469 } while (!current.isObject && !visited.contains(current)); 1470 } while (!current.isObject && !visited.contains(current));
1470 } 1471 }
1471 } 1472 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/task/options_work_manager.dart ('k') | pkg/analyzer/lib/src/task/yaml.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698