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

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

Issue 2062793003: Revert "Revert "Refactor strong mode to use standard Analyzer errors"" (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 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/visitor.dart'; 12 import 'package:analyzer/dart/ast/visitor.dart';
13 import 'package:analyzer/dart/element/element.dart'; 13 import 'package:analyzer/dart/element/element.dart';
14 import 'package:analyzer/dart/element/type.dart'; 14 import 'package:analyzer/dart/element/type.dart';
15 import 'package:analyzer/src/dart/element/type.dart'; 15 import 'package:analyzer/src/dart/element/type.dart';
16 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; 16 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
17 import 'package:analyzer/src/generated/error.dart' show StrongModeCode;
17 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; 18 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
18 import 'package:analyzer/src/generated/type_system.dart'; 19 import 'package:analyzer/src/generated/type_system.dart';
19 20
20 import 'info.dart'; 21 import 'ast_properties.dart';
21 22
22 DartType _elementType(Element e) { 23 DartType _elementType(Element e) {
23 if (e == null) { 24 if (e == null) {
24 // Malformed code - just return dynamic. 25 // Malformed code - just return dynamic.
25 return DynamicTypeImpl.instance; 26 return DynamicTypeImpl.instance;
26 } 27 }
27 return (e as dynamic).type; 28 return (e as dynamic).type;
28 } 29 }
29 30
30 PropertyInducingElement _getMemberField( 31 PropertyInducingElement _getMemberField(
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 return f; 95 return f;
95 } 96 }
96 97
97 typedef FunctionType _MemberTypeGetter(InterfaceType type); 98 typedef FunctionType _MemberTypeGetter(InterfaceType type);
98 99
99 /// Checks the body of functions and properties. 100 /// Checks the body of functions and properties.
100 class CodeChecker extends RecursiveAstVisitor { 101 class CodeChecker extends RecursiveAstVisitor {
101 final StrongTypeSystemImpl rules; 102 final StrongTypeSystemImpl rules;
102 final TypeProvider typeProvider; 103 final TypeProvider typeProvider;
103 final AnalysisErrorListener reporter; 104 final AnalysisErrorListener reporter;
104 final _OverrideChecker _overrideChecker;
105 final AnalysisOptionsImpl _options; 105 final AnalysisOptionsImpl _options;
106 _OverrideChecker _overrideChecker;
106 107
107 bool _failure = false; 108 bool _failure = false;
109 bool _hasImplicitCasts;
108 110
109 CodeChecker(TypeProvider typeProvider, StrongTypeSystemImpl rules, 111 CodeChecker(TypeProvider typeProvider, StrongTypeSystemImpl rules,
110 AnalysisErrorListener reporter, this._options) 112 AnalysisErrorListener reporter, this._options)
111 : typeProvider = typeProvider, 113 : typeProvider = typeProvider,
112 rules = rules, 114 rules = rules,
113 reporter = reporter, 115 reporter = reporter {
114 _overrideChecker = new _OverrideChecker(typeProvider, rules, reporter); 116 _overrideChecker = new _OverrideChecker(this);
117 }
115 118
116 bool get failure => _failure || _overrideChecker._failure; 119 bool get failure => _failure;
117 120
118 void checkArgument(Expression arg, DartType expectedType) { 121 void checkArgument(Expression arg, DartType expectedType) {
119 // Preserve named argument structure, so their immediate parent is the 122 // Preserve named argument structure, so their immediate parent is the
120 // method invocation. 123 // method invocation.
121 Expression baseExpression = arg is NamedExpression ? arg.expression : arg; 124 Expression baseExpression = arg is NamedExpression ? arg.expression : arg;
122 checkAssignment(baseExpression, expectedType); 125 checkAssignment(baseExpression, expectedType);
123 } 126 }
124 127
125 void checkArgumentList(ArgumentList node, FunctionType type) { 128 void checkArgumentList(ArgumentList node, FunctionType type) {
126 NodeList<Expression> list = node.arguments; 129 NodeList<Expression> list = node.arguments;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 checkArgumentList(list, _getTypeAsCaller(f)); 166 checkArgumentList(list, _getTypeAsCaller(f));
164 } 167 }
165 } 168 }
166 169
167 DartType getType(TypeName name) { 170 DartType getType(TypeName name) {
168 return (name == null) ? DynamicTypeImpl.instance : name.type; 171 return (name == null) ? DynamicTypeImpl.instance : name.type;
169 } 172 }
170 173
171 void reset() { 174 void reset() {
172 _failure = false; 175 _failure = false;
173 _overrideChecker._failure = false;
174 } 176 }
175 177
176 @override 178 @override
179 void visitCompilationUnit(CompilationUnit node) {
180 _hasImplicitCasts = false;
181 node.visitChildren(this);
182 setHasImplicitCasts(node, _hasImplicitCasts);
183 }
184
185 @override
177 void visitAsExpression(AsExpression node) { 186 void visitAsExpression(AsExpression node) {
178 // We could do the same check as the IsExpression below, but that is 187 // We could do the same check as the IsExpression below, but that is
179 // potentially too conservative. Instead, at runtime, we must fail hard 188 // potentially too conservative. Instead, at runtime, we must fail hard
180 // if the Dart as and the DDC as would return different values. 189 // if the Dart as and the DDC as would return different values.
181 node.visitChildren(this); 190 node.visitChildren(this);
182 } 191 }
183 192
184 @override 193 @override
185 void visitAssignmentExpression(AssignmentExpression node) { 194 void visitAssignmentExpression(AssignmentExpression node) {
186 var token = node.operator; 195 var token = node.operator;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 266
258 /// Check constructor declaration to ensure correct super call placement. 267 /// Check constructor declaration to ensure correct super call placement.
259 @override 268 @override
260 void visitConstructorDeclaration(ConstructorDeclaration node) { 269 void visitConstructorDeclaration(ConstructorDeclaration node) {
261 node.visitChildren(this); 270 node.visitChildren(this);
262 271
263 final init = node.initializers; 272 final init = node.initializers;
264 for (int i = 0, last = init.length - 1; i < last; i++) { 273 for (int i = 0, last = init.length - 1; i < last; i++) {
265 final node = init[i]; 274 final node = init[i];
266 if (node is SuperConstructorInvocation) { 275 if (node is SuperConstructorInvocation) {
267 _recordMessage(new InvalidSuperInvocation(node)); 276 _recordMessage(node, StrongModeCode.INVALID_SUPER_INVOCATION, [node]);
268 } 277 }
269 } 278 }
270 } 279 }
271 280
272 // Check invocations 281 // Check invocations
273 @override 282 @override
274 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) { 283 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
275 var field = node.fieldName; 284 var field = node.fieldName;
276 var element = field.staticElement; 285 var element = field.staticElement;
277 DartType staticType = _elementType(element); 286 DartType staticType = _elementType(element);
(...skipping 30 matching lines...) Expand all
308 @override 317 @override
309 void visitFieldFormalParameter(FieldFormalParameter node) { 318 void visitFieldFormalParameter(FieldFormalParameter node) {
310 var element = node.element; 319 var element = node.element;
311 var typeName = node.type; 320 var typeName = node.type;
312 if (typeName != null) { 321 if (typeName != null) {
313 var type = _elementType(element); 322 var type = _elementType(element);
314 var fieldElement = 323 var fieldElement =
315 node.identifier.staticElement as FieldFormalParameterElement; 324 node.identifier.staticElement as FieldFormalParameterElement;
316 var fieldType = _elementType(fieldElement.field); 325 var fieldType = _elementType(fieldElement.field);
317 if (!rules.isSubtypeOf(type, fieldType)) { 326 if (!rules.isSubtypeOf(type, fieldType)) {
318 var staticInfo = 327 _recordMessage(node, StrongModeCode.INVALID_PARAMETER_DECLARATION,
319 new InvalidParameterDeclaration(rules, node, fieldType); 328 [node, fieldType]);
320 _recordMessage(staticInfo);
321 } 329 }
322 } 330 }
323 node.visitChildren(this); 331 node.visitChildren(this);
324 } 332 }
325 333
326 @override 334 @override
327 void visitForEachStatement(ForEachStatement node) { 335 void visitForEachStatement(ForEachStatement node) {
328 var loopVariable = node.identifier ?? node.loopVariable?.identifier; 336 var loopVariable = node.identifier ?? node.loopVariable?.identifier;
329 337
330 // Safely handle malformed statements. 338 // Safely handle malformed statements.
331 if (loopVariable != null) { 339 if (loopVariable != null) {
332 // Find the element type of the sequence. 340 // Find the element type of the sequence.
333 var sequenceInterface = node.awaitKeyword != null 341 var sequenceInterface = node.awaitKeyword != null
334 ? typeProvider.streamType 342 ? typeProvider.streamType
335 : typeProvider.iterableType; 343 : typeProvider.iterableType;
336 var iterableType = _getStaticType(node.iterable); 344 var iterableType = _getStaticType(node.iterable);
337 var elementType = 345 var elementType =
338 rules.mostSpecificTypeArgument(iterableType, sequenceInterface); 346 rules.mostSpecificTypeArgument(iterableType, sequenceInterface);
339 347
340 // If the sequence is not an Iterable (or Stream for await for) but is a 348 // If the sequence is not an Iterable (or Stream for await for) but is a
341 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then 349 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then
342 // we'll do a separate cast of the dynamic element to the variable's type. 350 // we'll do a separate cast of the dynamic element to the variable's type.
343 if (elementType == null) { 351 if (elementType == null) {
344 var sequenceType = 352 var sequenceType =
345 sequenceInterface.instantiate([DynamicTypeImpl.instance]); 353 sequenceInterface.instantiate([DynamicTypeImpl.instance]);
346 354
347 if (rules.isSubtypeOf(sequenceType, iterableType)) { 355 if (rules.isSubtypeOf(sequenceType, iterableType)) {
348 _recordMessage(DownCast.create( 356 _recordImplicitCast(node.iterable, iterableType, sequenceType);
349 rules, node.iterable, iterableType, sequenceType, _options));
350 elementType = DynamicTypeImpl.instance; 357 elementType = DynamicTypeImpl.instance;
351 } 358 }
352 } 359 }
353 360
354 // If the sequence doesn't implement the interface at all, [ErrorVerifier] 361 // If the sequence doesn't implement the interface at all, [ErrorVerifier]
355 // will report the error, so ignore it here. 362 // will report the error, so ignore it here.
356 if (elementType != null) { 363 if (elementType != null) {
357 // Insert a cast from the sequence's element type to the loop variable's 364 // Insert a cast from the sequence's element type to the loop variable's
358 // if needed. 365 // if needed.
359 _checkDowncast(loopVariable, _getStaticType(loopVariable), 366 _checkDowncast(loopVariable, _getStaticType(loopVariable),
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 // dynamic d; 500 // dynamic d;
494 // d.someMethod(...); // the whole method call must be a dynamic send. 501 // d.someMethod(...); // the whole method call must be a dynamic send.
495 // 502 //
496 // ... from case like: 503 // ... from case like:
497 // 504 //
498 // SomeType s; 505 // SomeType s;
499 // s.someDynamicField(...); // static get, followed by dynamic call. 506 // s.someDynamicField(...); // static get, followed by dynamic call.
500 // 507 //
501 // The first case is handled here, the second case is handled below when 508 // The first case is handled here, the second case is handled below when
502 // we call [checkFunctionApplication]. 509 // we call [checkFunctionApplication].
503 DynamicInvoke.set(node.methodName, true); 510 setIsDynamicInvoke(node.methodName, true);
504 } else { 511 } else {
505 checkFunctionApplication(node, node.methodName, node.argumentList); 512 checkFunctionApplication(node, node.methodName, node.argumentList);
506 } 513 }
507 node.visitChildren(this); 514 node.visitChildren(this);
508 } 515 }
509 516
510 @override 517 @override
511 void visitPostfixExpression(PostfixExpression node) { 518 void visitPostfixExpression(PostfixExpression node) {
512 _checkUnary(node); 519 _checkUnary(node);
513 node.visitChildren(this); 520 node.visitChildren(this);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 } else { 619 } else {
613 // Sanity check the operator. 620 // Sanity check the operator.
614 assert(methodElement.isOperator); 621 assert(methodElement.isOperator);
615 var functionType = methodElement.type; 622 var functionType = methodElement.type;
616 var paramTypes = functionType.normalParameterTypes; 623 var paramTypes = functionType.normalParameterTypes;
617 assert(paramTypes.length == 1); 624 assert(paramTypes.length == 1);
618 assert(functionType.namedParameterTypes.isEmpty); 625 assert(functionType.namedParameterTypes.isEmpty);
619 assert(functionType.optionalParameterTypes.isEmpty); 626 assert(functionType.optionalParameterTypes.isEmpty);
620 627
621 // Check the LHS type. 628 // Check the LHS type.
622 var staticInfo;
623 var rhsType = _getStaticType(expr.rightHandSide); 629 var rhsType = _getStaticType(expr.rightHandSide);
624 var lhsType = _getStaticType(expr.leftHandSide); 630 var lhsType = _getStaticType(expr.leftHandSide);
625 var returnType = rules.refineBinaryExpressionType( 631 var returnType = rules.refineBinaryExpressionType(
626 typeProvider, lhsType, op, rhsType, functionType.returnType); 632 typeProvider, lhsType, op, rhsType, functionType.returnType);
627 633
628 if (!rules.isSubtypeOf(returnType, lhsType)) { 634 if (!rules.isSubtypeOf(returnType, lhsType)) {
629 final numType = typeProvider.numType; 635 final numType = typeProvider.numType;
630 // Try to fix up the numerical case if possible. 636 // Try to fix up the numerical case if possible.
631 if (rules.isSubtypeOf(lhsType, numType) && 637 if (rules.isSubtypeOf(lhsType, numType) &&
632 rules.isSubtypeOf(lhsType, rhsType)) { 638 rules.isSubtypeOf(lhsType, rhsType)) {
633 // This is also slightly different from spec, but allows us to keep 639 // This is also slightly different from spec, but allows us to keep
634 // compound operators in the int += num and num += dynamic cases. 640 // compound operators in the int += num and num += dynamic cases.
635 staticInfo = DownCast.create( 641 _recordImplicitCast(expr.rightHandSide, rhsType, lhsType);
636 rules, expr.rightHandSide, rhsType, lhsType, _options);
637 rhsType = lhsType;
638 } else { 642 } else {
639 staticInfo = new StaticTypeError(expr, lhsType); 643 _recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR,
644 [expr, returnType, lhsType]);
640 } 645 }
641 _recordMessage(staticInfo); 646 } else {
642 } 647 // Check the RHS type.
643 648 //
644 // Check the rhs type 649 // This is only needed if we didn't already need a cast, and avoids
645 if (staticInfo is! CoercionInfo) { 650 // emitting two messages for the same expression.
646 var paramType = paramTypes.first; 651 _checkDowncast(expr.rightHandSide, paramTypes.first);
647 _checkDowncast(expr.rightHandSide, paramType);
648 } 652 }
649 } 653 }
650 } 654 }
651 655
652 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. 656 /// Records a [DownCast] of [expr] from [from] to [to], if there is one.
653 /// 657 ///
654 /// If [from] is omitted, uses the static type of [expr]. 658 /// If [from] is omitted, uses the static type of [expr].
655 /// 659 ///
656 /// If [expr] does not require a downcast because it is not related to [to] 660 /// If [expr] does not require a downcast because it is not related to [to]
657 /// or is already a subtype of it, does nothing. 661 /// or is already a subtype of it, does nothing.
(...skipping 14 matching lines...) Expand all
672 // Note: a function type is never assignable to a class per the Dart 676 // Note: a function type is never assignable to a class per the Dart
673 // spec - even if it has a compatible call method. We disallow as 677 // spec - even if it has a compatible call method. We disallow as
674 // well for consistency. 678 // well for consistency.
675 if ((from is FunctionType && rules.getCallMethodType(to) != null) || 679 if ((from is FunctionType && rules.getCallMethodType(to) != null) ||
676 (to is FunctionType && rules.getCallMethodType(from) != null)) { 680 (to is FunctionType && rules.getCallMethodType(from) != null)) {
677 return; 681 return;
678 } 682 }
679 683
680 // Downcast if toT <: fromT 684 // Downcast if toT <: fromT
681 if (rules.isSubtypeOf(to, from)) { 685 if (rules.isSubtypeOf(to, from)) {
682 _recordMessage(DownCast.create(rules, expr, from, to, _options)); 686 _recordImplicitCast(expr, from, to);
683 return; 687 return;
684 } 688 }
685 689
686 // TODO(vsm): Once we have generic methods, we should delete this 690 // TODO(vsm): Once we have generic methods, we should delete this
687 // workaround. These sideways casts are always ones we warn about 691 // workaround. These sideways casts are always ones we warn about
688 // - i.e., we think they are likely to fail at runtime. 692 // - i.e., we think they are likely to fail at runtime.
689 // ------- 693 // -------
690 // Downcast if toT <===> fromT 694 // Downcast if toT <===> fromT
691 // The intention here is to allow casts that are sideways in the restricted 695 // The intention here is to allow casts that are sideways in the restricted
692 // type system, but allowed in the regular dart type system, since these 696 // type system, but allowed in the regular dart type system, since these
693 // are likely to succeed. The canonical example is List<dynamic> and 697 // are likely to succeed. The canonical example is List<dynamic> and
694 // Iterable<T> for some concrete T (e.g. Object). These are unrelated 698 // Iterable<T> for some concrete T (e.g. Object). These are unrelated
695 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. 699 // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
696 if (from.isAssignableTo(to)) { 700 if (from.isAssignableTo(to)) {
697 _recordMessage(DownCast.create(rules, expr, from, to, _options)); 701 _recordImplicitCast(expr, from, to);
698 } 702 }
699 } 703 }
700 704
701 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { 705 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
702 if ((_isDynamicTarget(target) || field.staticElement == null) && 706 if ((_isDynamicTarget(target) || field.staticElement == null) &&
703 !_isObjectProperty(target, field)) { 707 !_isObjectProperty(target, field)) {
704 _recordDynamicInvoke(node, target); 708 _recordDynamicInvoke(node, target);
705 } 709 }
706 node.visitChildren(this); 710 node.visitChildren(this);
707 } 711 }
(...skipping 16 matching lines...) Expand all
724 actualType.element == futureType.element) { 728 actualType.element == futureType.element) {
725 type = futureType.instantiate([type]); 729 type = futureType.instantiate([type]);
726 } 730 }
727 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null. 731 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
728 if (expression != null) checkAssignment(expression, type); 732 if (expression != null) checkAssignment(expression, type);
729 } 733 }
730 734
731 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) { 735 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) {
732 var type = getType(typeName); 736 var type = getType(typeName);
733 if (!rules.isGroundType(type)) { 737 if (!rules.isGroundType(type)) {
734 _recordMessage(new NonGroundTypeCheckInfo(node, type)); 738 _recordMessage(node, StrongModeCode.NON_GROUND_TYPE_CHECK_INFO, [type]);
735 } 739 }
736 } 740 }
737 741
738 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) { 742 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) {
739 var op = node.operator; 743 var op = node.operator;
740 if (op.isUserDefinableOperator || 744 if (op.isUserDefinableOperator ||
741 op.type == TokenType.PLUS_PLUS || 745 op.type == TokenType.PLUS_PLUS ||
742 op.type == TokenType.MINUS_MINUS) { 746 op.type == TokenType.MINUS_MINUS) {
743 if (_isDynamicTarget(node.operand)) { 747 if (_isDynamicTarget(node.operand)) {
744 _recordDynamicInvoke(node, node.operand); 748 _recordDynamicInvoke(node, node.operand);
745 } 749 }
746 // For ++ and --, even if it is not dynamic, we still need to check 750 // For ++ and --, even if it is not dynamic, we still need to check
747 // that the user defined method accepts an `int` as the RHS. 751 // that the user defined method accepts an `int` as the RHS.
748 // We assume Analyzer has done this already. 752 // We assume Analyzer has done this already.
749 } 753 }
750 } 754 }
751 755
756 /// Records an implicit cast for the [expression] from [fromType] to [toType].
757 ///
758 /// This will emit the appropriate error/warning/hint message as well as mark
759 /// the AST node.
760 void _recordImplicitCast(
761 Expression expression, DartType fromType, DartType toType) {
762 // toT <:_R fromT => to <: fromT
763 // NB: classes with call methods are subtypes of function
764 // types, but the function type is not assignable to the class
765 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
766
767 // Inference "casts":
768 if (expression is Literal || expression is FunctionExpression) {
769 // fromT should be an exact type - this will almost certainly fail at
770 // runtime.
771 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
772 [expression, fromType, toType]);
773 return;
774 }
775
776 if (expression is InstanceCreationExpression) {
777 ConstructorElement e = expression.staticElement;
778 if (e == null || !e.isFactory) {
779 // fromT should be an exact type - this will almost certainly fail at
780 // runtime.
781
782 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
783 [expression, fromType, toType]);
784 return;
785 }
786 }
787
788 if (isKnownFunction(expression)) {
789 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR,
790 [expression, fromType, toType]);
791 return;
792 }
793
794 // TODO(vsm): Change this to an assert when we have generic methods and
795 // fix TypeRules._coerceTo to disallow implicit sideways casts.
796 bool downCastComposite = false;
797 if (!rules.isSubtypeOf(toType, fromType)) {
798 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
799 downCastComposite = true;
800 }
801
802 // Composite cast: these are more likely to fail.
803 if (!rules.isGroundType(toType)) {
804 // This cast is (probably) due to our different treatment of dynamic.
805 // It may be more likely to fail at runtime.
806 if (fromType is InterfaceType) {
807 // For class types, we'd like to allow non-generic down casts, e.g.,
808 // Iterable<T> to List<T>. The intuition here is that raw (generic)
809 // casts are problematic, and we should complain about those.
810 var typeArgs = fromType.typeArguments;
811 downCastComposite =
812 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
813 } else {
814 downCastComposite = true;
815 }
816 }
817
818 var parent = expression.parent;
819 ErrorCode errorCode;
820 if (downCastComposite) {
821 errorCode = StrongModeCode.DOWN_CAST_COMPOSITE;
822 } else if (fromType.isDynamic) {
823 errorCode = StrongModeCode.DYNAMIC_CAST;
824 } else if (parent is VariableDeclaration &&
825 parent.initializer == expression) {
826 errorCode = StrongModeCode.ASSIGNMENT_CAST;
827 } else {
828 errorCode = StrongModeCode.DOWN_CAST_IMPLICIT;
829 }
830
831 _recordMessage(expression, errorCode, [fromType, toType]);
832 setImplicitCast(expression, toType);
833 _hasImplicitCasts = true;
834 }
835
752 // Produce a coercion which coerces something of type fromT 836 // Produce a coercion which coerces something of type fromT
753 // to something of type toT. 837 // to something of type toT.
754 // Returns the error coercion if the types cannot be coerced 838 // Returns the error coercion if the types cannot be coerced
755 // according to our current criteria. 839 // according to our current criteria.
756 /// Gets the expected return type of the given function [body], either from 840 /// Gets the expected return type of the given function [body], either from
757 /// a normal return/yield, or from a yield*. 841 /// a normal return/yield, or from a yield*.
758 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { 842 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
759 FunctionType functionType; 843 FunctionType functionType;
760 var parent = body.parent; 844 var parent = body.parent;
761 if (parent is Declaration) { 845 if (parent is Declaration) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 } else { 888 } else {
805 // Malformed type - fallback on analyzer error. 889 // Malformed type - fallback on analyzer error.
806 return null; 890 return null;
807 } 891 }
808 } 892 }
809 893
810 DartType _getStaticType(Expression expr) { 894 DartType _getStaticType(Expression expr) {
811 DartType t = expr.staticType ?? DynamicTypeImpl.instance; 895 DartType t = expr.staticType ?? DynamicTypeImpl.instance;
812 896
813 // Remove fuzzy arrow if possible. 897 // Remove fuzzy arrow if possible.
814 if (t is FunctionType && StaticInfo.isKnownFunction(expr)) { 898 if (t is FunctionType && isKnownFunction(expr)) {
815 t = rules.functionTypeToConcreteType(typeProvider, t); 899 t = rules.functionTypeToConcreteType(typeProvider, t);
816 } 900 }
817 901
818 return t; 902 return t;
819 } 903 }
820 904
821 /// Given an expression, return its type assuming it is 905 /// Given an expression, return its type assuming it is
822 /// in the caller position of a call (that is, accounting 906 /// in the caller position of a call (that is, accounting
823 /// for the possibility of a call method). Returns null 907 /// for the possibility of a call method). Returns null
824 /// if expression is not statically callable. 908 /// if expression is not statically callable.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 970
887 bool _isObjectMethod(Expression target, SimpleIdentifier id) { 971 bool _isObjectMethod(Expression target, SimpleIdentifier id) {
888 MethodElement element = typeProvider.objectType.element.getMethod(id.name); 972 MethodElement element = typeProvider.objectType.element.getMethod(id.name);
889 return (element != null && !element.isStatic); 973 return (element != null && !element.isStatic);
890 } 974 }
891 975
892 bool _isObjectProperty(Expression target, SimpleIdentifier id) { 976 bool _isObjectProperty(Expression target, SimpleIdentifier id) {
893 return _isObjectGetter(target, id) || _isObjectMethod(target, id); 977 return _isObjectGetter(target, id) || _isObjectMethod(target, id);
894 } 978 }
895 979
896 void _recordDynamicInvoke(AstNode node, AstNode target) { 980 void _recordDynamicInvoke(AstNode node, Expression target) {
897 if (_options.strongModeHints) { 981 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]);
898 reporter.onError(new DynamicInvoke(node).toAnalysisError());
899 }
900 // TODO(jmesserly): we may eventually want to record if the whole operation 982 // TODO(jmesserly): we may eventually want to record if the whole operation
901 // (node) was dynamic, rather than the target, but this is an easier fit 983 // (node) was dynamic, rather than the target, but this is an easier fit
902 // with what we used to do. 984 // with what we used to do.
903 DynamicInvoke.set(target, true); 985 setIsDynamicInvoke(target, true);
904 } 986 }
905 987
906 void _recordMessage(StaticInfo info) { 988 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) {
907 if (info == null) return; 989 var severity = errorCode.errorSeverity;
908 var error = info.toAnalysisError();
909 var severity = error.errorCode.errorSeverity;
910 if (severity == ErrorSeverity.ERROR) _failure = true; 990 if (severity == ErrorSeverity.ERROR) _failure = true;
911 if (severity != ErrorSeverity.INFO || _options.strongModeHints) { 991 if (severity != ErrorSeverity.INFO || _options.strongModeHints) {
992 int begin = node is AnnotatedNode
993 ? node.firstTokenAfterCommentAndMetadata.offset
994 : node.offset;
995 int length = node.end - begin;
996 var source = (node.root as CompilationUnit).element.source;
997 var error =
998 new AnalysisError(source, begin, length, errorCode, arguments);
912 reporter.onError(error); 999 reporter.onError(error);
913 } 1000 }
1001 }
1002 }
914 1003
915 if (info is CoercionInfo) { 1004 bool isKnownFunction(Expression expression) {
916 // TODO(jmesserly): if we're run again on the same AST, we'll produce the 1005 Element element = null;
917 // same annotations. This should be harmless. This might go away once 1006 if (expression is FunctionExpression) {
918 // CodeChecker is integrated better with analyzer, as it will know that 1007 return true;
919 // checking has already been performed. 1008 } else if (expression is PropertyAccess) {
920 // assert(CoercionInfo.get(info.node) == null); 1009 element = expression.propertyName.staticElement;
921 CoercionInfo.set(info.node, info); 1010 } else if (expression is Identifier) {
922 } 1011 element = expression.staticElement;
923 } 1012 }
1013 // First class functions and static methods, where we know the original
1014 // declaration, will have an exact type, so we know a downcast will fail.
1015 return element is FunctionElement ||
1016 element is MethodElement && element.isStatic;
924 } 1017 }
925 1018
926 /// Checks for overriding declarations of fields and methods. This is used to 1019 /// Checks for overriding declarations of fields and methods. This is used to
927 /// check overrides between classes and superclasses, interfaces, and mixin 1020 /// check overrides between classes and superclasses, interfaces, and mixin
928 /// applications. 1021 /// applications.
929 class _OverrideChecker { 1022 class _OverrideChecker {
930 bool _failure = false;
931 final StrongTypeSystemImpl rules; 1023 final StrongTypeSystemImpl rules;
932 final TypeProvider _typeProvider; 1024 final TypeProvider _typeProvider;
933 final AnalysisErrorListener _reporter; 1025 final CodeChecker _checker;
934 1026
935 _OverrideChecker(this._typeProvider, this.rules, this._reporter); 1027 _OverrideChecker(CodeChecker checker)
1028 : _checker = checker,
1029 rules = checker.rules,
1030 _typeProvider = checker.typeProvider;
936 1031
937 void check(ClassDeclaration node) { 1032 void check(ClassDeclaration node) {
938 if (node.element.type.isObject) return; 1033 if (node.element.type.isObject) return;
939 _checkSuperOverrides(node); 1034 _checkSuperOverrides(node);
940 _checkMixinApplicationOverrides(node); 1035 _checkMixinApplicationOverrides(node);
941 _checkAllInterfaceOverrides(node); 1036 _checkAllInterfaceOverrides(node);
942 } 1037 }
943 1038
944 /// Checks that implementations correctly override all reachable interfaces. 1039 /// Checks that implementations correctly override all reachable interfaces.
945 /// In particular, we need to check these overrides for the definitions in 1040 /// In particular, we need to check these overrides for the definitions in
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1189 FunctionType subType = _elementType(element); 1284 FunctionType subType = _elementType(element);
1190 // TODO(vsm): Test for generic 1285 // TODO(vsm): Test for generic
1191 FunctionType baseType = _getMemberType(type, element); 1286 FunctionType baseType = _getMemberType(type, element);
1192 if (baseType == null) return false; 1287 if (baseType == null) return false;
1193 1288
1194 if (isSubclass && element is PropertyAccessorElement) { 1289 if (isSubclass && element is PropertyAccessorElement) {
1195 // Disallow any overriding if the base class defines this member 1290 // Disallow any overriding if the base class defines this member
1196 // as a field. We effectively treat fields as final / non-virtual. 1291 // as a field. We effectively treat fields as final / non-virtual.
1197 PropertyInducingElement field = _getMemberField(type, element); 1292 PropertyInducingElement field = _getMemberField(type, element);
1198 if (field != null) { 1293 if (field != null) {
1199 _recordMessage(new InvalidFieldOverride( 1294 _checker._recordMessage(
1200 errorLocation, element, type, subType, baseType)); 1295 errorLocation, StrongModeCode.INVALID_FIELD_OVERRIDE, [
1296 element.enclosingElement.name,
1297 element.name,
1298 subType,
1299 type,
1300 baseType
1301 ]);
1201 } 1302 }
1202 } 1303 }
1203 FunctionType concreteSubType = subType; 1304 FunctionType concreteSubType = subType;
1204 FunctionType concreteBaseType = baseType; 1305 FunctionType concreteBaseType = baseType;
1205 if (element is MethodElement) { 1306 if (element is MethodElement) {
1206 if (concreteSubType.typeFormals.isNotEmpty) { 1307 if (concreteSubType.typeFormals.isNotEmpty) {
1207 if (concreteBaseType.typeFormals.isEmpty) { 1308 if (concreteBaseType.typeFormals.isEmpty) {
1208 concreteSubType = rules.instantiateToBounds(concreteSubType); 1309 concreteSubType = rules.instantiateToBounds(concreteSubType);
1209 } 1310 }
1210 } 1311 }
1211 concreteSubType = 1312 concreteSubType =
1212 rules.typeToConcreteType(_typeProvider, concreteSubType); 1313 rules.typeToConcreteType(_typeProvider, concreteSubType);
1213 concreteBaseType = 1314 concreteBaseType =
1214 rules.typeToConcreteType(_typeProvider, concreteBaseType); 1315 rules.typeToConcreteType(_typeProvider, concreteBaseType);
1215 } 1316 }
1216 if (!rules.isSubtypeOf(concreteSubType, concreteBaseType)) { 1317 if (!rules.isSubtypeOf(concreteSubType, concreteBaseType)) {
1217 // See whether non-subtype cases fit one of our common patterns: 1318 // See whether non-subtype cases fit one of our common patterns:
1218 // 1319 //
1219 // Common pattern 1: Inferable return type (on getters and methods) 1320 // Common pattern 1: Inferable return type (on getters and methods)
1220 // class A { 1321 // class A {
1221 // int get foo => ...; 1322 // int get foo => ...;
1222 // String toString() { ... } 1323 // String toString() { ... }
1223 // } 1324 // }
1224 // class B extends A { 1325 // class B extends A {
1225 // get foo => e; // no type specified. 1326 // get foo => e; // no type specified.
1226 // toString() { ... } // no return type specified. 1327 // toString() { ... } // no return type specified.
1227 // } 1328 // }
1228 _recordMessage(new InvalidMethodOverride( 1329
1229 errorLocation, element, type, subType, baseType)); 1330 ErrorCode errorCode;
1331 if (errorLocation is ExtendsClause) {
1332 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_BASE;
1333 } else if (errorLocation.parent is WithClause) {
1334 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_MIXIN;
1335 } else {
1336 errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE;
1337 }
1338
1339 _checker._recordMessage(errorLocation, errorCode, [
1340 element.enclosingElement.name,
1341 element.name,
1342 subType,
1343 type,
1344 baseType
1345 ]);
1230 } 1346 }
1231 return true; 1347 return true;
1232 } 1348 }
1233 1349
1234 /// Check overrides between a class and its superclasses and mixins. For 1350 /// Check overrides between a class and its superclasses and mixins. For
1235 /// example, in: 1351 /// example, in:
1236 /// 1352 ///
1237 /// A extends B with E, F 1353 /// A extends B with E, F
1238 /// 1354 ///
1239 /// we check A against B, B super classes, E, and F. 1355 /// we check A against B, B super classes, E, and F.
(...skipping 18 matching lines...) Expand all
1258 var current = node.element.type; 1374 var current = node.element.type;
1259 var visited = new Set<InterfaceType>(); 1375 var visited = new Set<InterfaceType>();
1260 do { 1376 do {
1261 visited.add(current); 1377 visited.add(current);
1262 current.mixins.reversed.forEach( 1378 current.mixins.reversed.forEach(
1263 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); 1379 (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
1264 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); 1380 _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
1265 current = current.superclass; 1381 current = current.superclass;
1266 } while (!current.isObject && !visited.contains(current)); 1382 } while (!current.isObject && !visited.contains(current));
1267 } 1383 }
1268
1269 void _recordMessage(StaticInfo info) {
1270 if (info == null) return;
1271 var error = info.toAnalysisError();
1272 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true;
1273 _reporter.onError(error);
1274 }
1275 } 1384 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/task/strong/ast_properties.dart ('k') | pkg/analyzer/lib/src/task/strong/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698