OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |