Search in sources :

Example 51 with Parameter

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

the class TraitTypeCheckingExtension method handleMissingMethod.

@Override
public List<MethodNode> handleMissingMethod(final ClassNode receiver, final String name, final ArgumentListExpression argumentList, final ClassNode[] argumentTypes, final MethodCall call) {
    String[] decomposed = Traits.decomposeSuperCallName(name);
    if (decomposed != null) {
        return convertToDynamicCall(call, receiver, decomposed, argumentTypes);
    }
    if (call instanceof MethodCallExpression) {
        MethodCallExpression mce = (MethodCallExpression) call;
        if (mce.getReceiver() instanceof VariableExpression) {
            VariableExpression var = (VariableExpression) mce.getReceiver();
            // GROOVY-7322
            // static method call in trait?
            ClassNode type = null;
            if (isStaticTraitReceiver(receiver, var)) {
                type = receiver.getGenericsTypes()[0].getType();
            } else if (isThisTraitReceiver(var)) {
                type = receiver;
            }
            if (type != null && Traits.isTrait(type)) {
                ClassNode helper = Traits.findHelper(type);
                Parameter[] params = new Parameter[argumentTypes.length + 1];
                params[0] = new Parameter(ClassHelper.CLASS_Type.getPlainNodeReference(), "staticSelf");
                for (int i = 1; i < params.length; i++) {
                    params[i] = new Parameter(argumentTypes[i - 1], "p" + i);
                }
                MethodNode method = helper.getDeclaredMethod(name, params);
                if (method != null) {
                    return Collections.singletonList(makeDynamic(call, method.getReturnType()));
                }
            }
        }
        ClassNode dynamic = mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
        if (dynamic != null) {
            return Collections.singletonList(makeDynamic(call, dynamic));
        }
    }
    return NOTFOUND;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) MethodNode(org.codehaus.groovy.ast.MethodNode) Parameter(org.codehaus.groovy.ast.Parameter) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression)

Example 52 with Parameter

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

the class StaticTypeCheckingVisitor method addArrayMethods.

/**
 * add various getAt and setAt methods for primitive arrays
 * @param receiver the receiver class
 * @param name  the name of the method
 * @param args the argument classes
 */
private void addArrayMethods(List<MethodNode> methods, ClassNode receiver, String name, ClassNode[] args) {
    if (args.length != 1)
        return;
    if (!receiver.isArray())
        return;
    if (!isIntCategory(getUnwrapper(args[0])))
        return;
    if ("getAt".equals(name)) {
        MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, receiver.getComponentType(), new Parameter[] { new Parameter(args[0], "arg") }, null, null);
        node.setDeclaringClass(receiver.redirect());
        methods.add(node);
    } else if ("setAt".equals(name)) {
        MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, VOID_TYPE, new Parameter[] { new Parameter(args[0], "arg") }, null, null);
        node.setDeclaringClass(receiver.redirect());
        methods.add(node);
    }
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) Parameter(org.codehaus.groovy.ast.Parameter)

Example 53 with Parameter

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

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

the class StaticInvocationWriter method loadArguments.

protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
    if (para.length == 0)
        return;
    ClassNode lastParaType = para[para.length - 1].getOriginType();
    AsmClassGenerator acg = controller.getAcg();
    TypeChooser typeChooser = controller.getTypeChooser();
    OperandStack operandStack = controller.getOperandStack();
    ClassNode lastArgType = argumentList.size() > 0 ? typeChooser.resolveType(argumentList.get(argumentList.size() - 1), controller.getClassNode()) : null;
    if (lastParaType.isArray() && ((argumentList.size() > para.length) || ((argumentList.size() == (para.length - 1)) && !lastParaType.equals(lastArgType)) || ((argumentList.size() == para.length && lastArgType != null && !lastArgType.isArray()) && (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType, lastParaType.getComponentType()))) || ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType()))) {
        int stackLen = operandStack.getStackLength() + argumentList.size();
        MethodVisitor mv = controller.getMethodVisitor();
        MethodVisitor orig = mv;
        // mv = new org.objectweb.asm.util.TraceMethodVisitor(mv);
        controller.setMethodVisitor(mv);
        // first parameters as usual
        for (int i = 0; i < para.length - 1; i++) {
            Expression expression = argumentList.get(i);
            expression.visit(acg);
            if (!isNullConstant(expression)) {
                operandStack.doGroovyCast(para[i].getType());
            }
        }
        // last parameters wrapped in an array
        List<Expression> lastParams = new LinkedList<Expression>();
        for (int i = para.length - 1; i < argumentList.size(); i++) {
            lastParams.add(argumentList.get(i));
        }
        ArrayExpression array = new ArrayExpression(lastParaType.getComponentType(), lastParams);
        array.visit(acg);
        // adjust stack length
        while (operandStack.getStackLength() < stackLen) {
            operandStack.push(ClassHelper.OBJECT_TYPE);
        }
        if (argumentList.size() == para.length - 1) {
            operandStack.remove(1);
        }
    } else if (argumentList.size() == para.length) {
        for (int i = 0; i < argumentList.size(); i++) {
            Expression expression = argumentList.get(i);
            expression.visit(acg);
            if (!isNullConstant(expression)) {
                operandStack.doGroovyCast(para[i].getType());
            }
        }
    } else {
        // method call with default arguments
        ClassNode classNode = controller.getClassNode();
        Expression[] arguments = new Expression[para.length];
        for (int i = 0, j = 0; i < para.length; i++) {
            Parameter curParam = para[i];
            ClassNode curParamType = curParam.getType();
            Expression curArg = j < argumentList.size() ? argumentList.get(j) : null;
            Expression initialExpression = (Expression) curParam.getNodeMetaData(StaticTypesMarker.INITIAL_EXPRESSION);
            if (initialExpression == null && curParam.hasInitialExpression())
                initialExpression = curParam.getInitialExpression();
            if (initialExpression == null && curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION) != null) {
                initialExpression = (Expression) curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION);
            }
            ClassNode curArgType = curArg == null ? null : typeChooser.resolveType(curArg, classNode);
            if (initialExpression != null && !compatibleArgumentType(curArgType, curParamType)) {
                // use default expression
                arguments[i] = initialExpression;
            } else {
                arguments[i] = curArg;
                j++;
            }
        }
        for (int i = 0; i < arguments.length; i++) {
            Expression expression = arguments[i];
            expression.visit(acg);
            if (!isNullConstant(expression)) {
                operandStack.doGroovyCast(para[i].getType());
            }
        }
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) Parameter(org.codehaus.groovy.ast.Parameter) AsmClassGenerator(org.codehaus.groovy.classgen.AsmClassGenerator) LinkedList(java.util.LinkedList) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 55 with Parameter

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

the class StaticInvocationWriter method makeCall.

