Search in sources :

Example 1 with ExtensionMethodNode

use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy-core by groovy.

the class MethodCallExpressionTransformer method tryTransformIsToCompareIdentity.

/**
 * Identifies a method call expression on {@link DefaultGroovyMethods#is(Object, Object)} and if recognized, transforms it into a {@link CompareIdentityExpression}.
 * @param call a method call to be transformed
 * @return null if the method call is not DGM#is, or {@link CompareIdentityExpression}
 */
private static Expression tryTransformIsToCompareIdentity(MethodCallExpression call) {
    MethodNode methodTarget = call.getMethodTarget();
    if (methodTarget instanceof ExtensionMethodNode && "is".equals(methodTarget.getName()) && methodTarget.getParameters().length == 1) {
        methodTarget = ((ExtensionMethodNode) methodTarget).getExtensionMethodNode();
        ClassNode owner = methodTarget.getDeclaringClass();
        if (DGM_CLASSNODE.equals(owner)) {
            Expression args = call.getArguments();
            if (args instanceof ArgumentListExpression) {
                ArgumentListExpression arguments = (ArgumentListExpression) args;
                List<Expression> exprs = arguments.getExpressions();
                if (exprs.size() == 1) {
                    CompareIdentityExpression cid = new CompareIdentityExpression(call.getObjectExpression(), exprs.get(0));
                    cid.setSourcePosition(call);
                    return cid;
                }
            }
        }
    }
    return null;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode)

Example 2 with ExtensionMethodNode

use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy-core by groovy.

the class StaticInvocationWriter method writeDirectMethodCall.

@Override
protected boolean writeDirectMethodCall(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args) {
    if (target == null)
        return false;
    if (target instanceof ExtensionMethodNode) {
        ExtensionMethodNode emn = (ExtensionMethodNode) target;
        MethodNode node = emn.getExtensionMethodNode();
        String methodName = target.getName();
        MethodVisitor mv = controller.getMethodVisitor();
        int argumentsToRemove = 0;
        List<Expression> argumentList = new LinkedList<Expression>(args.getExpressions());
        if (emn.isStaticExtension()) {
            // it's a static extension method
            argumentList.add(0, ConstantExpression.NULL);
        } else {
            argumentList.add(0, receiver);
        }
        Parameter[] parameters = node.getParameters();
        loadArguments(argumentList, parameters);
        String owner = BytecodeHelper.getClassInternalName(node.getDeclaringClass());
        String desc = BytecodeHelper.getMethodDescriptor(target.getReturnType(), parameters);
        mv.visitMethodInsn(INVOKESTATIC, owner, methodName, desc, false);
        ClassNode ret = target.getReturnType().redirect();
        if (ret == ClassHelper.VOID_TYPE) {
            ret = ClassHelper.OBJECT_TYPE;
            mv.visitInsn(ACONST_NULL);
        }
        argumentsToRemove += argumentList.size();
        controller.getOperandStack().remove(argumentsToRemove);
        controller.getOperandStack().push(ret);
        return true;
    } else {
        if (target == StaticTypeCheckingVisitor.CLOSURE_CALL_VARGS) {
            // wrap arguments into an array
            ArrayExpression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
            return super.writeDirectMethodCall(target, implicitThis, receiver, new ArgumentListExpression(arr));
        }
        ClassNode classNode = controller.getClassNode();
        if (classNode.isDerivedFrom(ClassHelper.CLOSURE_TYPE) && controller.isInClosure() && !target.isPublic() && target.getDeclaringClass() != classNode) {
            if (!tryBridgeMethod(target, receiver, implicitThis, args)) {
                // replace call with an invoker helper call
                ArrayExpression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
                MethodCallExpression mce = new MethodCallExpression(INVOKERHELER_RECEIVER, target.isStatic() ? "invokeStaticMethod" : "invokeMethodSafe", new ArgumentListExpression(target.isStatic() ? new ClassExpression(target.getDeclaringClass()) : receiver, new ConstantExpression(target.getName()), arr));
                mce.setMethodTarget(target.isStatic() ? INVOKERHELPER_INVOKESTATICMETHOD : INVOKERHELPER_INVOKEMETHOD);
                mce.visit(controller.getAcg());
                return true;
            }
            return true;
        }
        if (target.isPrivate()) {
            if (tryPrivateMethod(target, implicitThis, receiver, args, classNode))
                return true;
        } else if (target.isProtected()) {
            ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
            boolean isThisOrSuper = false;
            if (receiver instanceof VariableExpression) {
                isThisOrSuper = ((VariableExpression) receiver).isThisExpression() || ((VariableExpression) receiver).isSuperExpression();
            }
            if (!implicitThis && !isThisOrSuper && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node, target.getDeclaringClass())) {
                ASTNode src = receiver == null ? args : receiver;
                controller.getSourceUnit().addError(new SyntaxException("Method " + target.getName() + " is protected in " + target.getDeclaringClass().toString(false), src.getLineNumber(), src.getColumnNumber(), src.getLastLineNumber(), src.getLastColumnNumber()));
            }
        }
        if (receiver != null) {
            if (!(receiver instanceof VariableExpression) || !((VariableExpression) receiver).isSuperExpression()) {
                // in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead
                // then replace the top operand type
                Expression checkCastReceiver = new CheckcastReceiverExpression(receiver, target);
                return super.writeDirectMethodCall(target, implicitThis, checkCastReceiver, args);
            }
        }
        return super.writeDirectMethodCall(target, implicitThis, receiver, args);
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedList(java.util.LinkedList) MethodVisitor(org.objectweb.asm.MethodVisitor) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) SyntaxException(org.codehaus.groovy.syntax.SyntaxException) ASTNode(org.codehaus.groovy.ast.ASTNode) Parameter(org.codehaus.groovy.ast.Parameter) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode)

