Search in sources :

Example 31 with ClassNode

use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.

the class StaticInvocationWriter method tryBridgeMethod.

/**
     * Attempts to make a direct method call on a bridge method, if it exists.
     */
protected boolean tryBridgeMethod(MethodNode target, Expression receiver, boolean implicitThis, TupleExpression args) {
    ClassNode lookupClassNode;
    if (target.isProtected()) {
        lookupClassNode = controller.getClassNode();
        if (controller.isInClosure()) {
            lookupClassNode = lookupClassNode.getOuterClass();
        }
    } else {
        lookupClassNode = target.getDeclaringClass().redirect();
    }
    Map<MethodNode, MethodNode> bridges = lookupClassNode.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
    MethodNode bridge = bridges == null ? null : bridges.get(target);
    if (bridge != null) {
        Expression fixedReceiver = receiver;
        ClassNode classNode = implicitThis ? controller.getClassNode() : null;
        ClassNode declaringClass = bridge.getDeclaringClass();
        if (implicitThis && !controller.isInClosure() && !classNode.isDerivedFrom(declaringClass) && !classNode.implementsInterface(declaringClass) && classNode instanceof InnerClassNode) {
            fixedReceiver = new PropertyExpression(new ClassExpression(classNode.getOuterClass()), "this");
        }
        ArgumentListExpression newArgs = new ArgumentListExpression(target.isStatic() ? new ConstantExpression(null) : fixedReceiver);
        for (Expression expression : args.getExpressions()) {
            newArgs.addExpression(expression);
        }
        return writeDirectMethodCall(bridge, implicitThis, fixedReceiver, newArgs);
    }
    return false;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 32 with ClassNode

use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.

the class StaticInvocationWriter method tryImplicitReceiver.

boolean tryImplicitReceiver(final Expression origin, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
    Object implicitReceiver = origin.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
    ClassNode propertyOwnerType = origin.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
    if (implicitThis && implicitReceiver == null && origin instanceof MethodCallExpression) {
        implicitReceiver = ((MethodCallExpression) origin).getObjectExpression().getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
    }
    if (implicitReceiver != null && implicitThis) {
        String[] propertyPath = ((String) implicitReceiver).split("\\.");
        // GROOVY-6021
        PropertyExpression pexp = new PropertyExpression(new VariableExpression("this", CLOSURE_TYPE), propertyPath[0]);
        pexp.setImplicitThis(true);
        for (int i = 1; i < propertyPath.length; i++) {
            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
            pexp = new PropertyExpression(pexp, propertyPath[i]);
        }
        pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, implicitReceiver);
        if (propertyOwnerType != null) {
            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, propertyOwnerType);
        }
        origin.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
        if (origin instanceof PropertyExpression) {
            PropertyExpression rewritten = new PropertyExpression(pexp, ((PropertyExpression) origin).getProperty(), ((PropertyExpression) origin).isSafe());
            rewritten.setSpreadSafe(((PropertyExpression) origin).isSpreadSafe());
            rewritten.setImplicitThis(false);
            rewritten.visit(controller.getAcg());
            rewritten.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, origin.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
            return true;
        }
        makeCall(origin, pexp, message, arguments, adapter, safe, spreadSafe, false);
        return true;
    }
    return false;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 33 with ClassNode

use of org.codehaus.groovy.ast.ClassNode 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 34 with ClassNode

use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.

the class StatementWriter method writeTryCatchFinally.

