/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.nodes; import gw.internal.gosu.parser.ReducedParameterizedDynamicFunctionSymbol; import gw.lang.parser.IReducedDynamicFunctionSymbol; import gw.lang.reflect.*; import gw.lang.reflect.gs.IGosuMethodInfo; import gw.lang.reflect.gs.IGosuClass; import gw.lang.reflect.gs.IGosuEnhancement; import gw.lang.reflect.gs.IGenericTypeVariable; import gw.lang.reflect.gs.IGosuConstructorInfo; import gw.lang.reflect.gs.IExternalSymbolMap; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.IJavaConstructorInfo; import gw.lang.reflect.java.IJavaClassConstructor; import gw.lang.parser.IDynamicFunctionSymbol; import gw.lang.parser.ICapturedSymbol; import gw.lang.ir.IRType; import gw.lang.ir.IRTypeConstants; import gw.internal.gosu.ir.transform.util.AccessibilityUtil; import gw.internal.gosu.ir.transform.util.IRTypeResolver; import gw.internal.gosu.ir.transform.AbstractElementTransformer; import gw.internal.gosu.parser.TypeLord; import gw.internal.gosu.parser.IGosuClassInternal; import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Map; import java.lang.reflect.Constructor; public class IRMethodFromConstructorInfo extends IRFeatureBase implements IRMethod { private IConstructorInfo _constructor; public IRMethodFromConstructorInfo(IConstructorInfo constructor) { _constructor = constructor; } @Override public IRType getReturnType() { return IRTypeConstants.pVOID(); } @Override public List<IRType> getExplicitParameterTypes() { return getBoundedParameterTypeDescriptors(_constructor); } @Override public List<IRType> getAllParameterTypes() { return getMethodDescriptor(_constructor); } @Override public String getName() { return "<init>"; } @Override public IRType getOwningIRType() { return getTrueOwningType(_constructor); } // TODO - AHK - Duplicate of method in AbstractElementTransformer @Override public IType getOwningIType() { IType owningType; if( _constructor instanceof IJavaConstructorInfo) { // We have to get the owner type from the method because it may be // different from the owning type e.g., entity aspects see ContactGosuAspect.AllAdresses IJavaClassConstructor m = ((IJavaConstructorInfo)_constructor).getJavaConstructor(); if( m != null ) { owningType = TypeSystem.get( m.getEnclosingClass() ); } else { owningType = _constructor.getOwnersType(); } } else { owningType = _constructor.getOwnersType(); } return owningType; } @Override public IRelativeTypeInfo.Accessibility getAccessibility() { return AccessibilityUtil.forFeatureInfo(_constructor); } @Override public boolean isStatic() { return false; } // TODO - AHK - Duplicate of method in AbstractElementTransformer public IRType getTargetRootIRType( ) { IRType owner = getOwningIRType(); if( owner instanceof GosuClassIRType && ((GosuClassIRType)owner).getType() instanceof IGosuEnhancement ) { return IRTypeResolver.getDescriptor( ((IGosuEnhancement)((GosuClassIRType)owner).getType()).getEnhancedType() ); } else { return owner; } } @Override public IGenericTypeVariable[] getTypeVariables() { if (_constructor instanceof IGosuConstructorInfo && !IGosuClass.ProxyUtil.isProxy(_constructor.getOwnersType())) { return ((IGosuConstructorInfo) _constructor).getTypeVariables(); } else { return null; } } @Override public IFunctionType getFunctionType() { if (_constructor instanceof IGosuConstructorInfo && !IGosuClass.ProxyUtil.isProxy(_constructor.getOwnersType())) { return (IFunctionType) ((IGosuConstructorInfo) _constructor).getDfs().getType(); } else { return null; } } @Override public boolean isBytecodeMethod() { return (_constructor instanceof IGosuConstructorInfo || _constructor instanceof IJavaConstructorInfo) && !isExternalEntityJavaType( _constructor ); } private static IRType getTrueOwningType( IConstructorInfo mi ) { if( mi instanceof IJavaConstructorInfo) { // We have to get the owner type from the method because it may be different from the owning type e.g., entity aspects see ContactGosuAspect.AllAdresses IJavaClassConstructor m = ((IJavaConstructorInfo)mi).getJavaConstructor(); if( m != null ) { return IRTypeResolver.getDescriptor( m.getEnclosingClass() ); } } return IRTypeResolver.getDescriptor( mi.getOwnersType() ); } @Override public boolean couldHaveTypeVariables() { return _constructor instanceof IGosuMethodInfo && !IGosuClass.ProxyUtil.isProxy(_constructor.getOwnersType()); } public List<IRType> getMethodDescriptor( IConstructorInfo mi ) { List<IRType> paramTypes = new ArrayList<IRType>(); addImplicitConstructorParamTypes( getOwningIType(), paramTypes ); paramTypes.addAll( getBoundedParameterTypeDescriptors( mi ) ); return paramTypes; } private void addImplicitConstructorParamTypes( IType owningType, List<IRType> paramTypes ) { addImplicitOuterParamType( owningType, paramTypes ); addImplicitCapturedSymbolParamTypes( owningType, paramTypes ); addImplicitTypeVariableParamTypes( owningType, paramTypes ); addImplicitEnumParamTypes( owningType, paramTypes ); } private void addImplicitOuterParamType( IType owningType, List<IRType> paramTypes ) { // Outer 'this' if( AbstractElementTransformer.isNonStaticInnerClass( owningType ) ) { paramTypes.add( IRTypeResolver.getDescriptor( AbstractElementTransformer.getRuntimeEnclosingType( owningType ) ) ); } } private void addImplicitCapturedSymbolParamTypes( IType owningType, List<IRType> paramTypes ) { // 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( owningType instanceof IGosuClassInternal && owningType.isValid() ) //&& ((IGosuClassInternal)type).isAnonymous() ) { Map<String, ICapturedSymbol> capturedSymbols = ((IGosuClassInternal)owningType).getCapturedSymbols(); if( capturedSymbols != null ) { for( ICapturedSymbol sym : capturedSymbols.values() ) { paramTypes.add( IRTypeResolver.getDescriptor( sym.getType().getArrayType() ) ); } } } // The external symbols are always treated as captured if (AbstractElementTransformer.requiresExternalSymbolCapture( owningType ) ) { paramTypes.add( IRTypeResolver.getDescriptor( IExternalSymbolMap.class ) ); } } private void addImplicitTypeVariableParamTypes( IType owningType, List<IRType> paramTypes ) { if ( owningType instanceof IGosuClassInternal && !IGosuClassInternal.ProxyUtil.isProxy( owningType ) ) { if (owningType.isParameterizedType()) { owningType = owningType.getGenericType(); } addTypeVariableParameters( paramTypes, owningType.getGenericTypeVariables().length); addTypeVarsFromEnclosingFunctions( (IGosuClassInternal) owningType, paramTypes ); } } private void addTypeVarsFromEnclosingFunctions( IGosuClassInternal gsClass, List<IRType> parameters ) { while( gsClass.isAnonymous() ) { IDynamicFunctionSymbol dfs = AbstractElementTransformer.getEnclosingDFS( gsClass ); if( dfs == null ) { break; } addTypeVariableParameters( parameters, AbstractElementTransformer.getTypeVarsForDFS( dfs ).size() ); gsClass = (IGosuClassInternal)dfs.getGosuClass(); } } private void addImplicitEnumParamTypes( IType owningType, List<IRType> paramTypes ) { // Enums have name and ordinal arguments implicitly added to their constructors if (owningType.isEnum()) { paramTypes.add(IRTypeConstants.STRING()); paramTypes.add(IRTypeConstants.pINT()); } } private List<IRType> getBoundedParameterTypeDescriptors( IConstructorInfo mi ) { if( mi.getParameters().length == 0 ) { return Collections.emptyList(); } if( mi instanceof IJavaConstructorInfo ) { return IRTypeResolver.getDescriptors( ((IJavaConstructorInfo)mi).getJavaConstructor().getParameterTypes() ); } else if( mi instanceof IGosuConstructorInfo ) { IReducedDynamicFunctionSymbol dfs = ((IGosuConstructorInfo)mi).getDfs(); while( dfs instanceof ReducedParameterizedDynamicFunctionSymbol) { ReducedParameterizedDynamicFunctionSymbol pdfs = (ReducedParameterizedDynamicFunctionSymbol)dfs; dfs = pdfs.getBackingDfs(); } List<IRType> boundedTypes = new ArrayList<IRType>( dfs.getArgs().size() ); if( IGosuClass.ProxyUtil.isProxy( dfs.getGosuClass() ) ) { return getBoundedParamTypesFromProxiedClass( dfs ); } for( int i = 0; i < dfs.getArgs().size(); i++ ) { boundedTypes.add( IRTypeResolver.getDescriptor( TypeLord.getDefaultParameterizedTypeWithTypeVars( dfs.getArgs().get(i).getType() ) ) ); } return boundedTypes; } else { return getTypeDescriptors( mi.getParameters() ); } } private List<IRType> getBoundedParamTypesFromProxiedClass( IReducedDynamicFunctionSymbol dfs ) { Constructor m = getJavaConstructorFromProxy( dfs ); return IRTypeResolver.getDescriptors( m.getParameterTypes() ); } private Constructor getJavaConstructorFromProxy( IReducedDynamicFunctionSymbol dfs ) { IType proxyType = dfs.getGosuClass(); IJavaType javaType = (IJavaType)IGosuClass.ProxyUtil.getProxiedType( proxyType ); IType[] boundedDfsParams = new IType[dfs.getArgs().size()]; for( int i = 0; i < boundedDfsParams.length; i++ ) { IType param = dfs.getArgs().get(i).getType(); if( param instanceof ITypeVariableType && param.getEnclosingType() instanceof IGosuClass ) { param = ((ITypeVariableType)param).getBoundingType(); } boundedDfsParams[i] = param; } javaType = (IJavaType)TypeLord.getDefaultParameterizedType( javaType ); IJavaConstructorInfo jmi = (IJavaConstructorInfo)((IRelativeTypeInfo)javaType.getTypeInfo()).getConstructor( javaType, boundedDfsParams ); return jmi.getRawConstructor(); } @Override public boolean isGeneratedEnumMethod() { return false; } }