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

Side by Side Diff: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java

Issue 267923004: Check const map literal keys and switch case exprs using type of constant. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 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 | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013, the Dart project authors. 2 * Copyright (c) 2013, the Dart project authors.
3 * 3 *
4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u se this file except 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u se this file except
5 * in compliance with the License. You may obtain a copy of the License at 5 * in compliance with the License. You may obtain a copy of the License at
6 * 6 *
7 * http://www.eclipse.org/legal/epl-v10.html 7 * http://www.eclipse.org/legal/epl-v10.html
8 * 8 *
9 * Unless required by applicable law or agreed to in writing, software distribut ed under the License 9 * Unless required by applicable law or agreed to in writing, software distribut ed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K IND, either express 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K IND, either express
(...skipping 889 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 if (node.getConstKeyword() != null) { 900 if (node.getConstKeyword() != null) {
901 checkForInvalidTypeArgumentInConstTypedLiteral( 901 checkForInvalidTypeArgumentInConstTypedLiteral(
902 arguments, 902 arguments,
903 CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_MAP); 903 CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_MAP);
904 } 904 }
905 } 905 }
906 checkExpectedTwoMapTypeArguments(typeArguments); 906 checkExpectedTwoMapTypeArguments(typeArguments);
907 checkForMapTypeNotAssignable(node, typeArguments); 907 checkForMapTypeNotAssignable(node, typeArguments);
908 } 908 }
909 checkForNonConstMapAsExpressionStatement(node); 909 checkForNonConstMapAsExpressionStatement(node);
910 checkForConstMapKeyExpressionTypeImplementsEquals(node);
911 return super.visitMapLiteral(node); 910 return super.visitMapLiteral(node);
912 } 911 }
913 912
914 @Override 913 @Override
915 public Void visitMethodDeclaration(MethodDeclaration node) { 914 public Void visitMethodDeclaration(MethodDeclaration node) {
916 ExecutableElement previousFunction = enclosingFunction; 915 ExecutableElement previousFunction = enclosingFunction;
917 try { 916 try {
918 isInStaticMethod = node.isStatic(); 917 isInStaticMethod = node.isStatic();
919 enclosingFunction = node.getElement(); 918 enclosingFunction = node.getElement();
920 SimpleIdentifier identifier = node.getName(); 919 SimpleIdentifier identifier = node.getName();
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1066 isInConstructorInitializer = true; 1065 isInConstructorInitializer = true;
1067 try { 1066 try {
1068 return super.visitSuperConstructorInvocation(node); 1067 return super.visitSuperConstructorInvocation(node);
1069 } finally { 1068 } finally {
1070 isInConstructorInitializer = false; 1069 isInConstructorInitializer = false;
1071 } 1070 }
1072 } 1071 }
1073 1072
1074 @Override 1073 @Override
1075 public Void visitSwitchStatement(SwitchStatement node) { 1074 public Void visitSwitchStatement(SwitchStatement node) {
1076 checkForInconsistentCaseExpressionTypes(node);
1077 checkForSwitchExpressionNotAssignable(node); 1075 checkForSwitchExpressionNotAssignable(node);
1078 checkForCaseBlocksNotTerminated(node); 1076 checkForCaseBlocksNotTerminated(node);
1079 return super.visitSwitchStatement(node); 1077 return super.visitSwitchStatement(node);
1080 } 1078 }
1081 1079
1082 @Override 1080 @Override
1083 public Void visitThisExpression(ThisExpression node) { 1081 public Void visitThisExpression(ThisExpression node) {
1084 checkForInvalidReferenceToThis(node); 1082 checkForInvalidReferenceToThis(node);
1085 return super.visitThisExpression(node); 1083 return super.visitThisExpression(node);
1086 } 1084 }
(...skipping 1102 matching lines...) Expand 10 before | Expand all | Expand 10 after
2189 for (int i = 0; i < lastMember; i++) { 2187 for (int i = 0; i < lastMember; i++) {
2190 SwitchMember member = members.get(i); 2188 SwitchMember member = members.get(i);
2191 if (member instanceof SwitchCase) { 2189 if (member instanceof SwitchCase) {
2192 foundError |= checkForCaseBlockNotTerminated((SwitchCase) member); 2190 foundError |= checkForCaseBlockNotTerminated((SwitchCase) member);
2193 } 2191 }
2194 } 2192 }
2195 return foundError; 2193 return foundError;
2196 } 2194 }
2197 2195
2198 /** 2196 /**
2199 * This verifies that the passed switch statement does not have a case express ion with the
2200 * operator '==' overridden.
2201 *
2202 * @param node the switch statement to evaluate
2203 * @param type the common type of all 'case' expressions
2204 * @return {@code true} if and only if an error code is generated on the passe d node
2205 * @see CompileTimeErrorCode#CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
2206 */
2207 private boolean checkForCaseExpressionTypeImplementsEquals(SwitchStatement nod e, Type type) {
2208 if (!implementsEqualsWhenNotAllowed(type)) {
2209 return false;
2210 }
2211 // report error
2212 errorReporter.reportErrorForToken(
2213 CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
2214 node.getKeyword(),
2215 type.getDisplayName());
2216 return true;
2217 }
2218
2219 /**
2220 * This verifies that the passed method declaration is abstract only if the en closing class is 2197 * This verifies that the passed method declaration is abstract only if the en closing class is
2221 * also abstract. 2198 * also abstract.
2222 * 2199 *
2223 * @param node the method declaration to evaluate 2200 * @param node the method declaration to evaluate
2224 * @return {@code true} if and only if an error code is generated on the passe d node 2201 * @return {@code true} if and only if an error code is generated on the passe d node
2225 * @see StaticWarningCode#CONCRETE_CLASS_WITH_ABSTRACT_MEMBER 2202 * @see StaticWarningCode#CONCRETE_CLASS_WITH_ABSTRACT_MEMBER
2226 */ 2203 */
2227 private boolean checkForConcreteClassWithAbstractMember(MethodDeclaration node ) { 2204 private boolean checkForConcreteClassWithAbstractMember(MethodDeclaration node ) {
2228 if (node.isAbstract() && enclosingClass != null && !enclosingClass.isAbstrac t()) { 2205 if (node.isAbstract() && enclosingClass != null && !enclosingClass.isAbstrac t()) {
2229 SimpleIdentifier methodName = node.getName(); 2206 SimpleIdentifier methodName = node.getName();
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after
2771 */ 2748 */
2772 private boolean checkForConstFormalParameter(NormalFormalParameter node) { 2749 private boolean checkForConstFormalParameter(NormalFormalParameter node) {
2773 if (node.isConst()) { 2750 if (node.isConst()) {
2774 errorReporter.reportErrorForNode(CompileTimeErrorCode.CONST_FORMAL_PARAMET ER, node); 2751 errorReporter.reportErrorForNode(CompileTimeErrorCode.CONST_FORMAL_PARAMET ER, node);
2775 return true; 2752 return true;
2776 } 2753 }
2777 return false; 2754 return false;
2778 } 2755 }
2779 2756
2780 /** 2757 /**
2781 * This verifies that the all keys of the passed map literal have class type t hat does not declare
2782 * operator <i>==<i>.
2783 *
2784 * @param key the map literal to evaluate
2785 * @return {@code true} if and only if an error code is generated on the passe d node
2786 * @see CompileTimeErrorCode#CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
2787 */
2788 private boolean checkForConstMapKeyExpressionTypeImplementsEquals(MapLiteral n ode) {
2789 // OK, not const.
2790 if (node.getConstKeyword() == null) {
2791 return false;
2792 }
2793 // Check every map entry.
2794 boolean hasProblems = false;
2795 for (MapLiteralEntry entry : node.getEntries()) {
2796 Expression key = entry.getKey();
2797 Type type = key.getStaticType();
2798 if (implementsEqualsWhenNotAllowed(type)) {
2799 errorReporter.reportErrorForNode(
2800 CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS ,
2801 key,
2802 type.getDisplayName());
2803 hasProblems = true;
2804 }
2805 }
2806 return hasProblems;
2807 }
2808
2809 /**
2810 * This verifies that the passed instance creation expression is not being inv oked on an abstract 2758 * This verifies that the passed instance creation expression is not being inv oked on an abstract
2811 * class. 2759 * class.
2812 * 2760 *
2813 * @param node the instance creation expression to evaluate 2761 * @param node the instance creation expression to evaluate
2814 * @param typeName the {@link TypeName} of the {@link ConstructorName} from th e 2762 * @param typeName the {@link TypeName} of the {@link ConstructorName} from th e
2815 * {@link InstanceCreationExpression}, this is the AST node that the error is attached to 2763 * {@link InstanceCreationExpression}, this is the AST node that the error is attached to
2816 * @param type the type being constructed with this {@link InstanceCreationExp ression} 2764 * @param type the type being constructed with this {@link InstanceCreationExp ression}
2817 * @return {@code true} if and only if an error code is generated on the passe d node 2765 * @return {@code true} if and only if an error code is generated on the passe d node
2818 * @see StaticWarningCode#CONST_WITH_ABSTRACT_CLASS 2766 * @see StaticWarningCode#CONST_WITH_ABSTRACT_CLASS
2819 * @see StaticWarningCode#NEW_WITH_ABSTRACT_CLASS 2767 * @see StaticWarningCode#NEW_WITH_ABSTRACT_CLASS
(...skipping 831 matching lines...) Expand 10 before | Expand all | Expand 10 after
3651 } 3599 }
3652 // report problem 3600 // report problem
3653 errorReporter.reportErrorForNode( 3601 errorReporter.reportErrorForNode(
3654 CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY, 3602 CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY,
3655 node, 3603 node,
3656 node.getUri()); 3604 node.getUri());
3657 return true; 3605 return true;
3658 } 3606 }
3659 3607
3660 /** 3608 /**
3661 * This verifies that the passed switch statement case expressions all have th e same type.
3662 *
3663 * @param node the switch statement to evaluate
3664 * @return {@code true} if and only if an error code is generated on the passe d node
3665 * @see CompileTimeErrorCode#INCONSISTENT_CASE_EXPRESSION_TYPES
3666 */
3667 private boolean checkForInconsistentCaseExpressionTypes(SwitchStatement node) {
3668 // TODO(jwren) Revisit this algorithm, should there up to n-1 errors?
3669 NodeList<SwitchMember> switchMembers = node.getMembers();
3670 boolean foundError = false;
3671 Type firstType = null;
3672 for (SwitchMember switchMember : switchMembers) {
3673 if (switchMember instanceof SwitchCase) {
3674 SwitchCase switchCase = (SwitchCase) switchMember;
3675 Expression expression = switchCase.getExpression();
3676 if (firstType == null) {
3677 // TODO(brianwilkerson) This is failing with const variables whose dec lared type is
3678 // dynamic. The problem is that we don't have any way to propagate typ e information for
3679 // the variable.
3680 firstType = expression.getBestType();
3681 } else {
3682 Type nType = expression.getBestType();
3683 if (!firstType.equals(nType)) {
3684 errorReporter.reportErrorForNode(
3685 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES,
3686 expression,
3687 expression.toSource(),
3688 firstType.getDisplayName());
3689 foundError = true;
3690 }
3691 }
3692 }
3693 }
3694 if (!foundError) {
3695 checkForCaseExpressionTypeImplementsEquals(node, firstType);
3696 }
3697 return foundError;
3698 }
3699
3700 /**
3701 * For each class declaration, this method is called which verifies that all i nherited members are 3609 * For each class declaration, this method is called which verifies that all i nherited members are
3702 * inherited consistently. 3610 * inherited consistently.
3703 * 3611 *
3704 * @return {@code true} if and only if an error code is generated on the passe d node 3612 * @return {@code true} if and only if an error code is generated on the passe d node
3705 * @see StaticTypeWarningCode#INCONSISTENT_METHOD_INHERITANCE 3613 * @see StaticTypeWarningCode#INCONSISTENT_METHOD_INHERITANCE
3706 */ 3614 */
3707 private boolean checkForInconsistentMethodInheritance() { 3615 private boolean checkForInconsistentMethodInheritance() {
3708 // Ensure that the inheritance manager has a chance to generate all errors w e may care about, 3616 // Ensure that the inheritance manager has a chance to generate all errors w e may care about,
3709 // note that we ensure that the interfaces data since there are no errors. 3617 // note that we ensure that the interfaces data since there are no errors.
3710 inheritanceManager.getMapOfMembersInheritedFromInterfaces(enclosingClass); 3618 inheritanceManager.getMapOfMembersInheritedFromInterfaces(enclosingClass);
(...skipping 2017 matching lines...) Expand 10 before | Expand all | Expand 10 after
5728 for (Type typeArgument : interfaceType.getTypeArguments()) { 5636 for (Type typeArgument : interfaceType.getTypeArguments()) {
5729 addTypeToCheck(typeArgument); 5637 addTypeToCheck(typeArgument);
5730 } 5638 }
5731 } 5639 }
5732 } 5640 }
5733 }); 5641 });
5734 checked.add(current); 5642 checked.add(current);
5735 } 5643 }
5736 } 5644 }
5737 5645
5738 /**
5739 * @return {@code true} if given {@link Type} implements operator <i>==</i>, a nd it is not
5740 * <i>int</i> or <i>String</i>.
5741 */
5742 private boolean implementsEqualsWhenNotAllowed(Type type) {
5743 // ignore int or String
5744 if (type == null || type.equals(intType) || type.equals(typeProvider.getStri ngType())) {
5745 return false;
5746 } else if (type.equals(typeProvider.getDoubleType())) {
5747 return true;
5748 }
5749 // prepare ClassElement
5750 Element element = type.getElement();
5751 if (!(element instanceof ClassElement)) {
5752 return false;
5753 }
5754 ClassElement classElement = (ClassElement) element;
5755 // lookup for ==
5756 MethodElement method = classElement.lookUpMethod("==", currentLibrary);
5757 while (method != null && method.isAbstract()) {
5758 ClassElement definingClass = method.getEnclosingElement();
5759 if (definingClass == null) {
5760 return false;
5761 }
5762 method = definingClass.lookUpInheritedMethod("==", currentLibrary);
5763 }
5764 if (method == null || method.getEnclosingElement().getType().isObject()) {
5765 return false;
5766 }
5767 // there is == that we don't like
5768 return true;
5769 }
5770
5771 private boolean isFunctionType(Type type) { 5646 private boolean isFunctionType(Type type) {
5772 if (type.isDynamic() || type.isBottom()) { 5647 if (type.isDynamic() || type.isBottom()) {
5773 return true; 5648 return true;
5774 } else if (type instanceof FunctionType || type.isDartCoreFunction()) { 5649 } else if (type instanceof FunctionType || type.isDartCoreFunction()) {
5775 return true; 5650 return true;
5776 } else if (type instanceof InterfaceType) { 5651 } else if (type instanceof InterfaceType) {
5777 MethodElement callMethod = ((InterfaceType) type).lookUpMethod( 5652 MethodElement callMethod = ((InterfaceType) type).lookUpMethod(
5778 FunctionElement.CALL_METHOD_NAME, 5653 FunctionElement.CALL_METHOD_NAME,
5779 currentLibrary); 5654 currentLibrary);
5780 return callMethod != null; 5655 return callMethod != null;
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
6049 InterfaceType[] interfaceTypes = classElt.getInterfaces(); 5924 InterfaceType[] interfaceTypes = classElt.getInterfaces();
6050 for (InterfaceType interfaceType : interfaceTypes) { 5925 for (InterfaceType interfaceType : interfaceTypes) {
6051 if (safeCheckForRecursiveInterfaceInheritance(interfaceType.getElement(), path)) { 5926 if (safeCheckForRecursiveInterfaceInheritance(interfaceType.getElement(), path)) {
6052 return true; 5927 return true;
6053 } 5928 }
6054 } 5929 }
6055 path.remove(path.size() - 1); 5930 path.remove(path.size() - 1);
6056 return false; 5931 return false;
6057 } 5932 }
6058 } 5933 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698