public void writeTryCatchFinally(TryCatchStatement statement) {
    controller.getAcg().onLineNumber(statement, "visitTryCatchFinally");
    writeStatementLabel(statement);
    MethodVisitor mv = controller.getMethodVisitor();
    CompileStack compileStack = controller.getCompileStack();
    OperandStack operandStack = controller.getOperandStack();
    Statement tryStatement = statement.getTryStatement();
    final Statement finallyStatement = statement.getFinallyStatement();
    // start try block, label needed for exception table
    Label tryStart = new Label();
    mv.visitLabel(tryStart);
    BlockRecorder tryBlock = makeBlockRecorder(finallyStatement);
    tryBlock.startRange(tryStart);
    tryStatement.visit(controller.getAcg());
    // goto finally part
    Label finallyStart = new Label();
    mv.visitJumpInsn(GOTO, finallyStart);
    Label tryEnd = new Label();
    mv.visitLabel(tryEnd);
    tryBlock.closeRange(tryEnd);
    // pop for "makeBlockRecorder(finallyStatement)"
    controller.getCompileStack().pop();
    BlockRecorder catches = makeBlockRecorder(finallyStatement);
    for (CatchStatement catchStatement : statement.getCatchStatements()) {
        ClassNode exceptionType = catchStatement.getExceptionType();
        String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
        // start catch block, label needed for exception table
        Label catchStart = new Label();
        mv.visitLabel(catchStart);
        catches.startRange(catchStart);
        // create exception variable and store the exception
        Parameter exceptionVariable = catchStatement.getVariable();
        compileStack.pushState();
        compileStack.defineVariable(exceptionVariable, true);
        // handle catch body
        catchStatement.visit(controller.getAcg());
        // place holder to avoid problems with empty catch blocks
        mv.visitInsn(NOP);
        // pop for the variable
        controller.getCompileStack().pop();
        // end of catch
        Label catchEnd = new Label();
        mv.visitLabel(catchEnd);
        catches.closeRange(catchEnd);
        // goto finally start
        mv.visitJumpInsn(GOTO, finallyStart);
        compileStack.writeExceptionTable(tryBlock, catchStart, exceptionTypeInternalName);
    }
    // Label used to handle exceptions in catches and regularly
    // visited finals.
    Label catchAny = new Label();
    // add "catch any" block to exception table for try part we do this 
    // after the exception blocks, because else this one would supersede
    // any of those otherwise
    compileStack.writeExceptionTable(tryBlock, catchAny, null);
    // same for the catch parts
    compileStack.writeExceptionTable(catches, catchAny, null);
    // pop for "makeBlockRecorder(catches)"
    compileStack.pop();
    // start finally
    mv.visitLabel(finallyStart);
    finallyStatement.visit(controller.getAcg());
    //**
    mv.visitInsn(NOP);
    // goto after all-catching block
    Label skipCatchAll = new Label();
    mv.visitJumpInsn(GOTO, skipCatchAll);
    // start a block catching any Exception
    mv.visitLabel(catchAny);
    //store exception
    //TODO: maybe define a Throwable and use it here instead of Object
    operandStack.push(ClassHelper.OBJECT_TYPE);
    int anyExceptionIndex = compileStack.defineTemporaryVariable("exception", true);
    finallyStatement.visit(controller.getAcg());
    // load the exception and rethrow it
    mv.visitVarInsn(ALOAD, anyExceptionIndex);
    mv.visitInsn(ATHROW);
    mv.visitLabel(skipCatchAll);
}
Also used : BlockRecorder(org.codehaus.groovy.classgen.asm.CompileStack.BlockRecorder) ClassNode(org.codehaus.groovy.ast.ClassNode) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) WhileStatement(org.codehaus.groovy.ast.stmt.WhileStatement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ThrowStatement(org.codehaus.groovy.ast.stmt.ThrowStatement) CaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement) DoWhileStatement(org.codehaus.groovy.ast.stmt.DoWhileStatement) ContinueStatement(org.codehaus.groovy.ast.stmt.ContinueStatement) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) BreakStatement(org.codehaus.groovy.ast.stmt.BreakStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) SynchronizedStatement(org.codehaus.groovy.ast.stmt.SynchronizedStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) SwitchStatement(org.codehaus.groovy.ast.stmt.SwitchStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) AssertStatement(org.codehaus.groovy.ast.stmt.AssertStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) Label(org.objectweb.asm.Label) Parameter(org.codehaus.groovy.ast.Parameter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 35 with ClassNode

use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.

the class StatementWriter method writeReturn.

public void writeReturn(ReturnStatement statement) {
    controller.getAcg().onLineNumber(statement, "visitReturnStatement");
    writeStatementLabel(statement);
    MethodVisitor mv = controller.getMethodVisitor();
    OperandStack operandStack = controller.getOperandStack();
    ClassNode returnType = controller.getReturnType();
    if (returnType == ClassHelper.VOID_TYPE) {
        if (!(statement.isReturningNullOrVoid())) {
            //TODO: move to Verifier
            controller.getAcg().throwException("Cannot use return statement with an expression on a method that returns void");
        }
        controller.getCompileStack().applyBlockRecorder();
        mv.visitInsn(RETURN);
        return;
    }
    Expression expression = statement.getExpression();
    expression.visit(controller.getAcg());
    operandStack.doGroovyCast(returnType);
    if (controller.getCompileStack().hasBlockRecorder()) {
        ClassNode type = operandStack.getTopOperand();
        int returnValueIdx = controller.getCompileStack().defineTemporaryVariable("returnValue", returnType, true);
        controller.getCompileStack().applyBlockRecorder();
        operandStack.load(type, returnValueIdx);
    }
    BytecodeHelper.doReturn(mv, returnType);
    operandStack.remove(1);
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) EmptyExpression(org.codehaus.groovy.ast.expr.EmptyExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ClosureListExpression(org.codehaus.groovy.ast.expr.ClosureListExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

ClassNode (org.codehaus.groovy.ast.ClassNode)869 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)348 MethodNode (org.codehaus.groovy.ast.MethodNode)193 GenericsType (org.codehaus.groovy.ast.GenericsType)154 LowestUpperBoundClassNode (org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode)148 Expression (org.codehaus.groovy.ast.expr.Expression)146 Parameter (org.codehaus.groovy.ast.Parameter)135 FieldNode (org.codehaus.groovy.ast.FieldNode)126 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)118 AnnotationNode (org.codehaus.groovy.ast.AnnotationNode)117 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)113 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)103 ArrayList (java.util.ArrayList)95 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)92 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)75 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)74 LinkedList (java.util.LinkedList)71 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)71 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)62 ListExpression (org.codehaus.groovy.ast.expr.ListExpression)61