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

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

Issue 2054443002: Add analysis option that will be used to fix #26583 (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/resolver.dart' show TypeProvider; 17 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
17 import 'package:analyzer/src/generated/type_system.dart'; 18 import 'package:analyzer/src/generated/type_system.dart';
18 19
19 import 'info.dart'; 20 import 'info.dart';
20 21
21 DartType _elementType(Element e) { 22 DartType _elementType(Element e) {
22 if (e == null) { 23 if (e == null) {
23 // Malformed code - just return dynamic. 24 // Malformed code - just return dynamic.
24 return DynamicTypeImpl.instance; 25 return DynamicTypeImpl.instance;
25 } 26 }
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 } 95 }
95 96
96 typedef FunctionType _MemberTypeGetter(InterfaceType type); 97 typedef FunctionType _MemberTypeGetter(InterfaceType type);
97 98
98 /// Checks the body of functions and properties. 99 /// Checks the body of functions and properties.
99 class CodeChecker extends RecursiveAstVisitor { 100 class CodeChecker extends RecursiveAstVisitor {
100 final StrongTypeSystemImpl rules; 101 final StrongTypeSystemImpl rules;
101 final TypeProvider typeProvider; 102 final TypeProvider typeProvider;
102 final AnalysisErrorListener reporter; 103 final AnalysisErrorListener reporter;
103 final _OverrideChecker _overrideChecker; 104 final _OverrideChecker _overrideChecker;
104 final bool _hints; 105 final AnalysisOptionsImpl _options;
105 106
106 bool _failure = false; 107 bool _failure = false;
108
107 CodeChecker(TypeProvider typeProvider, StrongTypeSystemImpl rules, 109 CodeChecker(TypeProvider typeProvider, StrongTypeSystemImpl rules,
108 AnalysisErrorListener reporter, 110 AnalysisErrorListener reporter, this._options)
109 {bool hints: false})
110 : typeProvider = typeProvider, 111 : typeProvider = typeProvider,
111 rules = rules, 112 rules = rules,
112 reporter = reporter, 113 reporter = reporter,
113 _hints = hints,
114 _overrideChecker = new _OverrideChecker(typeProvider, rules, reporter); 114 _overrideChecker = new _OverrideChecker(typeProvider, rules, reporter);
115 115
116 bool get failure => _failure || _overrideChecker._failure; 116 bool get failure => _failure || _overrideChecker._failure;
117 117
118 void checkArgument(Expression arg, DartType expectedType) { 118 void checkArgument(Expression arg, DartType expectedType) {
119 // Preserve named argument structure, so their immediate parent is the 119 // Preserve named argument structure, so their immediate parent is the
120 // method invocation. 120 // method invocation.
121 Expression baseExpression = arg is NamedExpression ? arg.expression : arg; 121 Expression baseExpression = arg is NamedExpression ? arg.expression : arg;
122 checkAssignment(baseExpression, expectedType); 122 checkAssignment(baseExpression, expectedType);
123 } 123 }
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 339
340 // If the sequence is not an Iterable (or Stream for await for) but is a 340 // 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 341 // 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. 342 // we'll do a separate cast of the dynamic element to the variable's type.
343 if (elementType == null) { 343 if (elementType == null) {
344 var sequenceType = 344 var sequenceType =
345 sequenceInterface.instantiate([DynamicTypeImpl.instance]); 345 sequenceInterface.instantiate([DynamicTypeImpl.instance]);
346 346
347 if (rules.isSubtypeOf(sequenceType, iterableType)) { 347 if (rules.isSubtypeOf(sequenceType, iterableType)) {
348 _recordMessage(DownCast.create( 348 _recordMessage(DownCast.create(
349 rules, node.iterable, iterableType, sequenceType)); 349 rules, node.iterable, iterableType, sequenceType, _options));
350 elementType = DynamicTypeImpl.instance; 350 elementType = DynamicTypeImpl.instance;
351 } 351 }
352 } 352 }
353 353
354 // If the sequence doesn't implement the interface at all, [ErrorVerifier] 354 // If the sequence doesn't implement the interface at all, [ErrorVerifier]
355 // will report the error, so ignore it here. 355 // will report the error, so ignore it here.
356 if (elementType != null) { 356 if (elementType != null) {
357 // Insert a cast from the sequence's element type to the loop variable's 357 // Insert a cast from the sequence's element type to the loop variable's
358 // if needed. 358 // if needed.
359 _checkDowncast(loopVariable, _getStaticType(loopVariable), 359 _checkDowncast(loopVariable, _getStaticType(loopVariable),
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 var returnType = rules.refineBinaryExpressionType( 625 var returnType = rules.refineBinaryExpressionType(
626 typeProvider, lhsType, op, rhsType, functionType.returnType); 626 typeProvider, lhsType, op, rhsType, functionType.returnType);
627 627
628 if (!rules.isSubtypeOf(returnType, lhsType)) { 628 if (!rules.isSubtypeOf(returnType, lhsType)) {
629 final numType = typeProvider.numType; 629 final numType = typeProvider.numType;
630 // Try to fix up the numerical case if possible. 630 // Try to fix up the numerical case if possible.
631 if (rules.isSubtypeOf(lhsType, numType) && 631 if (rules.isSubtypeOf(lhsType, numType) &&
632 rules.isSubtypeOf(lhsType, rhsType)) { 632 rules.isSubtypeOf(lhsType, rhsType)) {
633 // This is also slightly different from spec, but allows us to keep 633 // This is also slightly different from spec, but allows us to keep
634 // compound operators in the int += num and num += dynamic cases. 634 // compound operators in the int += num and num += dynamic cases.
635 staticInfo = 635 staticInfo = DownCast.create(
636 DownCast.create(rules, expr.rightHandSide, rhsType, lhsType); 636 rules, expr.rightHandSide, rhsType, lhsType, _options);
637 rhsType = lhsType; 637 rhsType = lhsType;
638 } else { 638 } else {
639 staticInfo = new StaticTypeError(rules, expr, lhsType); 639 staticInfo = new StaticTypeError(expr, lhsType);
640 } 640 }
641 _recordMessage(staticInfo); 641 _recordMessage(staticInfo);
642 } 642 }
643 643
644 // Check the rhs type 644 // Check the rhs type
645 if (staticInfo is! CoercionInfo) { 645 if (staticInfo is! CoercionInfo) {
646 var paramType = paramTypes.first; 646 var paramType = paramTypes.first;
647 _checkDowncast(expr.rightHandSide, paramType); 647 _checkDowncast(expr.rightHandSide, paramType);
648 } 648 }
649 } 649 }
(...skipping 22 matching lines...) Expand all
672 // Note: a function type is never assignable to a class per the Dart 672 // 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 673 // spec - even if it has a compatible call method. We disallow as
674 // well for consistency. 674 // well for consistency.
675 if ((from is FunctionType && rules.getCallMethodType(to) != null) || 675 if ((from is FunctionType && rules.getCallMethodType(to) != null) ||
676 (to is FunctionType && rules.getCallMethodType(from) != null)) { 676 (to is FunctionType && rules.getCallMethodType(from) != null)) {
677 return; 677 return;
678 } 678 }
679 679
680 // Downcast if toT <: fromT 680 // Downcast if toT <: fromT
681 if (rules.isSubtypeOf(to, from)) { 681 if (rules.isSubtypeOf(to, from)) {
682 _recordMessage(DownCast.create(rules, expr, from, to)); 682 _recordMessage(DownCast.create(rules, expr, from, to, _options));
683 return; 683 return;
684 } 684 }
685 685
686 // TODO(vsm): Once we have generic methods, we should delete this 686 // TODO(vsm): Once we have generic methods, we should delete this
687 // workaround. These sideways casts are always ones we warn about 687 // workaround. These sideways casts are always ones we warn about
688 // - i.e., we think they are likely to fail at runtime. 688 // - i.e., we think they are likely to fail at runtime.
689 // ------- 689 // -------
690 // Downcast if toT <===> fromT 690 // Downcast if toT <===> fromT
691 // The intention here is to allow casts that are sideways in the restricted 691 // 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 692 // type system, but allowed in the regular dart type system, since these
693 // are likely to succeed. The canonical example is List<dynamic> and 693 // are likely to succeed. The canonical example is List<dynamic> and
694 // Iterable<T> for some concrete T (e.g. Object). These are unrelated 694 // Iterable<T> for some concrete T (e.g. Object). These are unrelated
695 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. 695 // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
696 if (from.isAssignableTo(to)) { 696 if (from.isAssignableTo(to)) {
697 _recordMessage(DownCast.create(rules, expr, from, to)); 697 _recordMessage(DownCast.create(rules, expr, from, to, _options));
698 } 698 }
699 } 699 }
700 700
701 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { 701 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
702 if ((_isDynamicTarget(target) || field.staticElement == null) && 702 if ((_isDynamicTarget(target) || field.staticElement == null) &&
703 !_isObjectProperty(target, field)) { 703 !_isObjectProperty(target, field)) {
704 _recordDynamicInvoke(node, target); 704 _recordDynamicInvoke(node, target);
705 } 705 }
706 node.visitChildren(this); 706 node.visitChildren(this);
707 } 707 }
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 bool _isObjectMethod(Expression target, SimpleIdentifier id) { 887 bool _isObjectMethod(Expression target, SimpleIdentifier id) {
888 MethodElement element = typeProvider.objectType.element.getMethod(id.name); 888 MethodElement element = typeProvider.objectType.element.getMethod(id.name);
889 return (element != null && !element.isStatic); 889 return (element != null && !element.isStatic);
890 } 890 }
891 891
892 bool _isObjectProperty(Expression target, SimpleIdentifier id) { 892 bool _isObjectProperty(Expression target, SimpleIdentifier id) {
893 return _isObjectGetter(target, id) || _isObjectMethod(target, id); 893 return _isObjectGetter(target, id) || _isObjectMethod(target, id);
894 } 894 }
895 895
896 void _recordDynamicInvoke(AstNode node, AstNode target) { 896 void _recordDynamicInvoke(AstNode node, AstNode target) {
897 if (_hints) { 897 if (_options.strongModeHints) {
898 reporter.onError(new DynamicInvoke(rules, node).toAnalysisError()); 898 reporter.onError(new DynamicInvoke(node).toAnalysisError());
899 } 899 }
900 // TODO(jmesserly): we may eventually want to record if the whole operation 900 // 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 901 // (node) was dynamic, rather than the target, but this is an easier fit
902 // with what we used to do. 902 // with what we used to do.
903 DynamicInvoke.set(target, true); 903 DynamicInvoke.set(target, true);
904 } 904 }
905 905
906 void _recordMessage(StaticInfo info) { 906 void _recordMessage(StaticInfo info) {
907 if (info == null) return; 907 if (info == null) return;
908 var error = info.toAnalysisError(); 908 var error = info.toAnalysisError();
909 var severity = error.errorCode.errorSeverity; 909 var severity = error.errorCode.errorSeverity;
910 if (severity == ErrorSeverity.ERROR) _failure = true; 910 if (severity == ErrorSeverity.ERROR) _failure = true;
911 if (severity != ErrorSeverity.INFO || _hints) { 911 if (severity != ErrorSeverity.INFO || _options.strongModeHints) {
912 reporter.onError(error); 912 reporter.onError(error);
913 } 913 }
914 914
915 if (info is CoercionInfo) { 915 if (info is CoercionInfo) {
916 // TODO(jmesserly): if we're run again on the same AST, we'll produce the 916 // TODO(jmesserly): if we're run again on the same AST, we'll produce the
917 // same annotations. This should be harmless. This might go away once 917 // same annotations. This should be harmless. This might go away once
918 // CodeChecker is integrated better with analyzer, as it will know that 918 // CodeChecker is integrated better with analyzer, as it will know that
919 // checking has already been performed. 919 // checking has already been performed.
920 // assert(CoercionInfo.get(info.node) == null); 920 // assert(CoercionInfo.get(info.node) == null);
921 CoercionInfo.set(info.node, info); 921 CoercionInfo.set(info.node, info);
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
1266 } while (!current.isObject && !visited.contains(current)); 1266 } while (!current.isObject && !visited.contains(current));
1267 } 1267 }
1268 1268
1269 void _recordMessage(StaticInfo info) { 1269 void _recordMessage(StaticInfo info) {
1270 if (info == null) return; 1270 if (info == null) return;
1271 var error = info.toAnalysisError(); 1271 var error = info.toAnalysisError();
1272 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; 1272 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true;
1273 _reporter.onError(error); 1273 _reporter.onError(error);
1274 } 1274 }
1275 } 1275 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698