| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.uibinder.rebind; |
| |
| import com.google.gwt.core.ext.typeinfo.JArrayType; |
| import com.google.gwt.core.ext.typeinfo.JClassType; |
| import com.google.gwt.core.ext.typeinfo.JConstructor; |
| import com.google.gwt.core.ext.typeinfo.JPrimitiveType; |
| import com.google.gwt.core.ext.typeinfo.JType; |
| |
| /** |
| * Utilities for functionality that really should be part of TypeOracle. |
| */ |
| public class TypeOracleUtils { |
| |
| /** |
| * Check for a constructor which is compatible with the supplied argument |
| * types. |
| * |
| * @param type |
| * @param argTypes |
| * @return true if a constructor compatible with the supplied arguments exists |
| */ |
| public static boolean hasCompatibleConstructor(JClassType type, JType... argTypes) { |
| // Note that this does not return the constructor, since that is a more |
| // complicated decision about finding the best matching arguments where |
| // more than one are compatible. |
| for (JConstructor ctor : type.getConstructors()) { |
| if (typesAreCompatible(ctor.getParameterTypes(), argTypes, ctor.isVarArgs())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return true if the supplied argument type is assignment compatible with a |
| * declared parameter type. |
| * |
| * @param paramType |
| * @param argType |
| * @return true if the argument type is compatible with the parameter type |
| */ |
| public static boolean typeIsCompatible(JType paramType, JType argType) { |
| if (paramType == argType) { |
| return true; |
| } |
| JClassType paramClass = paramType.isClassOrInterface(); |
| if (paramClass != null) { |
| JClassType argClass = argType.isClassOrInterface(); |
| return argClass != null && paramClass.isAssignableFrom(argClass); |
| } |
| JArrayType paramArray = paramType.isArray(); |
| if (paramArray != null) { |
| JArrayType argArray = argType.isArray(); |
| return argArray != null && typeIsCompatible(paramArray.getComponentType(), |
| argArray.getComponentType()); |
| } |
| if (paramType instanceof JPrimitiveType && argType instanceof JPrimitiveType) { |
| return isWideningPrimitiveConversion((JPrimitiveType) paramType, (JPrimitiveType) argType); |
| } |
| // TODO: handle autoboxing? |
| return false; |
| } |
| |
| /** |
| * Check if the types of supplied arguments are compatible with the parameter |
| * types of a method. |
| * |
| * @param paramTypes |
| * @param argTypes |
| * @param varArgs true if the method is a varargs method |
| * @return true if all argument types are compatible with the parameter types |
| */ |
| public static boolean typesAreCompatible(JType[] paramTypes, JType[] argTypes, boolean varArgs) { |
| int expectedArgs = paramTypes.length; |
| int actualArgs = argTypes.length; |
| int comparedArgs = expectedArgs; |
| if (varArgs) { |
| comparedArgs--; |
| if (actualArgs != expectedArgs || !typeIsCompatible(paramTypes[comparedArgs], argTypes[comparedArgs])) { |
| if (actualArgs < comparedArgs) { |
| return false; |
| } |
| JArrayType varargsArrayType = paramTypes[comparedArgs].isArray(); |
| assert varargsArrayType != null; |
| JType varargsType = varargsArrayType.getComponentType(); |
| for (int i = comparedArgs; i < actualArgs; ++i) { |
| if (!typeIsCompatible(varargsType, argTypes[i])) { |
| return false; |
| } |
| } |
| } |
| } else if (actualArgs != expectedArgs) { |
| return false; |
| } |
| for (int i = 0; i < comparedArgs; ++i) { |
| if (!typeIsCompatible(paramTypes[i], argTypes[i])) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Check for a widening primitive conversion. See |
| * <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25214">JLS 5.1.2</a>. |
| * |
| * @param paramType |
| * @param argType |
| * @return true if assigning argType to paramType is a widening conversion |
| */ |
| private static boolean isWideningPrimitiveConversion(JPrimitiveType paramType, JPrimitiveType argType) { |
| switch (paramType) { |
| case DOUBLE: |
| return argType != JPrimitiveType.BOOLEAN; |
| case FLOAT: |
| return argType != JPrimitiveType.BOOLEAN && argType != JPrimitiveType.DOUBLE; |
| case LONG: |
| return argType != JPrimitiveType.BOOLEAN && argType != JPrimitiveType.DOUBLE |
| && argType != JPrimitiveType.FLOAT; |
| case INT: |
| return argType == JPrimitiveType.BYTE || argType == JPrimitiveType.SHORT |
| || argType == JPrimitiveType.CHAR; |
| case SHORT: |
| return argType == JPrimitiveType.BYTE; |
| default: |
| return false; |
| } |
| } |
| |
| private TypeOracleUtils() { |
| } |
| } |