/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser; import gw.lang.Throws; import gw.lang.parser.IReducedSymbol; import gw.lang.parser.TypeVarToTypeMap; import gw.lang.reflect.FunctionType; import gw.lang.reflect.IAnnotationInfo; import gw.lang.reflect.IExceptionInfo; import gw.lang.reflect.IFeatureInfo; import gw.lang.reflect.IFunctionType; import gw.lang.reflect.IGenericMethodInfo; import gw.lang.reflect.IModifierInfo; import gw.lang.reflect.IParameterInfo; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.gs.IGenericTypeVariable; import gw.lang.reflect.gs.IGosuClass; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** */ public class AbstractGenericMethodInfo extends GosuBaseAttributedFeatureInfo implements IGenericMethodInfo { private static final GosuMethodParamInfo[] EMPTY_PARAMS = new GosuMethodParamInfo[0]; private ReducedDynamicFunctionSymbol _dfs; private GosuMethodParamInfo[] _params; private List<IExceptionInfo> _exceptions; public AbstractGenericMethodInfo( IFeatureInfo container, DynamicFunctionSymbol dfs ) { super( container ); _dfs = (ReducedDynamicFunctionSymbol) dfs.createReducedSymbol(); ((GosuClassTypeInfo)getGosuClass().getTypeInfo()).setModifierInfo( this, dfs.getModifierInfo() ); } public String getName() { return getDfs().getName(); } @Override public String getDisplayName() { return getDfs().getDisplayName(); } @Override public String getDescription() { return getDfs().getFullDescription(); } public boolean isStatic() { return getDfs().isStatic(); } @Override public boolean isPrivate() { return getDfs().isPrivate(); } @Override public boolean isInternal() { return getDfs().isInternal(); } @Override public boolean isProtected() { return getDfs().isProtected(); } @Override public boolean isPublic() { return getDfs().isPublic(); } @Override public boolean isAbstract() { return getDfs().isAbstract(); } @Override public boolean isFinal() { return getDfs().isFinal(); } public IParameterInfo[] getParameters() { if( _params != null ) { return _params; } return _params = makeParamDescriptors( getDfs() ); } public IGenericTypeVariable[] getTypeVariables() { FunctionType funcType = (FunctionType)getDfs().getType(); return funcType.getGenericTypeVariables(); } public IType getParameterizedReturnType( IType... typeParams ) { TypeVarToTypeMap actualParamByVarName = TypeLord.mapTypeByVarName( getOwnersType(), getOwnersType(), true ); int i = 0; for( IGenericTypeVariable tv : getTypeVariables() ) { if( actualParamByVarName.isEmpty() ) { actualParamByVarName = new TypeVarToTypeMap(); } actualParamByVarName.put( tv.getTypeVariableDefinition().getType(), typeParams[i++] ); } return TypeLord.getActualType( ((FunctionType)getDfs().getType()).getReturnType(), actualParamByVarName, true ); } public IType[] getParameterizedParameterTypes( IType... typeParams ) { return getParameterizedParameterTypes2( null, typeParams ); } public IType[] getParameterizedParameterTypes2( IGosuClass ownersType, IType... typeParams ) { IGosuClass ot = ownersType == null ? getOwnersType() : ownersType; TypeVarToTypeMap actualParamByVarName = TypeLord.mapTypeByVarName( ownersType, ownersType, true ); int i = 0; for( IGenericTypeVariable tv : getTypeVariables() ) { if( actualParamByVarName.isEmpty() ) { actualParamByVarName = new TypeVarToTypeMap(); } actualParamByVarName.put( tv.getTypeVariableDefinition().getType(), typeParams[i++] ); } IType[] genParamTypes = ((FunctionType)getDfs().getType()).getParameterTypes(); IType[] paramTypes = new IType[genParamTypes.length]; for( int j = 0; j < genParamTypes.length; j++ ) { paramTypes[j] = TypeLord.getActualType( genParamTypes[j], actualParamByVarName, true ); } return paramTypes; } public TypeVarToTypeMap inferTypeParametersFromArgumentTypes( IType... argTypes ) { return inferTypeParametersFromArgumentTypes2( null, argTypes ); } public TypeVarToTypeMap inferTypeParametersFromArgumentTypes2( IGosuClass owningParameterizedType, IType... argTypes ) { FunctionType funcType = (FunctionType)getDfs().getType(); IType[] genParamTypes = funcType.getParameterTypes(); IGosuClass ownersType = owningParameterizedType == null ? getOwnersType() : owningParameterizedType; TypeVarToTypeMap actualParamByVarName = TypeLord.mapTypeByVarName( ownersType, ownersType, true ); IGenericTypeVariable[] typeVars = getTypeVariables(); for( IGenericTypeVariable tv : typeVars ) { if( actualParamByVarName.isEmpty() ) { actualParamByVarName = new TypeVarToTypeMap(); } actualParamByVarName.put( tv.getTypeVariableDefinition().getType(), tv.getBoundingType() ); } TypeVarToTypeMap map = new TypeVarToTypeMap(); for( int i = 0; i < argTypes.length; i++ ) { if( genParamTypes.length > i ) { TypeLord.inferTypeVariableTypesFromGenParamTypeAndConcreteType( genParamTypes[i], argTypes[i], map ); ensureInferredTypeAssignableToBoundingType( actualParamByVarName, map ); } } return map; } private void ensureInferredTypeAssignableToBoundingType( TypeVarToTypeMap actualParamByVarName, TypeVarToTypeMap map ) { for( Object s : map.keySet() ) { IType inferredType = map.getRaw( s ); IType boundingType = actualParamByVarName.getRaw( s ); if( boundingType != null && !boundingType.isAssignableFrom( inferredType ) ) { map.putRaw( s, boundingType ); } } } public List<IExceptionInfo> getExceptions() { if (_exceptions == null) { _exceptions = Collections.emptyList(); List<IAnnotationInfo> annotations = getAnnotationsOfType(TypeSystem.getByFullName("gw.lang.Throws")); if (annotations != null) { for (IAnnotationInfo annotation : annotations) { Throws throwsInstance = (Throws) annotation.getInstance(); if (throwsInstance != null) { if( _exceptions.isEmpty() ) { _exceptions = new ArrayList<IExceptionInfo>( 2 ); } _exceptions.add(new GosuExceptionInfo(this, throwsInstance.getExceptionType().getName(), throwsInstance.getExceptionDescription())); } } } } return _exceptions; } IGosuClassInternal getGosuClass() { return getOwnersType(); } public ReducedDynamicFunctionSymbol getDfs() { return _dfs; } private GosuMethodParamInfo[] makeParamDescriptors( ReducedDynamicFunctionSymbol dfs ) { if( dfs.getArgs() == null || dfs.getArgs().isEmpty() ) { return EMPTY_PARAMS; } List<IReducedSymbol> params = dfs.getArgs(); GosuMethodParamInfo[] pd = new GosuMethodParamInfo[params.size()]; for( int i = 0; i < pd.length; i++ ) { IReducedSymbol argument = params.get(i); pd[i] = new GosuMethodParamInfo( this, argument, ((IFunctionType)dfs.getType()).getParameterTypes()[i] ); } return pd; } @Override protected List<IGosuAnnotation> getGosuAnnotations() { IModifierInfo modifierInfo = ((GosuClassTypeInfo)getGosuClass().getTypeInfo()).getModifierInfo( this ); return modifierInfo != null ? modifierInfo.getAnnotations() : Collections.<IGosuAnnotation>emptyList(); } public List<IReducedSymbol> getArgs() { return getDfs().getArgs(); } }