Example 3 with ExtensionMethodNode

use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.

the class MacroCallTransformingVisitor method visitMethodCallExpression.

@Override
public void visitMethodCallExpression(MethodCallExpression call) {
    super.visitMethodCallExpression(call);
    final List<Expression> callArguments;
    if (call.getArguments() instanceof TupleExpression) {
        callArguments = ((TupleExpression) call.getArguments()).getExpressions();
    } else {
        callArguments = Collections.singletonList(call.getArguments());
    }
    List<MethodNode> macroMethods = findMacroMethods(call.getMethodAsString(), callArguments);
    if (macroMethods.isEmpty()) {
        // Early return to avoid macro context and arguments creation
        return;
    }
    MacroContext macroContext = new MacroContext(unit, sourceUnit, call);
    Object[] macroArguments = new Object[callArguments.size() + 1];
    macroArguments[0] = macroContext;
    System.arraycopy(callArguments.toArray(), 0, macroArguments, 1, callArguments.size());
    for (MethodNode macroMethodNode : macroMethods) {
        if (!(macroMethodNode instanceof ExtensionMethodNode)) {
            throw new IllegalStateException(macroMethodNode + " is not an instance of ExtensionMethodNode");
        }
        if (tryMacroMethod(call, (ExtensionMethodNode) macroMethodNode, macroArguments)) {
            break;
        }
    }
}
Also used : ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) MacroContext(org.codehaus.groovy.macro.runtime.MacroContext) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode)

Example 4 with ExtensionMethodNode

use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.

the class MethodCallExpressionTransformer method tryTransformIsToCompareIdentity.

/**
 * Identifies a method call expression on {@link DefaultGroovyMethods#is(Object, Object)} and if recognized, transforms it into a {@link CompareIdentityExpression}.
 * @param call a method call to be transformed
 * @return null if the method call is not DGM#is, or {@link CompareIdentityExpression}
 */
private static Expression tryTransformIsToCompareIdentity(MethodCallExpression call) {
    if (call.isSafe())
        return null;
    MethodNode methodTarget = call.getMethodTarget();
    if (methodTarget instanceof ExtensionMethodNode && "is".equals(methodTarget.getName()) && methodTarget.getParameters().length == 1) {
        methodTarget = ((ExtensionMethodNode) methodTarget).getExtensionMethodNode();
        ClassNode owner = methodTarget.getDeclaringClass();
        if (DGM_CLASSNODE.equals(owner)) {
            Expression args = call.getArguments();
            if (args instanceof ArgumentListExpression) {
                ArgumentListExpression arguments = (ArgumentListExpression) args;
                List<Expression> exprs = arguments.getExpressions();
                if (exprs.size() == 1) {
                    CompareIdentityExpression cid = new CompareIdentityExpression(call.getObjectExpression(), exprs.get(0));
                    cid.setSourcePosition(call);
                    return cid;
                }
            }
        }
    }
    return null;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode)

Example 5 with ExtensionMethodNode

use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.

the class StaticInvocationWriter method writeDirectMethodCall.

