/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.lang.reflect;
import gw.lang.parser.StandardCoercionManager;
import gw.util.DynamicArray;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class MethodList extends DynamicArray<IMethodInfo> {
public static final MethodList EMPTY = new MethodList();
private HashMap<String, DynamicArray<IMethodInfo>> map = new HashMap<String, DynamicArray<IMethodInfo>>();
public MethodList() {
}
public MethodList(List<IMethodInfo> methods) {
addAll(methods);
}
public MethodList(int size) {
super(size);
}
public MethodList filterMethods(IRelativeTypeInfo.Accessibility accessibility) {
MethodList ret = new MethodList();
for (IMethodInfo method : this) {
if (FeatureManager.isFeatureAccessible(method, accessibility)) {
ret.add(method);
}
}
ret.trimToSize();
return ret;
}
@Override
public boolean add(IMethodInfo method) {
addToMap(method);
return super.add(method);
}
@Override
public boolean addAll(Collection<? extends IMethodInfo> c) {
for (IMethodInfo method : c) {
addToMap(method);
}
return super.addAll(c);
}
private void addToMap(IMethodInfo method) {
String displayName = (String)method.getDisplayName();
DynamicArray<IMethodInfo> methods = map.get(displayName);
if (methods == null) {
methods = new DynamicArray<IMethodInfo>(1);
map.put(displayName, methods);
}
methods.add(method);
}
@Override
public IMethodInfo remove(int index) {
IMethodInfo oldMethod = get(index);
String displayName = (String)oldMethod.getDisplayName();
DynamicArray<IMethodInfo> methods = map.get(displayName);
int i = methods.indexOf(oldMethod);
methods.remove(i);
return super.remove(index);
}
@Override
public IMethodInfo set(int index, IMethodInfo method) {
IMethodInfo oldMethod = get(index);
String displayName = (String)method.getDisplayName();
DynamicArray<IMethodInfo> methods = map.get(displayName);
int i = methods.indexOf(oldMethod);
methods.set(i, method);
return super.set(index, method);
}
public DynamicArray<? extends IMethodInfo> getMethods(String name) {
DynamicArray<IMethodInfo> methodInfoList = map.get( name );
return methodInfoList != null ? methodInfoList : DynamicArray.EMPTY;
}
public static MethodList singleton(IMethodInfo theOneMethod) {
MethodList infos = new MethodList(1);
infos.add(theOneMethod);
return infos;
}
@Override
public void add(int index, IMethodInfo method) {
throw new RuntimeException("Not supported");
}
@Override
public boolean addAll(int index, Collection<? extends IMethodInfo> c) {
throw new RuntimeException("Not supported");
}
@Override
public boolean remove(Object o) {
throw new RuntimeException("Not supported");
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
throw new RuntimeException("Not supported");
}
@Override
public Object clone() {
return super.clone();
}
@Override
public void clear() {
super.clear();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new RuntimeException("Not supported");
}
@Override
public boolean retainAll(Collection<?> c) {
throw new RuntimeException("Not supported");
}
public IMethodInfo findAssignableMethod( IMethodInfo miTo ) {
IMethodInfo foundMethod = null;
String mname = miTo.getDisplayName();
IParameterInfo[] toParams = miTo.getParameters();
int iTopScore = 0;
outer:
for( IMethodInfo miFrom : this ) {
if( miFrom.getDisplayName().equals( mname ) ) {
IType fromReturnType = miFrom.getReturnType();
IType toReturnType = miTo.getReturnType();
fromReturnType = TypeSystem.replaceTypeVariableTypeParametersWithBoundingTypes( fromReturnType, miFrom.getOwnersType() );
toReturnType = TypeSystem.replaceTypeVariableTypeParametersWithBoundingTypes( toReturnType, miTo.getOwnersType() );
if( !toReturnType.equals( fromReturnType ) &&
!toReturnType.isAssignableFrom( fromReturnType ) &&
!StandardCoercionManager.arePrimitiveTypesAssignable( toReturnType, fromReturnType ) ) {
continue;
}
IParameterInfo[] fromParams = miFrom.getParameters();
if( fromParams.length == toParams.length ) {
if( fromParams.length == 0 ) {
foundMethod = miFrom;
}
int iScore = 0;
for( int ip = 0; ip < fromParams.length; ip++ ) {
IParameterInfo fromParam = fromParams[ip];
IParameterInfo toParam = toParams[ip];
IType fromParamType = TypeSystem.replaceTypeVariableTypeParametersWithBoundingTypes( fromParam.getFeatureType(), miFrom.getOwnersType() );
IType toParamType = TypeSystem.replaceTypeVariableTypeParametersWithBoundingTypes( toParam.getFeatureType(), miTo.getOwnersType() );
if( fromParamType.equals( toParamType ) ) {
// types are the same
iScore += 2;
}
else if( fromParamType.isAssignableFrom( toParamType ) ||
StandardCoercionManager.arePrimitiveTypesAssignable( fromParamType, toParamType ) ) {
// types are contravariant
iScore += 1;
}
else {
continue outer;
}
}
if( iTopScore < iScore ) {
foundMethod = miFrom;
iTopScore = iScore;
}
}
}
}
return foundMethod;
}
}