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

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

Issue 2551023005: Prepare for decoupling analyzer ASTs from element model. (Closed)
Patch Set: Created 4 years 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/resolution_accessors.dart';
11 import 'package:analyzer/dart/ast/token.dart' show TokenType; 12 import 'package:analyzer/dart/ast/token.dart' show TokenType;
12 import 'package:analyzer/dart/ast/token.dart'; 13 import 'package:analyzer/dart/ast/token.dart';
13 import 'package:analyzer/dart/ast/visitor.dart'; 14 import 'package:analyzer/dart/ast/visitor.dart';
14 import 'package:analyzer/dart/element/element.dart'; 15 import 'package:analyzer/dart/element/element.dart';
15 import 'package:analyzer/dart/element/type.dart'; 16 import 'package:analyzer/dart/element/type.dart';
16 import 'package:analyzer/src/dart/element/type.dart'; 17 import 'package:analyzer/src/dart/element/type.dart';
17 import 'package:analyzer/src/error/codes.dart' show StrongModeCode; 18 import 'package:analyzer/src/error/codes.dart' show StrongModeCode;
18 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; 19 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; 20 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
20 import 'package:analyzer/src/generated/type_system.dart'; 21 import 'package:analyzer/src/generated/type_system.dart';
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 } 596 }
596 597
597 @override 598 @override
598 void visitPropertyAccess(PropertyAccess node) { 599 void visitPropertyAccess(PropertyAccess node) {
599 _checkFieldAccess(node, node.realTarget, node.propertyName); 600 _checkFieldAccess(node, node.realTarget, node.propertyName);
600 } 601 }
601 602
602 @override 603 @override
603 void visitRedirectingConstructorInvocation( 604 void visitRedirectingConstructorInvocation(
604 RedirectingConstructorInvocation node) { 605 RedirectingConstructorInvocation node) {
605 var type = node.staticElement?.type; 606 var type = staticElementForConstructorReference(node)?.type;
606 // TODO(leafp): There's a TODO in visitRedirectingConstructorInvocation 607 // TODO(leafp): There's a TODO in visitRedirectingConstructorInvocation
607 // in the element_resolver to handle the case that the element is null 608 // in the element_resolver to handle the case that the element is null
608 // and emit an error. In the meantime, just be defensive here. 609 // and emit an error. In the meantime, just be defensive here.
609 if (type != null) { 610 if (type != null) {
610 checkArgumentList(node.argumentList, type); 611 checkArgumentList(node.argumentList, type);
611 } 612 }
612 node.visitChildren(this); 613 node.visitChildren(this);
613 } 614 }
614 615
615 @override 616 @override
616 void visitReturnStatement(ReturnStatement node) { 617 void visitReturnStatement(ReturnStatement node) {
617 _checkReturnOrYield(node.expression, node); 618 _checkReturnOrYield(node.expression, node);
618 node.visitChildren(this); 619 node.visitChildren(this);
619 } 620 }
620 621
621 @override 622 @override
622 void visitSuperConstructorInvocation(SuperConstructorInvocation node) { 623 void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
623 var element = node.staticElement; 624 var element = node.staticElement;
624 if (element != null) { 625 if (element != null) {
625 var type = node.staticElement.type; 626 var type = staticElementForConstructorReference(node).type;
626 checkArgumentList(node.argumentList, type); 627 checkArgumentList(node.argumentList, type);
627 } 628 }
628 node.visitChildren(this); 629 node.visitChildren(this);
629 } 630 }
630 631
631 @override 632 @override
632 void visitSwitchStatement(SwitchStatement node) { 633 void visitSwitchStatement(SwitchStatement node) {
633 // SwitchStatement defines a boolean conversion to check the result of the 634 // SwitchStatement defines a boolean conversion to check the result of the
634 // case value == the switch value, but in dev_compiler we require a boolean 635 // case value == the switch value, but in dev_compiler we require a boolean
635 // return type from an overridden == operator (because Object.==), so 636 // return type from an overridden == operator (because Object.==), so
636 // checking in SwitchStatement shouldn't be necessary. 637 // checking in SwitchStatement shouldn't be necessary.
637 node.visitChildren(this); 638 node.visitChildren(this);
638 } 639 }
639 640
640 @override 641 @override
641 Object visitVariableDeclaration(VariableDeclaration node) { 642 Object visitVariableDeclaration(VariableDeclaration node) {
643 VariableElement variableElement =
644 node == null ? null : elementForVariableDeclaration(node);
642 if (!node.isConst && 645 if (!node.isConst &&
643 !node.isFinal && 646 !node.isFinal &&
644 node.initializer == null && 647 node.initializer == null &&
645 rules.isNonNullableType(node?.element?.type)) { 648 rules.isNonNullableType(variableElement?.type)) {
646 _recordMessage( 649 _recordMessage(
647 node, 650 node,
648 StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED, 651 StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED,
649 [node.name, node?.element?.type]); 652 [node.name, variableElement?.type]);
650 } 653 }
651 return super.visitVariableDeclaration(node); 654 return super.visitVariableDeclaration(node);
652 } 655 }
653 656
654 @override 657 @override
655 void visitVariableDeclarationList(VariableDeclarationList node) { 658 void visitVariableDeclarationList(VariableDeclarationList node) {
656 TypeName type = node.type; 659 TypeName type = node.type;
657 if (type == null) { 660 if (type == null) {
658 // No checks are needed when the type is var. Although internally the 661 // No checks are needed when the type is var. Although internally the
659 // typing rules may have inferred a more precise type for the variable 662 // typing rules may have inferred a more precise type for the variable
(...skipping 17 matching lines...) Expand all
677 680
678 @override 681 @override
679 void visitYieldStatement(YieldStatement node) { 682 void visitYieldStatement(YieldStatement node) {
680 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); 683 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null);
681 node.visitChildren(this); 684 node.visitChildren(this);
682 } 685 }
683 686
684 void _checkCompoundAssignment(AssignmentExpression expr) { 687 void _checkCompoundAssignment(AssignmentExpression expr) {
685 var op = expr.operator.type; 688 var op = expr.operator.type;
686 assert(op.isAssignmentOperator && op != TokenType.EQ); 689 assert(op.isAssignmentOperator && op != TokenType.EQ);
687 var methodElement = expr.staticElement; 690 var methodElement = staticElementForMethodReference(expr);
688 if (methodElement == null) { 691 if (methodElement == null) {
689 // Dynamic invocation. 692 // Dynamic invocation.
690 _recordDynamicInvoke(expr, expr.leftHandSide); 693 _recordDynamicInvoke(expr, expr.leftHandSide);
691 } else { 694 } else {
692 // Sanity check the operator. 695 // Sanity check the operator.
693 assert(methodElement.isOperator); 696 assert(methodElement.isOperator);
694 var functionType = methodElement.type; 697 var functionType = methodElement.type;
695 var paramTypes = functionType.normalParameterTypes; 698 var paramTypes = functionType.normalParameterTypes;
696 assert(paramTypes.length == 1); 699 assert(paramTypes.length == 1);
697 assert(functionType.namedParameterTypes.isEmpty); 700 assert(functionType.namedParameterTypes.isEmpty);
(...skipping 14 matching lines...) Expand all
712 // back to it. So these two implicit casts are equivalent: 715 // back to it. So these two implicit casts are equivalent:
713 // 716 //
714 // y = /*implicit cast*/(y + 42); 717 // y = /*implicit cast*/(y + 42);
715 // /*implicit assignment cast*/y += 42; 718 // /*implicit assignment cast*/y += 42;
716 // 719 //
717 _checkImplicitCast(expr.leftHandSide, lhsType, 720 _checkImplicitCast(expr.leftHandSide, lhsType,
718 from: returnType, opAssign: true); 721 from: returnType, opAssign: true);
719 } 722 }
720 } 723 }
721 724
722 /// Returns true if we need an implicit cast of [expr] from [from] type to
723 /// [to] type, otherwise returns false.
724 ///
725 /// If [from] is omitted, uses the static type of [expr].
726 bool _needsImplicitCast(Expression expr, DartType to, {DartType from}) {
727 from ??= _getDefiniteType(expr);
728
729 if (!_checkNonNullAssignment(expr, to, from)) return false;
730
731 // We can use anything as void.
732 if (to.isVoid) return false;
733
734 // fromT <: toT, no coercion needed.
735 if (rules.isSubtypeOf(from, to)) return false;
736
737 // Note: a function type is never assignable to a class per the Dart
738 // spec - even if it has a compatible call method. We disallow as
739 // well for consistency.
740 if (from is FunctionType && rules.getCallMethodType(to) != null) {
741 return false;
742 }
743
744 // Downcast if toT <: fromT
745 if (rules.isSubtypeOf(to, from)) {
746 return true;
747 }
748
749 // Anything else is an illegal sideways cast.
750 // However, these will have been reported already in error_verifier, so we
751 // don't need to report them again.
752 return false;
753 }
754
755 /// Checks if an implicit cast of [expr] from [from] type to [to] type is
756 /// needed, and if so records it.
757 ///
758 /// If [from] is omitted, uses the static type of [expr].
759 ///
760 /// If [expr] does not require an implicit cast because it is not related to
761 /// [to] or is already a subtype of it, does nothing.
762 void _checkImplicitCast(Expression expr, DartType to,
763 {DartType from, bool opAssign: false}) {
764 from ??= _getDefiniteType(expr);
765
766 if (_needsImplicitCast(expr, to, from: from)) {
767 _recordImplicitCast(expr, to, from: from, opAssign: opAssign);
768 }
769 }
770
771 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { 725 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
772 if (field.staticElement == null && 726 if (field.staticElement == null &&
773 !typeProvider.isObjectMember(field.name)) { 727 !typeProvider.isObjectMember(field.name)) {
774 _recordDynamicInvoke(node, target); 728 _recordDynamicInvoke(node, target);
775 } 729 }
776 node.visitChildren(this); 730 node.visitChildren(this);
777 } 731 }
778 732
779 /** 733 /**
780 * Check if the closure [node] is unsafe due to dartbug.com/26947. If so, 734 * Check if the closure [node] is unsafe due to dartbug.com/26947. If so,
781 * issue a warning. 735 * issue a warning.
782 * 736 *
783 * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed. 737 * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed.
784 */ 738 */
785 void _checkForUnsafeBlockClosureInference(FunctionExpression node) { 739 void _checkForUnsafeBlockClosureInference(FunctionExpression node) {
786 if (node.body is! BlockFunctionBody) { 740 if (node.body is! BlockFunctionBody) {
787 return; 741 return;
788 } 742 }
789 if (node.element.returnType.isDynamic) { 743 if (elementForFunctionExpression(node).returnType.isDynamic) {
790 return; 744 return;
791 } 745 }
792 // Find the enclosing variable declaration whose inferred type might depend 746 // Find the enclosing variable declaration whose inferred type might depend
793 // on the inferred return type of the block closure (if any). 747 // on the inferred return type of the block closure (if any).
794 AstNode prevAncestor = node; 748 AstNode prevAncestor = node;
795 AstNode ancestor = node.parent; 749 AstNode ancestor = node.parent;
796 while (ancestor != null && ancestor is! VariableDeclaration) { 750 while (ancestor != null && ancestor is! VariableDeclaration) {
797 if (ancestor is BlockFunctionBody) { 751 if (ancestor is BlockFunctionBody) {
798 // node is inside another block function body; if that block 752 // node is inside another block function body; if that block
799 // function body is unsafe, we've already warned about it. 753 // function body is unsafe, we've already warned about it.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
868 return; 822 return;
869 } 823 }
870 if (declElement.enclosingElement is ExecutableElement) { 824 if (declElement.enclosingElement is ExecutableElement) {
871 // Variable declaration is inside a function or method, so it's safe. 825 // Variable declaration is inside a function or method, so it's safe.
872 return; 826 return;
873 } 827 }
874 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, 828 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE,
875 [declElement.name]); 829 [declElement.name]);
876 } 830 }
877 831
832 /// Checks if an implicit cast of [expr] from [from] type to [to] type is
833 /// needed, and if so records it.
834 ///
835 /// If [from] is omitted, uses the static type of [expr].
836 ///
837 /// If [expr] does not require an implicit cast because it is not related to
838 /// [to] or is already a subtype of it, does nothing.
839 void _checkImplicitCast(Expression expr, DartType to,
840 {DartType from, bool opAssign: false}) {
841 from ??= _getDefiniteType(expr);
842
843 if (_needsImplicitCast(expr, to, from: from)) {
844 _recordImplicitCast(expr, to, from: from, opAssign: opAssign);
845 }
846 }
847
878 /// Checks if the assignment is valid with respect to non-nullable types. 848 /// Checks if the assignment is valid with respect to non-nullable types.
879 /// Returns `false` if a nullable expression is assigned to a variable of 849 /// Returns `false` if a nullable expression is assigned to a variable of
880 /// non-nullable type and `true` otherwise. 850 /// non-nullable type and `true` otherwise.
881 bool _checkNonNullAssignment( 851 bool _checkNonNullAssignment(
882 Expression expression, DartType to, DartType from) { 852 Expression expression, DartType to, DartType from) {
883 if (rules.isNonNullableType(to) && rules.isNullableType(from)) { 853 if (rules.isNonNullableType(to) && rules.isNullableType(from)) {
884 _recordMessage( 854 _recordMessage(
885 expression, StaticTypeWarningCode.INVALID_ASSIGNMENT, [from, to]); 855 expression, StaticTypeWarningCode.INVALID_ASSIGNMENT, [from, to]);
886 return false; 856 return false;
887 } 857 }
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
1027 // Dynamic as the parameter type is treated as bottom. A function with 997 // Dynamic as the parameter type is treated as bottom. A function with
1028 // a dynamic parameter type requires a dynamic call in general. 998 // a dynamic parameter type requires a dynamic call in general.
1029 // However, as an optimization, if we have an original definition, we know 999 // However, as an optimization, if we have an original definition, we know
1030 // dynamic is reified as Object - in this case a regular call is fine. 1000 // dynamic is reified as Object - in this case a regular call is fine.
1031 if (_hasStrictArrow(call.function)) { 1001 if (_hasStrictArrow(call.function)) {
1032 return false; 1002 return false;
1033 } 1003 }
1034 return rules.anyParameterType(ft, (pt) => pt.isDynamic); 1004 return rules.anyParameterType(ft, (pt) => pt.isDynamic);
1035 } 1005 }
1036 1006
1007 /// Returns true if we need an implicit cast of [expr] from [from] type to
1008 /// [to] type, otherwise returns false.
1009 ///
1010 /// If [from] is omitted, uses the static type of [expr].
1011 bool _needsImplicitCast(Expression expr, DartType to, {DartType from}) {
1012 from ??= _getDefiniteType(expr);
1013
1014 if (!_checkNonNullAssignment(expr, to, from)) return false;
1015
1016 // We can use anything as void.
1017 if (to.isVoid) return false;
1018
1019 // fromT <: toT, no coercion needed.
1020 if (rules.isSubtypeOf(from, to)) return false;
1021
1022 // Note: a function type is never assignable to a class per the Dart
1023 // spec - even if it has a compatible call method. We disallow as
1024 // well for consistency.
1025 if (from is FunctionType && rules.getCallMethodType(to) != null) {
1026 return false;
1027 }
1028
1029 // Downcast if toT <: fromT
1030 if (rules.isSubtypeOf(to, from)) {
1031 return true;
1032 }
1033
1034 // Anything else is an illegal sideways cast.
1035 // However, these will have been reported already in error_verifier, so we
1036 // don't need to report them again.
1037 return false;
1038 }
1039
1037 void _recordDynamicInvoke(AstNode node, Expression target) { 1040 void _recordDynamicInvoke(AstNode node, Expression target) {
1038 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]); 1041 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]);
1039 // TODO(jmesserly): we may eventually want to record if the whole operation 1042 // TODO(jmesserly): we may eventually want to record if the whole operation
1040 // (node) was dynamic, rather than the target, but this is an easier fit 1043 // (node) was dynamic, rather than the target, but this is an easier fit
1041 // with what we used to do. 1044 // with what we used to do.
1042 if (target != null) setIsDynamicInvoke(target, true); 1045 if (target != null) setIsDynamicInvoke(target, true);
1043 } 1046 }
1044 1047
1045 /// Records an implicit cast for the [expr] from [from] to [to]. 1048 /// Records an implicit cast for the [expr] from [from] to [to].
1046 /// 1049 ///
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1134 } 1137 }
1135 1138
1136 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) { 1139 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) {
1137 var severity = errorCode.errorSeverity; 1140 var severity = errorCode.errorSeverity;
1138 if (severity == ErrorSeverity.ERROR) _failure = true; 1141 if (severity == ErrorSeverity.ERROR) _failure = true;
1139 if (severity != ErrorSeverity.INFO || _options.strongModeHints) { 1142 if (severity != ErrorSeverity.INFO || _options.strongModeHints) {
1140 int begin = node is AnnotatedNode 1143 int begin = node is AnnotatedNode
1141 ? node.firstTokenAfterCommentAndMetadata.offset 1144 ? node.firstTokenAfterCommentAndMetadata.offset
1142 : node.offset; 1145 : node.offset;
1143 int length = node.end - begin; 1146 int length = node.end - begin;
1144 var source = (node.root as CompilationUnit).element.source; 1147 var source =
1148 elementForCompilationUnit(node.root as CompilationUnit).source;
1145 var error = 1149 var error =
1146 new AnalysisError(source, begin, length, errorCode, arguments); 1150 new AnalysisError(source, begin, length, errorCode, arguments);
1147 reporter.onError(error); 1151 reporter.onError(error);
1148 } 1152 }
1149 } 1153 }
1150 } 1154 }
1151 1155
1152 /// Checks for overriding declarations of fields and methods. This is used to 1156 /// Checks for overriding declarations of fields and methods. This is used to
1153 /// check overrides between classes and superclasses, interfaces, and mixin 1157 /// check overrides between classes and superclasses, interfaces, and mixin
1154 /// applications. 1158 /// applications.
1155 class _OverrideChecker { 1159 class _OverrideChecker {
1156 final StrongTypeSystemImpl rules; 1160 final StrongTypeSystemImpl rules;
1157 final CodeChecker _checker; 1161 final CodeChecker _checker;
1158 1162
1159 _OverrideChecker(CodeChecker checker) 1163 _OverrideChecker(CodeChecker checker)
1160 : _checker = checker, 1164 : _checker = checker,
1161 rules = checker.rules; 1165 rules = checker.rules;
1162 1166
1163 void check(ClassDeclaration node) { 1167 void check(ClassDeclaration node) {
1164 if (node.element.type.isObject) return; 1168 if (elementForClassDeclaration(node).type.isObject) return;
1165 _checkSuperOverrides(node); 1169 _checkSuperOverrides(node);
1166 _checkMixinApplicationOverrides(node); 1170 _checkMixinApplicationOverrides(node);
1167 _checkAllInterfaceOverrides(node); 1171 _checkAllInterfaceOverrides(node);
1168 } 1172 }
1169 1173
1170 /// Checks that implementations correctly override all reachable interfaces. 1174 /// Checks that implementations correctly override all reachable interfaces.
1171 /// In particular, we need to check these overrides for the definitions in 1175 /// In particular, we need to check these overrides for the definitions in
1172 /// the class itself and each its superclasses. If a superclass is not 1176 /// the class itself and each its superclasses. If a superclass is not
1173 /// abstract, then we can skip its transitive interfaces. For example, in: 1177 /// abstract, then we can skip its transitive interfaces. For example, in:
1174 /// 1178 ///
(...skipping 15 matching lines...) Expand all
1190 if (result.contains(interfaceType)) return; 1194 if (result.contains(interfaceType)) return;
1191 result.add(interfaceType); 1195 result.add(interfaceType);
1192 find(interfaceType.superclass, result); 1196 find(interfaceType.superclass, result);
1193 interfaceType.mixins.forEach((i) => find(i, result)); 1197 interfaceType.mixins.forEach((i) => find(i, result));
1194 interfaceType.interfaces.forEach((i) => find(i, result)); 1198 interfaceType.interfaces.forEach((i) => find(i, result));
1195 } 1199 }
1196 1200
1197 // Check all interfaces reachable from the `implements` clause in the 1201 // Check all interfaces reachable from the `implements` clause in the
1198 // current class against definitions here and in superclasses. 1202 // current class against definitions here and in superclasses.
1199 var localInterfaces = new Set<InterfaceType>(); 1203 var localInterfaces = new Set<InterfaceType>();
1200 var type = node.element.type; 1204 var type = elementForClassDeclaration(node).type;
1201 type.interfaces.forEach((i) => find(i, localInterfaces)); 1205 type.interfaces.forEach((i) => find(i, localInterfaces));
1202 _checkInterfacesOverrides(node, localInterfaces, seen, 1206 _checkInterfacesOverrides(node, localInterfaces, seen,
1203 includeParents: true); 1207 includeParents: true);
1204 1208
1205 // Check also how we override locally the interfaces from parent classes if 1209 // Check also how we override locally the interfaces from parent classes if
1206 // the parent class is abstract. Otherwise, these will be checked as 1210 // the parent class is abstract. Otherwise, these will be checked as
1207 // overrides on the concrete superclass. 1211 // overrides on the concrete superclass.
1208 var superInterfaces = new Set<InterfaceType>(); 1212 var superInterfaces = new Set<InterfaceType>();
1209 var parent = type.superclass; 1213 var parent = type.superclass;
1210 // TODO(sigmund): we don't seem to be reporting the analyzer error that a 1214 // TODO(sigmund): we don't seem to be reporting the analyzer error that a
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1247 found = true; 1251 found = true;
1248 } 1252 }
1249 if (found) { 1253 if (found) {
1250 seen.add(name); 1254 seen.add(name);
1251 } 1255 }
1252 } 1256 }
1253 } else if (member is MethodDeclaration) { 1257 } else if (member is MethodDeclaration) {
1254 if (member.isStatic) { 1258 if (member.isStatic) {
1255 continue; 1259 continue;
1256 } 1260 }
1257 var method = member.element; 1261 var method = elementForMethodDeclaration(member);
1258 if (seen.contains(method.name)) { 1262 if (seen.contains(method.name)) {
1259 continue; 1263 continue;
1260 } 1264 }
1261 if (_checkSingleOverride( 1265 if (_checkSingleOverride(
1262 method, baseType, member.name, member, isSubclass)) { 1266 method, baseType, member.name, member, isSubclass)) {
1263 seen.add(method.name); 1267 seen.add(method.name);
1264 } 1268 }
1265 } else { 1269 } else {
1266 assert(member is ConstructorDeclaration); 1270 assert(member is ConstructorDeclaration);
1267 } 1271 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 /// 1307 ///
1304 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For 1308 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For
1305 /// [ClassDeclaration]s errors are reported on the member that contains the 1309 /// [ClassDeclaration]s errors are reported on the member that contains the
1306 /// invalid override, for [InterfaceType]s we use [errorLocation] instead. 1310 /// invalid override, for [InterfaceType]s we use [errorLocation] instead.
1307 void _checkInterfacesOverrides( 1311 void _checkInterfacesOverrides(
1308 cls, Iterable<InterfaceType> interfaces, Set<String> seen, 1312 cls, Iterable<InterfaceType> interfaces, Set<String> seen,
1309 {Set<InterfaceType> visited, 1313 {Set<InterfaceType> visited,
1310 bool includeParents: true, 1314 bool includeParents: true,
1311 AstNode errorLocation}) { 1315 AstNode errorLocation}) {
1312 var node = cls is ClassDeclaration ? cls : null; 1316 var node = cls is ClassDeclaration ? cls : null;
1313 var type = cls is InterfaceType ? cls : node.element.type; 1317 var type =
1318 cls is InterfaceType ? cls : elementForClassDeclaration(node).type;
1314 1319
1315 if (visited == null) { 1320 if (visited == null) {
1316 visited = new Set<InterfaceType>(); 1321 visited = new Set<InterfaceType>();
1317 } else if (visited.contains(type)) { 1322 } else if (visited.contains(type)) {
1318 // Malformed type. 1323 // Malformed type.
1319 return; 1324 return;
1320 } else { 1325 } else {
1321 visited.add(type); 1326 visited.add(type);
1322 } 1327 }
1323 1328
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1358 1363
1359 /// Check overrides from mixin applications themselves. For example, in: 1364 /// Check overrides from mixin applications themselves. For example, in:
1360 /// 1365 ///
1361 /// A extends B with E, F 1366 /// A extends B with E, F
1362 /// 1367 ///
1363 /// we check: 1368 /// we check:
1364 /// 1369 ///
1365 /// B & E against B (equivalently how E overrides B) 1370 /// B & E against B (equivalently how E overrides B)
1366 /// B & E & F against B & E (equivalently how F overrides both B and E) 1371 /// B & E & F against B & E (equivalently how F overrides both B and E)
1367 void _checkMixinApplicationOverrides(ClassDeclaration node) { 1372 void _checkMixinApplicationOverrides(ClassDeclaration node) {
1368 var type = node.element.type; 1373 var type = elementForClassDeclaration(node).type;
1369 var parent = type.superclass; 1374 var parent = type.superclass;
1370 var mixins = type.mixins; 1375 var mixins = type.mixins;
1371 1376
1372 // Check overrides from applying mixins 1377 // Check overrides from applying mixins
1373 for (int i = 0; i < mixins.length; i++) { 1378 for (int i = 0; i < mixins.length; i++) {
1374 var seen = new Set<String>(); 1379 var seen = new Set<String>();
1375 var current = mixins[i]; 1380 var current = mixins[i];
1376 var errorLocation = node.withClause.mixinTypes[i]; 1381 var errorLocation = node.withClause.mixinTypes[i];
1377 for (int j = i - 1; j >= 0; j--) { 1382 for (int j = i - 1; j >= 0; j--) {
1378 _checkIndividualOverridesFromType( 1383 _checkIndividualOverridesFromType(
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1477 /// m(A a) {} 1482 /// m(A a) {}
1478 /// } 1483 /// }
1479 /// class Parent extends Grandparent { 1484 /// class Parent extends Grandparent {
1480 /// m(A a) {} 1485 /// m(A a) {}
1481 /// } 1486 /// }
1482 /// class Test extends Parent { 1487 /// class Test extends Parent {
1483 /// m(B a) {} // invalid override 1488 /// m(B a) {} // invalid override
1484 /// } 1489 /// }
1485 void _checkSuperOverrides(ClassDeclaration node) { 1490 void _checkSuperOverrides(ClassDeclaration node) {
1486 var seen = new Set<String>(); 1491 var seen = new Set<String>();
1487 var current = node.element.type; 1492 var current = elementForClassDeclaration(node).type;
1488 var visited = new Set<InterfaceType>(); 1493 var visited = new Set<InterfaceType>();
1489 do { 1494 do {
1490 visited.add(current); 1495 visited.add(current);
1491 current.mixins.reversed.forEach( 1496 current.mixins.reversed.forEach(
1492 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); 1497 (m) => _checkIndividualOverridesFromClass(node, m, seen, true));
1493 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); 1498 _checkIndividualOverridesFromClass(node, current.superclass, seen, true);
1494 current = current.superclass; 1499 current = current.superclass;
1495 } while (!current.isObject && !visited.contains(current)); 1500 } while (!current.isObject && !visited.contains(current));
1496 } 1501 }
1497 } 1502 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698