/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.nodes;
import gw.lang.reflect.IType;
import gw.lang.reflect.IRelativeTypeInfo;
import gw.lang.reflect.IFunctionType;
import gw.lang.reflect.gs.IGenericTypeVariable;
import gw.lang.reflect.gs.IGosuEnhancement;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.reflect.gs.IExternalSymbolMap;
import gw.lang.parser.ICapturedSymbol;
import gw.lang.ir.IRType;
import gw.lang.ir.IRTypeConstants;
import gw.internal.gosu.parser.DynamicFunctionSymbol;
import gw.internal.gosu.parser.IGosuClassInternal;
import gw.internal.gosu.ir.transform.util.AccessibilityUtil;
import gw.internal.gosu.ir.transform.util.IRTypeResolver;
import gw.internal.gosu.ir.transform.AbstractElementTransformer;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
public class IRMethodForConstructorSymbol implements IRMethod {
private IType _gosuClass;
private DynamicFunctionSymbol _dfs;
private int _numberOfTypeParameters;
public IRMethodForConstructorSymbol(IType gosuClass, DynamicFunctionSymbol dfs, int numberOfTypeParameters) {
_gosuClass = gosuClass;
_dfs = dfs;
_numberOfTypeParameters = numberOfTypeParameters;
}
@Override
public IRType getReturnType() {
return IRTypeConstants.pVOID();
}
@Override
public List<IRType> getExplicitParameterTypes() {
List<IRType> explicitParameterTypes = new ArrayList<IRType>();
for (IType declaredParam : _dfs.getArgTypes() ) {
explicitParameterTypes.add( IRTypeResolver.getDescriptor( declaredParam ) );
}
return explicitParameterTypes;
}
@Override
public List<IRType> getAllParameterTypes() {
return getConstructorParamTypes( _dfs.getArgTypes(), _numberOfTypeParameters, _gosuClass );
}
@Override
public String getName() {
return "<init>";
}
@Override
public IRType getOwningIRType() {
return IRTypeResolver.getDescriptor(_gosuClass);
}
@Override
public IType getOwningIType() {
return _gosuClass;
}
@Override
public IRelativeTypeInfo.Accessibility getAccessibility() {
return AccessibilityUtil.forSymbol( _dfs );
}
@Override
public boolean isStatic() {
return false;
}
@Override
public IRType getTargetRootIRType() {
return getOwningIRType();
}
@Override
public IGenericTypeVariable[] getTypeVariables() {
return null;
}
@Override
public IFunctionType getFunctionType() {
return (IFunctionType) _dfs.getType();
}
@Override
public boolean isGeneratedEnumMethod()
{
return false;
}
@Override
public boolean isBytecodeMethod() {
return true;
}
/**
* Parameters are order like so:
* ctor( [OuterThis,] [This,] [CapturedSymbols,] [TypeParams,] [EnumParams,] params )
*/
protected List<IRType> getConstructorParamTypes( IType[] declaredParams, int iTypeParams, IType type )
{
List<IRType> params = new ArrayList<IRType>();
// Insert outer 'this'
if( isNonStaticInnerClass( type ) )
{
params.add( IRTypeResolver.getDescriptor( getRuntimeEnclosingType( type ) ) );
}
// Insert captured symbols
// Don't attempt to get captured symbols if the type isn't valid; it'll just throw and result in a cascading break
if( type instanceof IGosuClassInternal && type.isValid() ) //&& ((IGosuClassInternal)type).isAnonymous() )
{
Map<String, ICapturedSymbol> capturedSymbols = ((IGosuClassInternal)type).getCapturedSymbols();
if( capturedSymbols != null )
{
for( ICapturedSymbol sym : capturedSymbols.values() )
{
params.add( IRTypeResolver.getDescriptor( sym.getType().getArrayType() ) );
}
}
}
// The external symbols are always treated as captured
if (AbstractElementTransformer.requiresExternalSymbolCapture( type ) ) {
params.add( IRTypeResolver.getDescriptor( IExternalSymbolMap.class ) );
}
// Insert type-parameter types
if( iTypeParams > 0 )
{
for( int i = 0; i < iTypeParams; i++ )
{
params.add(IRTypeConstants.ITYPE());
}
}
// Enums have name and ordinal arguments implicitly added to their constructors
if (type.isEnum()) {
params.add(IRTypeConstants.STRING());
params.add(IRTypeConstants.pINT());
}
// Add declared parameters
for (IType declaredParam : declaredParams ) {
params.add( IRTypeResolver.getDescriptor( declaredParam ) );
}
return params;
}
/**
* @param type
* @return the actual runtime enclosing type of this type (handles the case of enhancements, when
* the "enclosing type" at runtime will be the enhanced object, rather than the acutal enclosing type)
*/
public IType getRuntimeEnclosingType( IType type )
{
IType enclosingType = maybeUnwrapProxy( type.getEnclosingType() );
if( enclosingType instanceof IGosuEnhancement)
{
IGosuEnhancement enhancement = (IGosuEnhancement)enclosingType;
enclosingType = enhancement.getEnhancedType();
}
return enclosingType;
}
private IType maybeUnwrapProxy( IType type )
{
if( type != null && type.isParameterizedType() )
{
type = type.getGenericType();
}
return type == null ? null : IGosuClass.ProxyUtil.getProxiedType( type );
}
public boolean isNonStaticInnerClass( IType type )
{
return (type instanceof IGosuClass) && type.getEnclosingType() != null && !((IGosuClass)type).isStatic();
}
@Override
public boolean couldHaveTypeVariables() {
return true;
}
}