/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.nodes;
import gw.config.CommonServices;
import gw.internal.gosu.parser.IGosuTemplateInternal;
import gw.lang.reflect.IFeatureInfo;
import gw.lang.reflect.gs.IGosuEnhancement;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.reflect.gs.IExternalSymbolMap;
import gw.lang.reflect.gs.IGosuProgram;
import gw.lang.reflect.IType;
import gw.lang.reflect.IFunctionType;
import gw.lang.reflect.IParameterInfo;
import gw.lang.reflect.IPropertyInfo;
import gw.lang.reflect.java.IJavaType;
import gw.lang.reflect.java.IJavaFieldPropertyInfo;
import gw.lang.ir.IRType;
import gw.lang.ir.IRTypeConstants;
import gw.internal.gosu.ir.transform.util.IRTypeResolver;
import gw.internal.gosu.parser.IGosuClassInternal;
import gw.internal.gosu.parser.TypeLord;
import gw.internal.gosu.parser.statements.VarStatement;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Field;
public class IRFeatureBase {
protected IRType maybeReifyFieldType( IType owner, String name, IType originalType )
{
IRType symType;
if( owner.isParameterizedType() )
{
if( owner instanceof IGosuClassInternal)
{
IType reifiedOwner = TypeLord.getDefaultParameterizedType( owner.getGenericType() );
VarStatement field = ((IGosuClassInternal) reifiedOwner).getMemberField( name );
symType = IRTypeResolver.getDescriptor( field.getType() );
}
else if( owner instanceof IJavaType)
{
IJavaType javaType = (IJavaType)owner;
try
{
Field field = javaType.getIntrinsicClass().getField( name );
symType = IRTypeResolver.getDescriptor( field.getType() );
}
catch( NoSuchFieldException e )
{
throw new RuntimeException( e );
}
}
else
{
throw new IllegalArgumentException( "Cannot reify field for type " + owner.getName() + " whose metatype is " + owner.getClass() );
}
}
else
{
symType = IRTypeResolver.getDescriptor( originalType );
}
return symType;
}
protected String resolveFieldName( IType owner, String name )
{
// If we have a field on a Java class, its name could have been munged, i.e.
// $100 becomes _100 in the type info. So we need to unwrap proxies to see
// if we have a java class, and if so get the underlying java property. If
// that property happens to be a field, then we get the underlying field name.
if ( IGosuClass.ProxyUtil.isProxy( owner ) ) {
owner = IGosuClass.ProxyUtil.getProxiedType( owner );
}
if( owner instanceof IJavaType) {
IPropertyInfo property = owner.getTypeInfo().getProperty(name);
if ( property instanceof IJavaFieldPropertyInfo ) {
return ((IJavaFieldPropertyInfo) property).getField().getName();
}
}
return name;
}
protected void addImplicitParameters( IType owner, IFunctionType functionType, boolean bStatic, List<IRType> params ) {
addImplicitEnhancementParams( owner, bStatic, params );
addFunctionTypeParams( functionType, params );
addImplicitExternalSymbolMapParam( owner, bStatic, params );
}
private void addImplicitEnhancementParams( IType owner, boolean bStatic, List<IRType> params )
{
if ( owner instanceof IGosuEnhancement && !bStatic ) {
params.add( IRTypeResolver.getDescriptor( ( (IGosuEnhancement) owner).getEnhancedType() ) );
if( owner.isParameterizedType() )
{
addTypeVariableParameters( params, owner.getTypeParameters().length );
}
else if( owner.isGenericType() )
{
addTypeVariableParameters( params, owner.getGenericTypeVariables().length );
}
}
}
private void addImplicitExternalSymbolMapParam( IType owner, boolean bStatic, List<IRType> params )
{
if( !isImplicitMethod() )
{
if( owner instanceof IGosuProgram && !(owner instanceof IGosuTemplateInternal) )
{
params.add( IRTypeResolver.getDescriptor( IExternalSymbolMap.class ) );
}
else if( owner != null && bStatic )
{
addImplicitExternalSymbolMapParam( owner.getEnclosingType(), bStatic, params );
}
}
}
protected boolean isImplicitMethod() {
return false;
}
private void addFunctionTypeParams( IFunctionType functionType, List<IRType> params )
{
if (functionType == null) {
return;
}
if( functionType.isParameterizedType() )
{
addTypeVariableParameters( params, functionType.getTypeParameters().length );
}
else if( functionType.isGenericType() )
{
addTypeVariableParameters( params, functionType.getGenericTypeVariables().length );
}
}
protected void addTypeVariableParameters( List<IRType> params, int number ) {
for( int i = 0; i < number; i++ )
{
params.add(IRTypeConstants.ITYPE());
}
}
protected List<IRType> getTypeDescriptors( IParameterInfo[] parameters )
{
List<IRType> paramTypes = new ArrayList<IRType>(parameters.length);
for( int i = 0; i < parameters.length; i++ )
{
paramTypes.add( IRTypeResolver.getDescriptor( parameters[i].getFeatureType() ) );
}
return paramTypes;
}
public static boolean isExternalEntityJavaType( IFeatureInfo fi )
{
return fi.getOwnersType() instanceof IJavaType &&
((IJavaType)fi.getOwnersType()).getBackingClass() != null &&
CommonServices.getEntityAccess().isExternal( ((IJavaType)fi.getOwnersType()).getBackingClass() );
}
}