@Override
protected boolean writeDirectMethodCall(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args) {
    if (target == null)
        return false;
    ClassNode classNode = controller.getClassNode();
    if (target instanceof ExtensionMethodNode) {
        ExtensionMethodNode emn = (ExtensionMethodNode) target;
        MethodVisitor mv = controller.getMethodVisitor();
        MethodNode node = emn.getExtensionMethodNode();
        Parameter[] parameters = node.getParameters();
        ClassNode returnType = node.getReturnType();
        List<Expression> argumentList = new ArrayList<>();
        if (emn.isStaticExtension()) {
            argumentList.add(nullX());
        } else {
            Expression fixedReceiver = null;
            if (isThisOrSuper(receiver) && classNode.getOuterClass() != null && controller.isInGeneratedFunction()) {
                ClassNode current = classNode.getOuterClass();
                fixedReceiver = varX("thisObject", current);
                // adjust for multiple levels of nesting if needed
                while (current.getOuterClass() != null && !classNode.equals(current)) {
                    FieldNode thisField = current.getField("this$0");
                    current = current.getOuterClass();
                    if (thisField != null) {
                        fixedReceiver = propX(fixedReceiver, "this$0");
                        fixedReceiver.setType(current);
                    }
                }
            }
            argumentList.add(fixedReceiver != null ? fixedReceiver : receiver);
        }
        argumentList.addAll(args.getExpressions());
        loadArguments(argumentList, parameters);
        String owner = BytecodeHelper.getClassInternalName(node.getDeclaringClass());
        String desc = BytecodeHelper.getMethodDescriptor(returnType, parameters);
        mv.visitMethodInsn(INVOKESTATIC, owner, target.getName(), desc, false);
        controller.getOperandStack().remove(argumentList.size());
        if (isPrimitiveVoid(returnType)) {
            returnType = ClassHelper.OBJECT_TYPE;
            mv.visitInsn(ACONST_NULL);
        }
        controller.getOperandStack().push(returnType);
        return true;
    }
    if (target == StaticTypeCheckingVisitor.CLOSURE_CALL_VARGS) {
        // wrap arguments into an array
        Expression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
        return super.writeDirectMethodCall(target, implicitThis, receiver, args(arr));
    }
    if (!target.isPublic() && controller.isInGeneratedFunction() && target.getDeclaringClass() != classNode) {
        if (!tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
            // replace call with an invoker helper call
            MethodNode methodNode = target.isStatic() ? INVOKERHELPER_INVOKESTATICMETHOD : INVOKERHELPER_INVOKEMETHOD;
            MethodCallExpression mce = callX(classX(INVOKERHELPER_CLASSNODE), methodNode.getName(), args(target.isStatic() ? classX(target.getDeclaringClass()) : receiver, constX(target.getName()), new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions())));
            mce.setMethodTarget(methodNode);
            mce.visit(controller.getAcg());
        }
        return true;
    }
    if (target.isPrivate() && tryPrivateMethod(target, implicitThis, receiver, args, classNode)) {
        return true;
    }
    Expression fixedReceiver = null;
    boolean fixedImplicitThis = implicitThis;
    if (target.isProtected()) {
        ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
        if (!implicitThis && !isThisOrSuper(receiver) && !samePackageName(node, classNode) && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node, target.getDeclaringClass())) {
            controller.getSourceUnit().addError(new SyntaxException("Method " + target.getName() + " is protected in " + target.getDeclaringClass().toString(false), receiver != null ? receiver : args));
        } else if (!node.isDerivedFrom(target.getDeclaringClass()) && tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
            return true;
        }
    } else if (target.isPublic() && receiver != null) {
        if (implicitThis && controller.isInGeneratedFunction() && !classNode.isDerivedFrom(target.getDeclaringClass()) && !classNode.implementsInterface(target.getDeclaringClass())) {
            ClassNode thisType = controller.getThisType();
            // GROOVY-7242
            if (isTrait(thisType.getOuterClass()))
                thisType = ClassHelper.dynamicType();
            fixedReceiver = varX("thisObject", thisType);
            // account for multiple levels of inner types
            while (thisType.getOuterClass() != null && !target.getDeclaringClass().equals(thisType)) {
                FieldNode thisField = thisType.getField("this$0");
                thisType = thisType.getOuterClass();
                if (thisField != null) {
                    fixedReceiver = propX(fixedReceiver, "this$0");
                    fixedReceiver.setType(thisType);
                    fixedImplicitThis = false;
                }
            }
        }
    }
    if (receiver != null && !isSuperExpression(receiver)) {
        // in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead then replace the top operand type
        return super.writeDirectMethodCall(target, fixedImplicitThis, new CheckcastReceiverExpression(fixedReceiver != null ? fixedReceiver : receiver, target), args);
    }
    return super.writeDirectMethodCall(target, implicitThis, receiver, args);
}
Also used : DecompiledClassNode(org.codehaus.groovy.ast.decompiled.DecompiledClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) ArrayList(java.util.ArrayList) MethodVisitor(org.objectweb.asm.MethodVisitor) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) ExpressionUtils.isSuperExpression(org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) AttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression) SyntaxException(org.codehaus.groovy.syntax.SyntaxException) Parameter(org.codehaus.groovy.ast.Parameter) ArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode)

Aggregations

MethodNode (org.codehaus.groovy.ast.MethodNode)6 ExtensionMethodNode (org.codehaus.groovy.transform.stc.ExtensionMethodNode)6 ClassNode (org.codehaus.groovy.ast.ClassNode)5 Expression (org.codehaus.groovy.ast.expr.Expression)5 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)5 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)4 TupleExpression (org.codehaus.groovy.ast.expr.TupleExpression)4 Parameter (org.codehaus.groovy.ast.Parameter)3 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)3 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)3 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)2 ArrayExpression (org.codehaus.groovy.ast.expr.ArrayExpression)2 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)2 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)2 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)2 SyntaxException (org.codehaus.groovy.syntax.SyntaxException)2 MethodVisitor (org.objectweb.asm.MethodVisitor)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 ExpressionUtils.isSuperExpression (org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression)1