@Override
public void makeCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
    ClassNode dynamicCallReturnType = origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION);
    if (dynamicCallReturnType != null) {
        StaticTypesWriterController staticController = (StaticTypesWriterController) controller;
        if (origin instanceof MethodCallExpression) {
            ((MethodCallExpression) origin).setMethodTarget(null);
        }
        InvocationWriter dynamicInvocationWriter = staticController.getRegularInvocationWriter();
        dynamicInvocationWriter.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
        return;
    }
    if (tryImplicitReceiver(origin, message, arguments, adapter, safe, spreadSafe, implicitThis)) {
        return;
    }
    // if call is spread safe, replace it with a for in loop
    if (spreadSafe && origin instanceof MethodCallExpression) {
        MethodVisitor mv = controller.getMethodVisitor();
        CompileStack compileStack = controller.getCompileStack();
        TypeChooser typeChooser = controller.getTypeChooser();
        OperandStack operandStack = controller.getOperandStack();
        ClassNode classNode = controller.getClassNode();
        int counter = labelCounter.incrementAndGet();
        // create an empty arraylist
        VariableExpression result = new VariableExpression("spreadresult" + counter, StaticCompilationVisitor.ARRAYLIST_CLASSNODE);
        ConstructorCallExpression cce = new ConstructorCallExpression(StaticCompilationVisitor.ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
        cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, StaticCompilationVisitor.ARRAYLIST_CONSTRUCTOR);
        DeclarationExpression declr = new DeclarationExpression(result, Token.newSymbol("=", origin.getLineNumber(), origin.getColumnNumber()), cce);
        declr.visit(controller.getAcg());
        operandStack.pop();
        // if (receiver != null)
        receiver.visit(controller.getAcg());
        Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
        mv.visitJumpInsn(IFNULL, ifnull);
        // receiver consumed by if()
        operandStack.remove(1);
        Label nonull = compileStack.createLocalLabel("nonull_" + counter);
        mv.visitLabel(nonull);
        ClassNode componentType = StaticTypeCheckingVisitor.inferLoopElementType(typeChooser.resolveType(receiver, classNode));
        Parameter iterator = new Parameter(componentType, "for$it$" + counter);
        VariableExpression iteratorAsVar = new VariableExpression(iterator);
        MethodCallExpression origMCE = (MethodCallExpression) origin;
        MethodCallExpression newMCE = new MethodCallExpression(iteratorAsVar, origMCE.getMethodAsString(), origMCE.getArguments());
        newMCE.setImplicitThis(false);
        newMCE.setMethodTarget(origMCE.getMethodTarget());
        newMCE.setSafe(true);
        MethodCallExpression add = new MethodCallExpression(result, "add", newMCE);
        add.setImplicitThis(false);
        add.setMethodTarget(StaticCompilationVisitor.ARRAYLIST_ADD_METHOD);
        // for (e in receiver) { result.add(e?.method(arguments) }
        ForStatement stmt = new ForStatement(iterator, receiver, new ExpressionStatement(add));
        stmt.visit(controller.getAcg());
        // else { empty list }
        mv.visitLabel(ifnull);
        // end of if/else
        // return result list
        result.visit(controller.getAcg());
    } else if (safe && origin instanceof MethodCallExpression) {
        // wrap call in an IFNULL check
        MethodVisitor mv = controller.getMethodVisitor();
        CompileStack compileStack = controller.getCompileStack();
        OperandStack operandStack = controller.getOperandStack();
        int counter = labelCounter.incrementAndGet();
        // if (receiver != null)
        ExpressionAsVariableSlot slot = new ExpressionAsVariableSlot(controller, receiver);
        slot.visit(controller.getAcg());
        operandStack.box();
        Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
        mv.visitJumpInsn(IFNULL, ifnull);
        // receiver consumed by if()
        operandStack.remove(1);
        Label nonull = compileStack.createLocalLabel("nonull_" + counter);
        mv.visitLabel(nonull);
        MethodCallExpression origMCE = (MethodCallExpression) origin;
        MethodCallExpression newMCE = new MethodCallExpression(new VariableSlotLoader(slot.getType(), slot.getIndex(), controller.getOperandStack()), origMCE.getMethodAsString(), origMCE.getArguments());
        MethodNode methodTarget = origMCE.getMethodTarget();
        newMCE.setMethodTarget(methodTarget);
        newMCE.setSafe(false);
        newMCE.setImplicitThis(origMCE.isImplicitThis());
        newMCE.setSourcePosition(origMCE);
        newMCE.visit(controller.getAcg());
        compileStack.removeVar(slot.getIndex());
        ClassNode returnType = operandStack.getTopOperand();
        if (ClassHelper.isPrimitiveType(returnType) && !ClassHelper.VOID_TYPE.equals(returnType)) {
            operandStack.box();
        }
        Label endof = compileStack.createLocalLabel("endof_" + counter);
        mv.visitJumpInsn(GOTO, endof);
        mv.visitLabel(ifnull);
        // else { null }
        mv.visitInsn(ACONST_NULL);
        mv.visitLabel(endof);
    } else {
        if ((adapter == AsmClassGenerator.getGroovyObjectField || adapter == AsmClassGenerator.getField) && origin instanceof AttributeExpression) {
            String pname = ((PropertyExpression) origin).getPropertyAsString();
            CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
            if (pname != null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
                StaticTypesCallSiteWriter stcsw = (StaticTypesCallSiteWriter) callSiteWriter;
                TypeChooser typeChooser = controller.getTypeChooser();
                if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, safe, false, true)) {
                    return;
                }
            }
        }
        super.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) Label(org.objectweb.asm.Label) MethodVisitor(org.objectweb.asm.MethodVisitor) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Parameter(org.codehaus.groovy.ast.Parameter) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement)

Aggregations

Parameter (org.codehaus.groovy.ast.Parameter)342 ClassNode (org.codehaus.groovy.ast.ClassNode)202 MethodNode (org.codehaus.groovy.ast.MethodNode)135 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)117 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)111 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)102 Expression (org.codehaus.groovy.ast.expr.Expression)98 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)90 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)75 FieldNode (org.codehaus.groovy.ast.FieldNode)71 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)71 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)69 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)68 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)66 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)66 Statement (org.codehaus.groovy.ast.stmt.Statement)66 ArrayList (java.util.ArrayList)62 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)56 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)52 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)51