1 /******************************************************************************* 2 * Copyright (c) 2000, 2016 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for 14 * bug "inline method - doesn't handle implicit cast" (see 15 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=24941). 16 *******************************************************************************/ 17 package org.eclipse.jdt.internal.corext.dom; 18 19 import org.eclipse.jdt.core.dom.ITypeBinding; 20 import org.eclipse.jdt.core.dom.Modifier; 21 import org.eclipse.jdt.core.dom.PrimitiveType; 22 23 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; 24 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment; 25 26 /** 27 * Helper class to check if objects are assignable to each other. 28 * Methods with multiple arguments also work across bindings environments. 29 */ 30 // @see JDTUIHelperClasses 31 public class TypeRules { 32 33 /** 34 * Tests if two types are assign compatible. Void types are never compatible. 35 * 36 * @param typeToAssign The binding of the type to assign 37 * @param definedType The type of the object that is assigned 38 * @return <code>true</code> iff definedType = typeToAssign is a valid assignment 39 */ canAssign(ITypeBinding typeToAssign, ITypeBinding definedType)40 public static boolean canAssign(ITypeBinding typeToAssign, ITypeBinding definedType) { 41 TypeEnvironment typeEnvironment= new TypeEnvironment(false, true); 42 TType defined= typeEnvironment.create(definedType); 43 TType toAssign= typeEnvironment.create(typeToAssign); 44 return toAssign.canAssignTo(defined); 45 } 46 isArrayCompatible(ITypeBinding definedType)47 public static boolean isArrayCompatible(ITypeBinding definedType) { 48 if (definedType.isTopLevel()) { 49 if (definedType.isClass()) { 50 return "Object".equals(definedType.getName()) && "java.lang".equals(definedType.getPackage().getName()); //$NON-NLS-1$//$NON-NLS-2$ 51 } else { 52 String qualifiedName= definedType.getQualifiedName(); 53 return "java.io.Serializable".equals(qualifiedName) || "java.lang.Cloneable".equals(qualifiedName); //$NON-NLS-1$ //$NON-NLS-2$ 54 } 55 } 56 return false; 57 } 58 isJavaLangObject(ITypeBinding definedType)59 public static boolean isJavaLangObject(ITypeBinding definedType) { 60 return definedType.isTopLevel() && definedType.isClass() && "Object".equals(definedType.getName()) && "java.lang".equals(definedType.getPackage().getName()); //$NON-NLS-1$//$NON-NLS-2$ 61 } 62 63 /** 64 * Tests if a two types are cast compatible 65 * @param castType The binding of the type to cast to 66 * @param bindingToCast The binding ef the expression to cast. 67 * @return boolean Returns true if (castType) bindingToCast is a valid cast expression (can be unnecessary, but not invalid). 68 */ canCast(ITypeBinding castType, ITypeBinding bindingToCast)69 public static boolean canCast(ITypeBinding castType, ITypeBinding bindingToCast) { 70 //see bug 80715 71 72 String voidName= PrimitiveType.VOID.toString(); 73 74 if (castType.isAnonymous() || castType.isNullType() || voidName.equals(castType.getName())) { 75 throw new IllegalArgumentException(); 76 } 77 78 if (castType == bindingToCast) { 79 return true; 80 } 81 82 if (voidName.equals(bindingToCast.getName())) { 83 return false; 84 } 85 86 if (bindingToCast.isArray()) { 87 if (!castType.isArray()) { 88 return isArrayCompatible(castType); // can not cast an arraytype to a non array type (except to Object, Serializable...) 89 } 90 91 int toCastDim= bindingToCast.getDimensions(); 92 int castTypeDim= castType.getDimensions(); 93 if (toCastDim == castTypeDim) { 94 bindingToCast= bindingToCast.getElementType(); 95 castType= castType.getElementType(); 96 if (castType.isPrimitive() && castType != bindingToCast) { 97 return false; // can't assign arrays of different primitive types to each other 98 } 99 // fall through 100 } else if (toCastDim < castTypeDim) { 101 return isArrayCompatible(bindingToCast.getElementType()); 102 } else { 103 return isArrayCompatible(castType.getElementType()); 104 } 105 } 106 if (castType.isPrimitive()) { 107 if (!bindingToCast.isPrimitive()) { 108 return false; 109 } 110 String boolName= PrimitiveType.BOOLEAN.toString(); 111 return (!boolName.equals(castType.getName()) && !boolName.equals(bindingToCast.getName())); 112 } else { 113 if (bindingToCast.isPrimitive()) { 114 return false; 115 } 116 if (castType.isArray()) { 117 return isArrayCompatible(bindingToCast); 118 } 119 if (castType.isInterface()) { 120 if ((bindingToCast.getModifiers() & Modifier.FINAL) != 0) { 121 return Bindings.isSuperType(castType, bindingToCast); 122 } else { 123 return true; 124 } 125 } 126 if (bindingToCast.isInterface()) { 127 if ((castType.getModifiers() & Modifier.FINAL) != 0) { 128 return Bindings.isSuperType(bindingToCast, castType); 129 } else { 130 return true; 131 } 132 } 133 if (isJavaLangObject(castType)) { 134 return true; 135 } 136 137 return Bindings.isSuperType(bindingToCast, castType) || Bindings.isSuperType(castType, bindingToCast); 138 } 139 } 140 TypeRules()141 private TypeRules() { 142 } 143 144 } 145