blob: ad590fb336b9d505aec6119a620436ebee9c64d8 [file] [log] [blame]
/*
* 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() {
}
}