Search in sources :

Example 26 with ASTNode

use of org.codehaus.groovy.ast.ASTNode 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;
    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, classNode)) {
                // 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;
        }
        Expression fixedReceiver = null;
        boolean fixedImplicitThis = implicitThis;
        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()));
            } else if (!node.isDerivedFrom(target.getDeclaringClass()) && tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
                return true;
            }
        } else if (target.isPublic() && receiver != null) {
            if (implicitThis && !classNode.isDerivedFrom(target.getDeclaringClass()) && !classNode.implementsInterface(target.getDeclaringClass()) && classNode instanceof InnerClassNode && controller.isInClosure()) {
                ClassNode current = classNode.getOuterClass();
                fixedReceiver = new VariableExpression("thisObject", current);
                // adjust for multiple levels of nesting if needed
                while (current != null && current instanceof InnerClassNode && !classNode.equals(current)) {
                    FieldNode thisField = current.getField("this$0");
                    current = current.getOuterClass();
                    if (thisField != null) {
                        fixedReceiver = new PropertyExpression(fixedReceiver, "this$0");
                        fixedReceiver.setType(current);
                        fixedImplicitThis = false;
                    }
                }
            }
        }
        if (receiver != null) {
            boolean callToSuper = receiver instanceof VariableExpression && ((VariableExpression) receiver).isSuperExpression();
            if (!callToSuper) {
                fixedReceiver = fixedReceiver == null ? receiver : fixedReceiver;
                // 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(fixedReceiver, target);
                return super.writeDirectMethodCall(target, fixedImplicitThis, checkCastReceiver, args);
            }
        }
        return super.writeDirectMethodCall(target, implicitThis, receiver, args);
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) LinkedList(java.util.LinkedList) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodVisitor(org.objectweb.asm.MethodVisitor) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) TemporaryVariableExpression(org.codehaus.groovy.transform.sc.TemporaryVariableExpression) 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 27 with ASTNode

use of org.codehaus.groovy.ast.ASTNode in project groovy by apache.

the class StaticTypesTypeChooser method resolveType.

@Override
public ClassNode resolveType(final Expression exp, final ClassNode current) {
    ASTNode target = exp instanceof VariableExpression ? getTarget((VariableExpression) exp) : exp;
    ClassNode inferredType = (ClassNode) target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
    if (inferredType == null) {
        inferredType = (ClassNode) target.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
        if (inferredType == null && target instanceof VariableExpression && ((VariableExpression) target).getAccessedVariable() instanceof Parameter) {
            target = (Parameter) ((VariableExpression) target).getAccessedVariable();
            inferredType = ((Parameter) target).getOriginType();
        }
    }
    if (inferredType != null) {
        if (ClassHelper.VOID_TYPE == inferredType) {
            // we are in a case of a type inference failure, probably because code was generated
            // it is better to avoid using this
            inferredType = super.resolveType(exp, current);
        }
        return inferredType;
    }
    if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) {
        // AsmClassGenerator may create "this" expressions that the type checker knows nothing about
        return current;
    }
    return super.resolveType(exp, current);
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) ASTNode(org.codehaus.groovy.ast.ASTNode) Parameter(org.codehaus.groovy.ast.Parameter) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression)

Aggregations

ASTNode (org.codehaus.groovy.ast.ASTNode)27 MethodNode (org.codehaus.groovy.ast.MethodNode)17 ClassNode (org.codehaus.groovy.ast.ClassNode)15 Parameter (org.codehaus.groovy.ast.Parameter)10 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)8 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)8 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)7 Variable (org.codehaus.groovy.ast.Variable)6 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)6 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)6 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)6 Expression (org.codehaus.groovy.ast.expr.Expression)6 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)6 TupleExpression (org.codehaus.groovy.ast.expr.TupleExpression)6 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)6 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)6 LinkedList (java.util.LinkedList)5 FieldNode (org.codehaus.groovy.ast.FieldNode)5 ClosureSignatureHint (groovy.transform.stc.ClosureSignatureHint)4 DynamicVariable (org.codehaus.groovy.ast.DynamicVariable)4