/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.lang.reflect;
import gw.config.CommonServices;
import gw.lang.parser.CICS;
import gw.lang.reflect.gs.IGenericTypeVariable;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.reflect.gs.IGosuEnhancement;
import gw.lang.reflect.java.IJavaMethodInfo;
import gw.lang.reflect.java.JavaTypes;
import gw.lang.reflect.module.IModule;
import gw.util.GosuExceptionUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings({"unchecked"})
public class FeatureManager<T extends CharSequence> {
private final boolean _caseSensitive;
private final boolean _addObjectMethods;
private IRelativeTypeInfo _typeInfo;
private volatile Map<IModule, InitState> _methodsInitialized = new HashMap<IModule, InitState>();
private volatile Map<IModule, InitState> _propertiesInitialized = new HashMap<IModule, InitState>();
private volatile InitState _ctorsInitialized = InitState.NotInitialized;
private Map<IModule, PropertyNameMap<T>[]> _properties = new HashMap<IModule, PropertyNameMap<T>[]>();
private Map<IModule, MethodList[]> _methods = new HashMap<IModule, MethodList[]>();
private List<IConstructorInfo>[] _constructors = new List[IRelativeTypeInfo.Accessibility_Size];
private String _superPropertyPrefix;
private IType _supertypeToCopyPropertiesFrom;
public FeatureManager(IRelativeTypeInfo typeInfo, boolean caseSensitive) {
this(typeInfo, caseSensitive, false);
}
public FeatureManager(IRelativeTypeInfo typeInfo, boolean caseSensitive, boolean addObjectMethods) {
_typeInfo = typeInfo;
_caseSensitive = caseSensitive;// && !ILanguageLevel.Util.STANDARD_GOSU();
_addObjectMethods = addObjectMethods;
}
public static IRelativeTypeInfo.Accessibility getAccessibilityForClass( IType ownersClass, IType whosAskin )
{
if( TypeSystem.isIncludeAll() )
{
return IRelativeTypeInfo.Accessibility.PRIVATE;
}
if( ownersClass == null || whosAskin == null )
{
return IRelativeTypeInfo.Accessibility.PUBLIC;
}
if( getTopLevelTypeName( whosAskin ).equals( getTopLevelTypeName( ownersClass ) ) )
{
// Implies private members, which means everything.
return IRelativeTypeInfo.Accessibility.PRIVATE;
}
else if( Modifier.isPrivate( ownersClass.getModifiers() ) )
{
return IRelativeTypeInfo.Accessibility.NONE;
}
else if( isInSameNamespace( ownersClass, whosAskin ) )
{
return IRelativeTypeInfo.Accessibility.INTERNAL;
}
else if( Modifier.isInternal( ownersClass.getModifiers() ) )
{
return IRelativeTypeInfo.Accessibility.NONE;
}
else if( isInEnclosingClassHierarchy( ownersClass, whosAskin ) )
{
return IRelativeTypeInfo.Accessibility.PROTECTED;
}
return IRelativeTypeInfo.Accessibility.PUBLIC;
}
public static boolean isInSameNamespace(IType ownersClass, IType whosAskin) {
String whosAskinNamespace = getTopLevelEnclosingClassNamespace(whosAskin);
return whosAskinNamespace != null &&
whosAskinNamespace.equals( getTopLevelEnclosingClassNamespace( ownersClass ) );
}
private static String getTopLevelEnclosingClassNamespace(IType type) {
IType topLevelClass = type;
while (topLevelClass.getEnclosingType() != null) {
topLevelClass = topLevelClass.getEnclosingType();
}
return topLevelClass.getNamespace();
}
public static boolean isInEnclosingClassHierarchy(IType ownersClass, IType whosAskin) {
return whosAskin != null && ownersClass != null &&
(isInHierarchy(ownersClass, whosAskin) ||
isInEnhancedTypesHierarchy(ownersClass, whosAskin) ||
isInEnclosingClassHierarchy(ownersClass.getEnclosingType(), whosAskin) ||
isInEnclosingClassHierarchy(ownersClass, whosAskin.getEnclosingType()));
}
protected static boolean isInEnhancedTypesHierarchy(IType ownersClass, IType whosAskin) {
return (whosAskin instanceof IGosuEnhancement &&
((IGosuEnhancement)whosAskin).getEnhancedType() != null &&
ownersClass.isAssignableFrom(((IGosuEnhancement) whosAskin).getEnhancedType()));
}
protected static boolean isInHierarchy(IType ownersClass, IType whosAskin) {
return ownersClass.isAssignableFrom(whosAskin) ||
(ownersClass instanceof IGosuClass && ((IGosuClass) ownersClass).isSubClass( whosAskin ));
}
private static String getTopLevelTypeName( IType type )
{
while( type.getEnclosingType() != null )
{
type = TypeSystem.getPureGenericType( type.getEnclosingType() );
}
return TypeSystem.getPureGenericType( type ).getName();
}
public static boolean areInvocableTypesAssignable(IInvocableType iT0, IInvocableType iT1)
{
return iT0.isAssignableFrom(iT1) || iT1.isAssignableFrom(iT0);
}
public static boolean isFeatureAccessible(IAttributedFeatureInfo property, IRelativeTypeInfo.Accessibility accessibility) {
boolean isAccessible = false;
switch (accessibility) {
case NONE:
break;
case PUBLIC:
if (property.isPublic()) {
isAccessible = true;
}
break;
case PROTECTED:
if (property.isPublic() || property.isProtected()) {
isAccessible = true;
}
break;
case INTERNAL:
if (property.isPublic() || property.isInternal() || property.isProtected()) {
isAccessible = true;
}
break;
case PRIVATE:
if (property.isPublic() || property.isInternal() || property.isProtected() || property.isPrivate()) {
isAccessible = true;
}
break;
}
return isAccessible;
}
public void clear() {
_methodsInitialized = new HashMap<IModule, InitState>();
_propertiesInitialized = new HashMap<IModule, InitState>();
_ctorsInitialized = InitState.NotInitialized;
clearMaps();
}
private void clearMaps() {
for(PropertyNameMap<T>[] properties : _properties.values()) {
for (int i = 0; i < properties.length; i++) {
properties[i] = null;
}
}
for (int i = 0; i < _constructors.length; i++) {
_constructors[i] = null;
}
for(MethodList[] methods : _methods.values()) {
for (int i = 0; i < methods.length; i++) {
methods[i] = null;
}
}
}
private void clearProperties(IModule module) {
PropertyNameMap<T>[] properties = _properties.get(module);
if(properties != null) {
for (int i = 0; i < properties.length; i++) {
properties[i] = null;
}
}
}
private void clearMethods(IModule module) {
MethodList[] methods = _methods.get(module);
if(methods != null) {
for (int i = 0; i < methods.length; i++) {
methods[i] = null;
}
}
}
private void clearCtors() {
for (int i = 0; i < _constructors.length; i++) {
_constructors[i] = null;
}
}
public List<IPropertyInfo> getProperties( IRelativeTypeInfo.Accessibility accessibility ) {
maybeInitProperties();
PropertyNameMap<T>[] arr = _properties.get( TypeSystem.getCurrentModule() );
if( arr == null )
{
return Collections.emptyList();
}
PropertyNameMap<T> props = arr[accessibility.ordinal()];
return (List<IPropertyInfo>) (props == null ? Collections.emptyList() : props.values());
}
public IPropertyInfo getProperty( IRelativeTypeInfo.Accessibility accessibility, CharSequence propName ) {
maybeInitProperties();
PropertyNameMap<T>[] arr = _properties.get( TypeSystem.getCurrentModule() );
if( arr == null )
{
return null;
}
PropertyNameMap<T> accessMap = arr[accessibility.ordinal()];
return accessMap == null ? null : accessMap.get(convertCharSequenceToCorrectSensitivity(propName));
}
private T convertCharSequenceToCorrectSensitivity(CharSequence propName) {
return (T) (_caseSensitive ? propName == null ? "": propName.toString() : CICS.get( propName ));
}
@SuppressWarnings({"unchecked"})
public MethodList getMethods( IRelativeTypeInfo.Accessibility accessibility) {
maybeInitMethods();
MethodList[] arr = _methods.get( TypeSystem.getCurrentModule() );
if( arr == null )
{
return MethodList.EMPTY;
}
MethodList iMethodInfos = arr[accessibility.ordinal()];
return iMethodInfos == null ? MethodList.EMPTY : iMethodInfos;
}
public IMethodInfo getMethod( IRelativeTypeInfo.Accessibility accessibility, CharSequence methodName, IType... params ) {
maybeInitMethods();
return ITypeInfo.FIND.method( getMethods( accessibility ), methodName, params );
}
@SuppressWarnings({"unchecked"})
public List<? extends IConstructorInfo> getConstructors( IRelativeTypeInfo.Accessibility accessibility ) {
maybeInitConstructors();
List<IConstructorInfo> list = _constructors[accessibility.ordinal()];
return (List<IConstructorInfo>) (list == null ? Collections.emptyList() : list);
}
public IConstructorInfo getConstructor( IRelativeTypeInfo.Accessibility accessibility, IType[] params ) {
maybeInitConstructors();
return ITypeInfo.FIND.constructor( getConstructors(accessibility), params );
}
@SuppressWarnings({"ConstantConditions"})
protected void maybeInitMethods() {
IModule module = TypeSystem.getCurrentModule();
if (module == null) {
throw new NullPointerException("Cannot init the FeatureManager with no current module.");
}
if (_methodsInitialized.get(module) != InitState.Initialized && _methodsInitialized.get(module) != InitState.ERROR) {
TypeSystem.lock();
try {
if (_methodsInitialized.get(module) != InitState.Initialized) {
if (_methodsInitialized.get(module) == InitState.Initializing) {
throw new IllegalStateException("Methods for " + _typeInfo.getOwnersType() + " are cyclic.");
}
_methodsInitialized.put(module, InitState.Initializing);
clearMethods(module);
try {
MethodList[] methods = new MethodList[IRelativeTypeInfo.Accessibility_Size];
{
MethodList privateMethods = new MethodList();
if( _addObjectMethods ) {
mergeMethods( privateMethods, convertType( JavaTypes.OBJECT() ), false );
}
if( _typeInfo == null ) {
throw new IllegalStateException( "Null TypeInfo" );
}
if( _typeInfo.getOwnersType() == null ) {
throw new IllegalStateException( "null owner" );
}
if( _typeInfo.getOwnersType().getInterfaces() == null ) {
throw new IllegalStateException( "null interfaces for " + _typeInfo.getOwnersType().getName() );
}
for (IType type : _typeInfo.getOwnersType().getInterfaces()) {
mergeMethods(privateMethods, convertType(type), false);
}
if ( _typeInfo.getOwnersType().getSupertype() != null) {
mergeMethods(privateMethods, convertType( _typeInfo.getOwnersType().getSupertype()), true);
}
List<? extends IMethodInfo> declaredMethods = _typeInfo.getDeclaredMethods();
for (IMethodInfo methodInfo : declaredMethods) {
mergeMethod(privateMethods, methodInfo, true);
}
addEnhancementMethods(privateMethods);
privateMethods.trimToSize();
// privateMethods = Collections.unmodifiableList(privateMethods);
// The size checking madness is to save memory. If the lists/maps are the same then reuse.
methods[IRelativeTypeInfo.Accessibility.PRIVATE.ordinal()] = privateMethods;
methods[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()] = privateMethods.filterMethods(IRelativeTypeInfo.Accessibility.PROTECTED);
if (methods[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()].size() == privateMethods.size()) {
methods[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()] = privateMethods;
}
methods[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()] = privateMethods.filterMethods(IRelativeTypeInfo.Accessibility.INTERNAL);
if (methods[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()].size() == methods[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()].size()) {
methods[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()] = methods[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()];
}
methods[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()] = privateMethods.filterMethods(IRelativeTypeInfo.Accessibility.PUBLIC);
if (methods[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()].size() == methods[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()].size()) {
methods[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()] = methods[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()];
}
methods[IRelativeTypeInfo.Accessibility.NONE.ordinal()] = MethodList.EMPTY;
}
_methods.put(module, methods);
_methodsInitialized.put(module, InitState.Initialized);
} finally {
if (_methodsInitialized.get(module) != InitState.Initialized) {
_methodsInitialized.put(module, InitState.ERROR);
}
}
}
} catch ( Exception ex ) {
ex.printStackTrace(); // exception is swallowed by source diff handler? print it again here
throw GosuExceptionUtil.forceThrow( ex, _typeInfo.getOwnersType().getName() );
} finally {
TypeSystem.unlock();
}
}
}
@SuppressWarnings({"ConstantConditions"})
protected void maybeInitProperties() {
maybeInitMethods(); // because properties depend on methods for their getter or setter method !
IModule module = TypeSystem.getCurrentModule();
if (module == null) {
throw new NullPointerException("Cannot init the FeatureManager with no current module.");
}
if (_propertiesInitialized.get(module) != InitState.Initialized && _propertiesInitialized.get(module) != InitState.ERROR) {
TypeSystem.lock();
try {
if (_propertiesInitialized.get(module) != InitState.Initialized) {
if (_propertiesInitialized.get(module) == InitState.Initializing) {
throw new IllegalStateException("Properties for " + _typeInfo.getOwnersType() + " are cyclic.");
}
_propertiesInitialized.put(module, InitState.Initializing);
clearProperties(module);
try {
PropertyNameMap<T>[] properties = new PropertyNameMap[IRelativeTypeInfo.Accessibility_Size];
{
PropertyNameMap privateProps = new PropertyNameMap();
for (IType type : _typeInfo.getOwnersType().getInterfaces()) {
mergeProperties(privateProps, convertType(type), false);
}
IType supertype = _typeInfo.getOwnersType().getSupertype();
if ( supertype != null ) {
mergeProperties( privateProps, convertType( supertype ), true );
}
List<IPropertyInfo> declaredProperties = (List<IPropertyInfo>) _typeInfo.getDeclaredProperties();
for (IPropertyInfo property : declaredProperties) {
mergeProperty(privateProps, property, true);
}
addEnhancementProperties(privateProps, _caseSensitive);
privateProps.freeze();
// The size checking madness is to save memory. If the lists/maps are the same then reuse.
properties[IRelativeTypeInfo.Accessibility.PRIVATE.ordinal()] = privateProps;
properties[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()] = convertToMap(filterFeatures(privateProps.values(), IRelativeTypeInfo.Accessibility.PROTECTED));
if (properties[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()].size() == privateProps.size()) {
properties[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()] = privateProps;
}
properties[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()] = convertToMap(filterFeatures(privateProps.values(), IRelativeTypeInfo.Accessibility.INTERNAL));
if (properties[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()].size() == properties[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()].size()) {
properties[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()] = properties[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()];
}
properties[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()] = convertToMap(filterFeatures(privateProps.values(), IRelativeTypeInfo.Accessibility.PUBLIC));
if (properties[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()].size() == properties[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()].size()) {
properties[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()] = properties[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()];
}
properties[IRelativeTypeInfo.Accessibility.NONE.ordinal()] = new PropertyNameMap();
}
_properties.put(module, properties);
_propertiesInitialized.put(module, InitState.Initialized);
} finally {
if (_propertiesInitialized.get(module) != InitState.Initialized) {
_propertiesInitialized.put(module, InitState.ERROR);
}
}
}
} catch ( Exception ex ) {
ex.printStackTrace(); // exception is swallowed by source diff handler? print it again here
throw GosuExceptionUtil.forceThrow( ex, _typeInfo.getOwnersType().getName() );
} finally {
TypeSystem.unlock();
}
}
}
@SuppressWarnings({"ConstantConditions"})
protected void maybeInitConstructors() {
if (_ctorsInitialized != InitState.Initialized && _ctorsInitialized != InitState.ERROR) {
TypeSystem.lock();
try {
if (_ctorsInitialized != InitState.Initialized) {
if (_ctorsInitialized == InitState.Initializing) {
throw new IllegalStateException("Constructors for " + _typeInfo.getOwnersType() + " are cyclic.");
}
_ctorsInitialized = InitState.Initializing;
clearCtors();
try {
if(_ctorsInitialized != InitState.Initialized && _ctorsInitialized != InitState.ERROR) {
clearCtors();
try {
List<IConstructorInfo>[] constructors = new List[IRelativeTypeInfo.Accessibility_Size];
{
List<IConstructorInfo> privateConstructors = new ArrayList<IConstructorInfo>( _typeInfo.getDeclaredConstructors());
((ArrayList) privateConstructors).trimToSize();
privateConstructors = Collections.unmodifiableList(privateConstructors);
constructors[IRelativeTypeInfo.Accessibility.PRIVATE.ordinal()] = Collections.unmodifiableList(privateConstructors);
constructors[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()] = Collections.unmodifiableList((List<IConstructorInfo>) filterFeatures(privateConstructors, IRelativeTypeInfo.Accessibility.PROTECTED));
if (constructors[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()].size() == privateConstructors.size()) {
constructors[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()] = privateConstructors;
}
constructors[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()] = Collections.unmodifiableList((List<IConstructorInfo>) filterFeatures(privateConstructors, IRelativeTypeInfo.Accessibility.INTERNAL));
if (constructors[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()].size() == constructors[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()].size()) {
constructors[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()] = constructors[IRelativeTypeInfo.Accessibility.PROTECTED.ordinal()];
}
constructors[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()] = Collections.unmodifiableList((List<IConstructorInfo>) filterFeatures(privateConstructors, IRelativeTypeInfo.Accessibility.PUBLIC));
if (constructors[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()].size() == constructors[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()].size()) {
constructors[IRelativeTypeInfo.Accessibility.PUBLIC.ordinal()] = constructors[IRelativeTypeInfo.Accessibility.INTERNAL.ordinal()];
}
constructors[IRelativeTypeInfo.Accessibility.NONE.ordinal()] = Collections.emptyList();
}
_constructors = constructors;
_ctorsInitialized = InitState.Initialized;
} finally {
if(_ctorsInitialized != InitState.Initialized) {
_ctorsInitialized = InitState.ERROR;
}
}
}
_ctorsInitialized = InitState.Initialized;
} finally {
if (_ctorsInitialized != InitState.Initialized) {
_ctorsInitialized = InitState.ERROR;
}
}
}
} catch ( Exception ex ) {
// ex.printStackTrace(); // exception is swallowed by source diff handler? print it again here
throw GosuExceptionUtil.forceThrow( ex, _typeInfo.getOwnersType().getName() );
} finally {
TypeSystem.unlock();
}
}
}
protected IType convertType(IType type) {
return type;
}
protected void addEnhancementMethods(List<IMethodInfo> privateMethods) {
CommonServices.getEntityAccess().addEnhancementMethods(_typeInfo.getOwnersType(), privateMethods );
}
protected void addEnhancementProperties(PropertyNameMap<T> privateProps, boolean caseSensitive) {
CommonServices.getEntityAccess().addEnhancementProperties(_typeInfo.getOwnersType(), privateProps, caseSensitive );
}
public void setSuperPropertyPrefix( String superPropertyPrefix ) {
_superPropertyPrefix = superPropertyPrefix;
}
public void setSupertypeToCopyPropertiesFrom( IType supertypeToCopyPropertiesFrom ) {
_supertypeToCopyPropertiesFrom = supertypeToCopyPropertiesFrom;
}
private PropertyNameMap<T> convertToMap(List<IPropertyInfo> features) {
PropertyNameMap<T> ret = new PropertyNameMap();
for (IPropertyInfo feature : features) {
ret.put(convertCharSequenceToCorrectSensitivity(feature.getName()), feature);
}
ret.freeze();
return ret;
}
private List filterFeatures(List props, IRelativeTypeInfo.Accessibility accessibility) {
ArrayList<IFeatureInfo> ret = new ArrayList<IFeatureInfo>();
for (Object o : props) {
IAttributedFeatureInfo property = (IAttributedFeatureInfo) o;
if (isFeatureAccessible(property, accessibility)) {
ret.add(property);
}
}
ret.trimToSize();
return ret;
}
protected void mergeProperties(PropertyNameMap<T> props, IType type, boolean replace) {
if( type != null )
{
List<? extends IPropertyInfo> propertyInfos;
if (type.getTypeInfo() instanceof IRelativeTypeInfo) {
propertyInfos = ((IRelativeTypeInfo) type.getTypeInfo()).getProperties( _typeInfo.getOwnersType());
} else {
propertyInfos = type.getTypeInfo().getProperties();
}
for (IPropertyInfo propertyInfo : propertyInfos) {
IType ownersType = propertyInfo.getOwnersType();
if ( _supertypeToCopyPropertiesFrom == null || ownersType.isAssignableFrom( _supertypeToCopyPropertiesFrom ) || ownersType instanceof IGosuEnhancement ) {
mergeProperty( props, propertyInfo, replace );
}
}
}
}
protected void mergeProperty(PropertyNameMap<T> props, IPropertyInfo propertyInfo, boolean replace) {
boolean prependPrefix = _superPropertyPrefix != null && ! propertyInfo.getOwnersType().equals( _typeInfo.getOwnersType() );
T cs = convertCharSequenceToCorrectSensitivity( prependPrefix ? ( _superPropertyPrefix + propertyInfo.getName() ) : propertyInfo.getName() );
if (replace || !props.containsKey(cs)) {
if ( prependPrefix ) {
props.put( cs, new PropertyInfoDelegate( propertyInfo.getContainer(), propertyInfo, cs.toString() ) );
}
else {
props.put(cs, propertyInfo);
}
}
}
protected void mergeMethods(List<IMethodInfo> methods, IType type, boolean replace) {
List<? extends IMethodInfo> methodInfos;
if (type != null && !TypeSystem.isDeleted(type)) {
if (type.getTypeInfo() instanceof IRelativeTypeInfo) {
methodInfos = ((IRelativeTypeInfo) type.getTypeInfo()).getMethods( _typeInfo.getOwnersType());
} else {
methodInfos = type.getTypeInfo().getMethods();
}
for (IMethodInfo methodInfo : methodInfos) {
mergeMethod(methods, methodInfo, replace);
}
}
}
protected void mergeMethod(List<IMethodInfo> methods, IMethodInfo thisMethodInfo, boolean replace) {
IType[] paramTypes = removeGenericMethodParameters(thisMethodInfo);
boolean add = true;
int replacementIndex = -1;
for (int i = 0; i < methods.size(); i++) {
IMethodInfo superMethodInfo = methods.get(i);
replacementIndex++;
if (isOverride(thisMethodInfo, superMethodInfo)) {
IType[] superParamTypes;
superParamTypes = removeGenericMethodParameters(superMethodInfo);
if (argsEqual(superParamTypes, paramTypes)) {
if (replace) {
methods.set(replacementIndex, thisMethodInfo);
}
add = false;
break;
}
}
}
if (add) {
methods.add(thisMethodInfo);
}
}
private boolean isOverride(IMethodInfo thisMethodInfo, IMethodInfo superMethodInfo) {
// if( ILanguageLevel.Util.STANDARD_GOSU() ) {
return superMethodInfo.getDisplayName().equals(thisMethodInfo.getDisplayName());
// }
// return superMethodInfo.getDisplayName().equalsIgnoreCase(thisMethodInfo.getDisplayName());
}
private IType[] removeGenericMethodParameters(IMethodInfo thisMethodInfo) {
IParameterInfo[] parameters;
if (thisMethodInfo instanceof IJavaMethodInfo) {
parameters = ((IJavaMethodInfo) thisMethodInfo).getGenericParameters();
} else {
parameters = thisMethodInfo.getParameters();
}
IType[] paramTypes = new IType[parameters.length];
List<IType> methodTypeVars = null;
if (thisMethodInfo instanceof IGenericMethodInfo) {
IGenericTypeVariable[] typeVariables = ((IGenericMethodInfo) thisMethodInfo).getTypeVariables();
if (typeVariables != null && typeVariables.length > 0) {
methodTypeVars = new ArrayList<IType>();
for (IGenericTypeVariable typeVariable : typeVariables) {
ITypeVariableType typeVarType = typeVariable.getTypeVariableDefinition().getType();
methodTypeVars.add(typeVarType);
}
}
}
for (int i = 0; i < parameters.length; i++) {
IParameterInfo parameter = parameters[i];
IType featureType = parameter.getFeatureType();
if (methodTypeVars != null) {
featureType = TypeSystem.boundTypes(featureType, methodTypeVars);
}
paramTypes[i] = featureType;
}
return paramTypes;
}
protected boolean areMethodParamsEqual(IType thisMethodParamType, IType superMethodParamType) {
return thisMethodParamType.equals(superMethodParamType);
}
private boolean argsEqual(IType[] parameters, IType[] parameters1) {
if (parameters.length == parameters1.length) {
for (int i = 0; i < parameters.length; i++) {
IType parameter = parameters[i];
if ( !areMethodParamsEqual(parameter, parameters1[i]) ) {
return false;
}
}
return true;
}
return false;
}
public String toString() {
return _typeInfo.getOwnersType().getName();
}
private enum InitState {
NotInitialized,
Initializing,
ERROR, Initialized
}
}