package net.sourceforge.javautil.bytecode.api.type.method;
import net.sourceforge.javautil.bytecode.api.IBytecodeMember;
import net.sourceforge.javautil.bytecode.api.IBytecodeReferenceable;
import net.sourceforge.javautil.bytecode.api.BytecodeResolutionPool;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.MethodDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess;
/**
* The base for all method related byte code.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public interface IBytecodeMethod<C extends BytecodeContextMethod> extends IBytecodeMember {
/**
* The argument match indicates how exactly the parameter types match
* to a corresponding argument set.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: ClassMethodAbstract.java 1536 2009-12-03 22:51:08Z ponderator $
*/
public enum ArgumentMatch {
/**
* There is not functional match and any invocation attempt will fail.
*/
NONE,
/**
* An invocation attempt should work, but some or all of the arguments are sub classes of the exact parameter types
*/
FUNCTIONAL,
/**
* An invocation will work, and all the arguments are exact matchees for the parameter types
*/
EXACT
};
/**
* @return The type this method was declared on
*/
IBytecodeResolvable getDeclaringType();
/**
* @param ctx The context in which to compare the arguments
* @param types The types of arguments to compare to
* @return The result of the comparison
*/
ArgumentMatch compareArguments (BytecodeResolutionPool pool, TypeDescriptor... types);
/**
* @return The name of this method
*/
String getName();
/**
* @return The descriptor for this method
*/
MethodDescriptor getDescriptor();
/**
* @return True if the last argument is of an array type and the variable argument count flag is true, otherwise false
*/
boolean isVarArgs ();
/**
* Utility class for {@link IBytecodeMethod}'s.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public static class Util {
/**
* @param arguments The arguments to compare to the parameter types
* @return The match result for the comparison
*/
public static ArgumentMatch compareArguments (BytecodeResolutionPool pool, IBytecodeMethod method, TypeDescriptor... arguments) {
boolean varArgs = method.getDescriptor().isVarArgs();
if (method.getDescriptor().getParameters().length != arguments.length) {
if (varArgs) {
if (method.getDescriptor().getParameters().length != arguments.length + 1) {
return ArgumentMatch.NONE;
}
} else
return ArgumentMatch.NONE;
}
IBytecodeResolvable[] parameterTypes = pool.resolve(method.getDescriptor().getParameters());
if (parameterTypes.length != parameterTypes.length && !varArgs)
return ArgumentMatch.NONE;
else if (parameterTypes.length > arguments.length && arguments.length < parameterTypes.length - 1 && varArgs)
return ArgumentMatch.NONE;
int matched = 0;
for (int p=0; p<parameterTypes.length; p++) {
if (arguments.length > p && arguments[p] == null) {
if (!parameterTypes[p].getType().isPrimitive()) { matched++; continue; } else return ArgumentMatch.NONE;
}
if (p == parameterTypes.length - 1 && parameterTypes[p].getType().isArray() && varArgs) {
if (arguments.length == p) { matched++; continue; }
IBytecodeResolvable ct = parameterTypes[p];
for (int a=p; a<arguments.length; a++) {
if (arguments[a] == null && ct.getType().isPrimitive()) return ArgumentMatch.NONE;
if (arguments[a] == null) continue;
IBytecodeResolvable abr = pool.resolve(arguments[a].getClassName());
if (abr.isInstanceof(pool, ct)) continue;
if (arguments[a].isArray() && arguments[a].getComponentType().compareTo( ct.getType() ) == 0) continue;
return ArgumentMatch.NONE;
}
} else if (parameterTypes[p].getType().isPrimitive()) {
TypeDescriptor ptype = parameterTypes[p].getType();
if (ptype == arguments[p]) { matched++; continue; }
if (ptype.isPrimitive() && arguments[p].getClassName().equals(ptype.getBoxedType())) {
matched++; continue;
} else return ArgumentMatch.NONE;
} else if (arguments.length > p) {
if (parameterTypes[p].getType().compareTo( arguments[p] ) == 0) { matched++; continue; }
else {
IBytecodeResolvable abr = pool.resolve(arguments[p].getClassName());
if (abr.isInstanceof( pool, parameterTypes[p] )) continue;
}
return ArgumentMatch.NONE;
}
}
return matched == parameterTypes.length ? ArgumentMatch.EXACT : ArgumentMatch.FUNCTIONAL;
}
}
}