public VariableExpression(String variable, ClassNode type) { this.variable = variable; originType = type; setType(ClassHelper.getWrapper(type)); }
/** * Returns a wrapped type if, and only if, the provided class node is a primitive type. * This method differs from {@link ClassHelper#getWrapper(org.codehaus.groovy.ast.ClassNode)} as it will * return the same instance if the provided type is not a generic type. * * @param type * @return the wrapped type */ protected static ClassNode wrapTypeIfNecessary(ClassNode type) { if (isPrimitiveType(type)) return getWrapper(type); return type; }
private static boolean hasCompatibleType(ClassNode attrType, ClassNode wrapperType) { return wrapperType.isDerivedFrom(ClassHelper.getWrapper(attrType)); }
public ClassNode box() { MethodVisitor mv = controller.getMethodVisitor(); int size = stack.size(); ClassNode type = stack.get(size-1); if (ClassHelper.isPrimitiveType(type) && ClassHelper.VOID_TYPE!=type) { ClassNode wrapper = ClassHelper.getWrapper(type); BytecodeHelper.doCastToWrappedType(mv, type, wrapper); type = wrapper; } // else nothing to box stack.set(size-1, type); return type; }
private boolean compatibleArgumentType(ClassNode argumentType, ClassNode paramType) { if (argumentType == null) return false; if (ClassHelper.getWrapper(argumentType).equals(ClassHelper.getWrapper(paramType))) return true; if (paramType.isInterface()) return argumentType.implementsInterface(paramType); if (paramType.isArray() && argumentType.isArray()) return compatibleArgumentType(argumentType.getComponentType(), paramType.getComponentType()); return ClassHelper.getWrapper(argumentType).isDerivedFrom(ClassHelper.getWrapper(paramType)); }
public static ClassNode getSuperClass(ClassNode type, ClassNode target) { ClassNode superClass = ClassHelper.getNextSuperClass(type, target); if (superClass == null) { if (ClassHelper.isPrimitiveType(type)) { superClass = ClassHelper.getNextSuperClass(ClassHelper.getWrapper(type), target); } } return superClass; }
@Override public void castToNonPrimitiveIfNecessary(ClassNode sourceType, ClassNode targetType) { ClassNode boxedType = ClassHelper.getWrapper(sourceType); if (WideningCategories.implementsInterfaceOrSubclassOf(boxedType, targetType)) { controller.getOperandStack().box(); return; } writeIndyCast(sourceType, targetType); }
private static ClassNode adjustTypeForSpreading(ClassNode inferredRightExpressionType, Expression leftExpression) { // imagine we have: list*.foo = 100 // then the assignment must be checked against [100], not 100 ClassNode wrappedRHS = inferredRightExpressionType; if (leftExpression instanceof PropertyExpression && ((PropertyExpression) leftExpression).isSpreadSafe()) { wrappedRHS = LIST_TYPE.getPlainNodeReference(); wrappedRHS.setGenericsTypes(new GenericsType[]{ new GenericsType(getWrapper(inferredRightExpressionType)) }); } return wrappedRHS; }
private void writePowerCall(Expression receiver, Expression arguments, final ClassNode rType, ClassNode aType) { OperandStack operandStack = controller.getOperandStack(); int m1 = operandStack.getStackLength(); //slow Path prepareSiteAndReceiver(receiver, "power", false, controller.getCompileStack().isLHS()); operandStack.doGroovyCast(getWrapper(rType)); visitBoxedArgument(arguments); operandStack.doGroovyCast(getWrapper(aType)); int m2 = operandStack.getStackLength(); MethodVisitor mv = controller.getMethodVisitor(); if (BigDecimal_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) { mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigDecimal;Ljava/lang/Integer;)Ljava/lang/Number;", false); } else if (BigInteger_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) { mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigInteger;Ljava/lang/Integer;)Ljava/lang/Number;", false); } else if (Long_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) { mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Long;Ljava/lang/Integer;)Ljava/lang/Number;", false); } else if (Integer_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) { mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Number;", false); } else { mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false); } controller.getOperandStack().replace(Number_TYPE, m2 - m1); }
private static Expression transformConstantExpression(Expression val, ClassNode returnType) { ClassNode returnWrapperType = ClassHelper.getWrapper(returnType); if (val instanceof ConstantExpression) { Expression result = revertType(val, returnWrapperType); if (result != null) { return result; } return val; } if (val instanceof CastExpression) { CastExpression castExp = (CastExpression) val; Expression castee = castExp.getExpression(); if (castee instanceof ConstantExpression) { if (ClassHelper.getWrapper(castee.getType()).isDerivedFrom(returnWrapperType)) { return castee; } Expression result = revertType(castee, returnWrapperType); if (result != null) { return result; } return castee; } } return transformInlineConstants(val, returnType); }
protected void visitConstantExpression(String attrName, ConstantExpression constExpr, ClassNode attrType) { ClassNode constType = constExpr.getType(); ClassNode wrapperType = ClassHelper.getWrapper(constType); if (!hasCompatibleType(attrType, wrapperType)) { addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "'; but found type '" + constType.getName() + "'", constExpr); } }
/** * Visits a class literal. If the type of the classnode is a primitive type, * the generated bytecode will be a GETSTATIC Integer.TYPE. * If the classnode is not a primitive type, we will generate a LDC instruction. */ public static void visitClassLiteral(MethodVisitor mv, ClassNode classNode) { if (ClassHelper.isPrimitiveType(classNode)) { mv.visitFieldInsn( GETSTATIC, getClassInternalName(ClassHelper.getWrapper(classNode)), "TYPE", "Ljava/lang/Class;"); } else { mv.visitLdcInsn(org.objectweb.asm.Type.getType(getTypeDescription(classNode))); } }
private static boolean matchWithOrWithourBoxing(final ClassNode argType, final Class aClass) { final boolean match; ClassNode type = ClassHelper.make(aClass); if (ClassHelper.isPrimitiveType(type) && !ClassHelper.isPrimitiveType(argType)) { type = ClassHelper.getWrapper(type); } else if (ClassHelper.isPrimitiveType(argType) && !ClassHelper.isPrimitiveType(type)) { type = ClassHelper.getUnwrapper(type); } match = argType.equals(type); return match; }
public MethodNode getGetterMethod(String getterName, boolean searchSuperClasses) { MethodNode getterMethod = null; boolean booleanReturnOnly = getterName.startsWith("is"); for (MethodNode method : getDeclaredMethods(getterName)) { if (getterName.equals(method.getName()) && ClassHelper.VOID_TYPE!=method.getReturnType() && method.getParameters().length == 0 && (!booleanReturnOnly || ClassHelper.Boolean_TYPE.equals(ClassHelper.getWrapper(method.getReturnType())))) { // GROOVY-7363: There can be multiple matches for a getter returning a generic parameter type, due to // the generation of a bridge method. The real getter is really the non-bridge, non-synthetic one as it // has the most specific and exact return type of the two. Picking the bridge method results in loss of // type information, as it down-casts the return type to the lower bound of the generic parameter. if (getterMethod == null || getterMethod.isSynthetic()) { getterMethod = method; } } } if (getterMethod != null) return getterMethod; if (searchSuperClasses) { ClassNode parent = getSuperClass(); if (parent != null) return parent.getGetterMethod(getterName); } return null; }
@Override public void visitRangeExpression(final RangeExpression expression) { super.visitRangeExpression(expression); ClassNode fromType = getWrapper(getType(expression.getFrom())); ClassNode toType = getWrapper(getType(expression.getTo())); if (Integer_TYPE.equals(fromType) && Integer_TYPE.equals(toType)) { storeType(expression, ClassHelper.make(IntRange.class)); } else { ClassNode rangeType = ClassHelper.make(Range.class).getPlainNodeReference(); rangeType.setGenericsTypes(new GenericsType[]{new GenericsType(WideningCategories.lowestUpperBound(fromType, toType))}); storeType(expression, rangeType); } }
private static DeclarationExpression optimizeConstantInitialization( final BinaryExpression originalDeclaration, final Token operation, final ConstantExpression constant, final Expression leftExpression, final ClassNode declarationType) { ConstantExpression cexp = new ConstantExpression( convertConstant((Number) constant.getValue(), ClassHelper.getWrapper(declarationType)), true); cexp.setType(declarationType); cexp.setSourcePosition(constant); DeclarationExpression result = new DeclarationExpression( leftExpression, operation, cexp ); result.setSourcePosition(originalDeclaration); result.copyNodeMetaData(originalDeclaration); return result; }
@Override public void coerce(ClassNode from, ClassNode target) { ClassNode wrapper = ClassHelper.getWrapper(target); makeIndyCall(invokeMethod, EmptyExpression.INSTANCE, false, false, "asType", new ClassExpression(wrapper)); if (ClassHelper.boolean_TYPE.equals(target) || ClassHelper.Boolean_TYPE.equals(target)) { writeIndyCast(ClassHelper.OBJECT_TYPE,target); } else { BytecodeHelper.doCast(controller.getMethodVisitor(), wrapper); controller.getOperandStack().replace(wrapper); controller.getOperandStack().doGroovyCast(target); } }
private ClassNode getTypeForSpreadExpression(ClassNode testClass, ClassNode objectExpressionType, PropertyExpression pexp) { if (!pexp.isSpreadSafe()) return null; MethodCallExpression mce = callX(varX("_", testClass), "iterator", ArgumentListExpression.EMPTY_ARGUMENTS); mce.setImplicitThis(false); mce.visit(this); ClassNode callType = getType(mce); if (!implementsInterfaceOrIsSubclassOf(callType, Iterator_TYPE)) return null; GenericsType[] types = callType.getGenericsTypes(); ClassNode contentType = OBJECT_TYPE; if (types != null && types.length == 1) contentType = types[0].getType(); PropertyExpression subExp = new PropertyExpression(varX("{}", contentType), pexp.getPropertyAsString()); AtomicReference<ClassNode> result = new AtomicReference<ClassNode>(); if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) { ClassNode intf = LIST_TYPE.getPlainNodeReference(); intf.setGenericsTypes(new GenericsType[]{new GenericsType(getWrapper(result.get()))}); return intf; } return null; }
static void visitField(ErrorCollecting xform, AnnotationNode node, FieldNode fieldNode) { final Expression soft = node.getMember("soft"); final Expression init = getInitExpr(xform, fieldNode); String backingFieldName = "$" + fieldNode.getName(); fieldNode.rename(backingFieldName); fieldNode.setModifiers(ACC_PRIVATE | (fieldNode.getModifiers() & (~(ACC_PUBLIC | ACC_PROTECTED)))); PropertyNode pNode = fieldNode.getDeclaringClass().getProperty(backingFieldName); if (pNode != null) { fieldNode.getDeclaringClass().getProperties().remove(pNode); } if (soft instanceof ConstantExpression && ((ConstantExpression) soft).getValue().equals(true)) { createSoft(fieldNode, init); } else { create(fieldNode, init); // @Lazy not meaningful with primitive so convert to wrapper if needed if (ClassHelper.isPrimitiveType(fieldNode.getType())) { fieldNode.setType(ClassHelper.getWrapper(fieldNode.getType())); } } }
@Override public void visitForLoop(final ForStatement forLoop) { super.visitForLoop(forLoop); Expression collectionExpression = forLoop.getCollectionExpression(); if (!(collectionExpression instanceof ClosureListExpression)) { final ClassNode collectionType = getType(forLoop.getCollectionExpression()); ClassNode forLoopVariableType = forLoop.getVariableType(); ClassNode componentType; if (Character_TYPE.equals(ClassHelper.getWrapper(forLoopVariableType)) && STRING_TYPE.equals(collectionType)) { // we allow auto-coercion here componentType = forLoopVariableType; } else { componentType = inferLoopElementType(collectionType); } forLoop.getVariable().setType(componentType); forLoop.getVariable().setOriginType(componentType); } }