/* * 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.IAspectMethodInfoDelegate; import gw.lang.reflect.IRelativeTypeInfo; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.IMethodInfoDelegate; import gw.lang.reflect.IMetaType; import gw.lang.reflect.ITypeVariableType; import gw.lang.reflect.IFunctionType; 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.java.IJavaMethodInfo; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.JavaTypes; import gw.lang.reflect.java.IJavaClassMethod; import gw.lang.reflect.java.IJavaClassInfo; import gw.lang.ir.IRType; import gw.internal.gosu.ir.transform.util.AccessibilityUtil; import gw.internal.gosu.ir.transform.util.IRTypeResolver; import gw.internal.gosu.parser.TypeLord; import java.util.List; import java.util.ArrayList; import java.util.Collections; public class IRMethodFromMethodInfo extends IRFeatureBase implements IRMethod { private IMethodInfo _originalMethod; private IMethodInfo _terminalMethod; private IFunctionType _functionType; public IRMethodFromMethodInfo(IMethodInfo originalMethod, IFunctionType functionType) { _originalMethod = originalMethod; _terminalMethod = originalMethod; while (_terminalMethod instanceof IMethodInfoDelegate && !(_terminalMethod instanceof IAspectMethodInfoDelegate)) { _terminalMethod = ((IMethodInfoDelegate) _terminalMethod).getSource(); } _functionType = functionType; } public IMethodInfo getOriginalMethod() { return _originalMethod; } public IMethodInfo getTerminalMethod() { return _terminalMethod; } @Override public IRType getReturnType() { return getBoundedReturnType(_terminalMethod); } @Override public List<IRType> getExplicitParameterTypes() { return getBoundedParameterTypeDescriptors(_terminalMethod); } @Override public List<IRType> getAllParameterTypes() { return getMethodDescriptor(_terminalMethod); } @Override public String getName() { return getActualMethodName(_terminalMethod); } @Override public IRType getOwningIRType() { return getTrueOwningType(_terminalMethod); } @Override public IType getOwningIType() { IType owningType; if( _terminalMethod instanceof IJavaMethodInfo ) { // 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 IJavaClassMethod m = ((IJavaMethodInfo)_terminalMethod).getMethod(); if( m != null ) { owningType = TypeSystem.get( m.getEnclosingClass() ); } else { owningType = _terminalMethod.getOwnersType(); } } else { owningType = _terminalMethod.getOwnersType(); } if( owningType instanceof IMetaType) { owningType = ((IMetaType)owningType).getType(); } return owningType; } /*if( rootType instanceof IMetaType ) { rootType = ((IMetaType)rootType).getType(); } return rootType;*/ @Override public IRelativeTypeInfo.Accessibility getAccessibility() { return AccessibilityUtil.forFeatureInfo(_terminalMethod); } @Override public boolean isStatic() { return _terminalMethod.isStatic(); } 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 (_terminalMethod instanceof IGosuMethodInfo && !IGosuClass.ProxyUtil.isProxy(_terminalMethod.getOwnersType())) { return ((IGosuMethodInfo) _terminalMethod).getTypeVariables(); } else { return null; } } @Override public IFunctionType getFunctionType() { return _functionType; } @Override protected boolean isImplicitMethod() { return isGeneratedEnumMethod(); } @Override public boolean isGeneratedEnumMethod() { return getOwningIType().isEnum() && isStatic() && (hasSignature( "getAllValues" ) || hasSignature( "values" ) || hasSignature( "valueOf", JavaTypes.STRING() )); } private boolean hasSignature( String name, IType... argTypes ) { if( getName().equals( name ) && _originalMethod.getParameters().length == argTypes.length ) { for( int i = 0; i < argTypes.length; i++ ) { if( !_originalMethod.getParameters()[i].getFeatureType().equals( argTypes[i] ) ) { return false; } } return true; } return false; } @Override public boolean isBytecodeMethod() { return (_terminalMethod instanceof IGosuMethodInfo || _terminalMethod instanceof IJavaMethodInfo) && !IRFeatureBase.isExternalEntityJavaType( _terminalMethod ); } private static IRType getTrueOwningType( IMethodInfo mi ) { if( mi instanceof IJavaMethodInfo) { // 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 IJavaClassMethod m = ((IJavaMethodInfo)mi).getMethod(); if( m != null ) { return IRTypeResolver.getDescriptor( m.getEnclosingClass() ); } } return IRTypeResolver.getDescriptor( mi.getOwnersType() ); } @Override public boolean couldHaveTypeVariables() { return _terminalMethod instanceof IGosuMethodInfo && !IGosuClass.ProxyUtil.isProxy(_terminalMethod.getOwnersType()); } private String getActualMethodName(IMethodInfo methodInfo) { if( methodInfo instanceof IJavaMethodInfo) { // Get the name from the Java method in case a PublishedName attr was used in typeinfo return ((IJavaMethodInfo)methodInfo).getMethod().getName(); } else { return methodInfo.getDisplayName(); } } private IRType getBoundedReturnType( IMethodInfo mi ) { if( mi instanceof IJavaMethodInfo ) { return IRTypeResolver.getDescriptor( ((IJavaMethodInfo)mi).getMethod().getReturnClassInfo() ); } else if( mi instanceof IGosuMethodInfo) { IReducedDynamicFunctionSymbol dfs = ((IGosuMethodInfo)mi).getDfs(); while( dfs instanceof ReducedParameterizedDynamicFunctionSymbol) { ReducedParameterizedDynamicFunctionSymbol pdfs = (ReducedParameterizedDynamicFunctionSymbol)dfs; dfs = pdfs.getBackingDfs(); } if( IGosuClass.ProxyUtil.isProxy( dfs.getGosuClass() ) ) { return getBoundedReturnTypeFromProxiedClass( dfs ); } return IRTypeResolver.getDescriptor( TypeLord.getDefaultParameterizedTypeWithTypeVars( dfs.getReturnType() ) ); } else { return IRTypeResolver.getDescriptor( mi.getReturnType() ); } } private IRType getBoundedReturnTypeFromProxiedClass( IReducedDynamicFunctionSymbol dfs ) { IJavaClassMethod m = getJavaMethodFromProxy( dfs ); return JavaClassIRType.get( m.getReturnClassInfo() ); } public List<IRType> getMethodDescriptor( IMethodInfo mi ) { List<IRType> paramTypes = new ArrayList<IRType>(); IFunctionType functionType = null; if (mi instanceof IGosuMethodInfo && !IGosuClass.ProxyUtil.isProxy( mi.getOwnersType() )) { functionType = (IFunctionType) ((IGosuMethodInfo) mi).getDfs().getType(); } addImplicitParameters( getOwningIType(), functionType, isStatic(), paramTypes ); paramTypes.addAll( getBoundedParameterTypeDescriptors( mi ) ); return paramTypes; } private List<IRType> getBoundedParameterTypeDescriptors( IMethodInfo mi ) { if( mi.getParameters().length == 0 ) { return Collections.emptyList(); } if( mi instanceof IJavaMethodInfo ) { return IRTypeResolver.getDescriptors( ((IJavaMethodInfo)mi).getMethod().getParameterTypes() ); } else if( mi instanceof IGosuMethodInfo ) { IReducedDynamicFunctionSymbol dfs = ((IGosuMethodInfo)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 ) { IJavaClassMethod m = getJavaMethodFromProxy( dfs ); IJavaClassInfo[] paramClasses = m.getParameterTypes(); List<IRType> paramTypes = new ArrayList<IRType>( paramClasses.length ); for( int i = 0; i < paramClasses.length; i++ ) { paramTypes.add( JavaClassIRType.get( paramClasses[i] ) ); } return paramTypes; } private IJavaClassMethod getJavaMethodFromProxy( 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 || TypeLord.isRecursiveType( javaType )) ) { param = ((ITypeVariableType)param).getBoundingType(); } boundedDfsParams[i] = TypeLord.getPureGenericType( param ); } javaType = (IJavaType)TypeLord.getDefaultParameterizedType( javaType ); IJavaMethodInfo jmi = (IJavaMethodInfo)((IRelativeTypeInfo)javaType.getTypeInfo()).getMethod( javaType, dfs.getDisplayName(), boundedDfsParams ); return jmi.getMethod(); } }