Search in sources :

Example 81 with MethodNode

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

the class StaticTypeCheckingVisitor method visitClosureExpression.

@Override
public void visitClosureExpression(final ClosureExpression expression) {
    boolean oldStaticContext = typeCheckingContext.isInStaticContext;
    typeCheckingContext.isInStaticContext = false;
    // collect every variable expression used in the loop body
    final Map<VariableExpression, ClassNode> varOrigType = new HashMap<VariableExpression, ClassNode>();
    Statement code = expression.getCode();
    code.visit(new VariableExpressionTypeMemoizer(varOrigType));
    Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
    // first, collect closure shared variables and reinitialize types
    SharedVariableCollector collector = new SharedVariableCollector(getSourceUnit());
    collector.visitClosureExpression(expression);
    Set<VariableExpression> closureSharedExpressions = collector.getClosureSharedExpressions();
    Map<VariableExpression, ListHashMap> typesBeforeVisit = null;
    if (!closureSharedExpressions.isEmpty()) {
        typesBeforeVisit = new HashMap<VariableExpression, ListHashMap>();
        saveVariableExpressionMetadata(closureSharedExpressions, typesBeforeVisit);
    }
    // perform visit
    typeCheckingContext.pushEnclosingClosureExpression(expression);
    DelegationMetadata dmd = getDelegationMetadata(expression);
    if (dmd == null) {
        typeCheckingContext.delegationMetadata = new DelegationMetadata(typeCheckingContext.getEnclosingClassNode(), Closure.OWNER_FIRST, typeCheckingContext.delegationMetadata);
    } else {
        typeCheckingContext.delegationMetadata = new DelegationMetadata(dmd.getType(), dmd.getStrategy(), typeCheckingContext.delegationMetadata);
    }
    super.visitClosureExpression(expression);
    typeCheckingContext.delegationMetadata = typeCheckingContext.delegationMetadata.getParent();
    MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
    returnAdder.visitMethod(node);
    TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
    if (!enclosingClosure.getReturnTypes().isEmpty()) {
        ClassNode returnType = lowestUpperBound(enclosingClosure.getReturnTypes());
        storeInferredReturnType(expression, returnType);
        ClassNode inferredType = wrapClosureType(returnType);
        storeType(enclosingClosure.getClosureExpression(), inferredType);
    }
    typeCheckingContext.popEnclosingClosure();
    boolean typeChanged = isSecondPassNeededForControlStructure(varOrigType, oldTracker);
    if (typeChanged)
        visitClosureExpression(expression);
    // restore original metadata
    restoreVariableExpressionMetadata(typesBeforeVisit);
    typeCheckingContext.isInStaticContext = oldStaticContext;
    Parameter[] parameters = expression.getParameters();
    if (parameters != null) {
        for (Parameter parameter : parameters) {
            typeCheckingContext.controlStructureVariables.remove(parameter);
        }
    }
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedHashMap(java.util.LinkedHashMap) ListHashMap(org.codehaus.groovy.util.ListHashMap) HashMap(java.util.HashMap) CaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement) WhileStatement(org.codehaus.groovy.ast.stmt.WhileStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) SwitchStatement(org.codehaus.groovy.ast.stmt.SwitchStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) ListHashMap(org.codehaus.groovy.util.ListHashMap) MethodNode(org.codehaus.groovy.ast.MethodNode) Parameter(org.codehaus.groovy.ast.Parameter) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Example 82 with MethodNode

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

the class StaticTypeCheckingVisitor method ensureValidSetter.

/**
     * Given a binary expression corresponding to an assignment, will check that the type of the RHS matches one
     * of the possible setters and if not, throw a type checking error.
     * @param expression the assignment expression
     * @param leftExpression left expression of the assignment
     * @param rightExpression right expression of the assignment
     * @param setterInfo possible setters
     * @return true if type checking passed
     */
private boolean ensureValidSetter(final Expression expression, final Expression leftExpression, final Expression rightExpression, final SetterInfo setterInfo) {
    // for expressions like foo = { ... }
    // we know that the RHS type is a closure
    // but we must check if the binary expression is an assignment
    // because we need to check if a setter uses @DelegatesTo
    VariableExpression ve = varX("%", setterInfo.receiverType);
    // for compound assignment "x op= y" find type as if it was "x = (x op y)"
    final Expression newRightExpression = isCompoundAssignment(expression) ? binX(leftExpression, getOpWithoutEqual(expression), rightExpression) : rightExpression;
    MethodCallExpression call = callX(ve, setterInfo.name, newRightExpression);
    call.setImplicitThis(false);
    visitMethodCallExpression(call);
    MethodNode directSetterCandidate = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
    if (directSetterCandidate == null) {
        // notation AND that the RHS is not a boolean/String/Class
        for (MethodNode setter : setterInfo.setters) {
            ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
            if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
                call = callX(ve, setterInfo.name, castX(type, newRightExpression));
                call.setImplicitThis(false);
                visitMethodCallExpression(call);
                directSetterCandidate = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
                if (directSetterCandidate != null) {
                    break;
                }
            }
        }
    }
    if (directSetterCandidate != null) {
        for (MethodNode setter : setterInfo.setters) {
            if (setter == directSetterCandidate) {
                leftExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
                storeType(leftExpression, getType(newRightExpression));
                break;
            }
        }
    } else {
        ClassNode firstSetterType = setterInfo.setters.iterator().next().getParameters()[0].getOriginType();
        addAssignmentError(firstSetterType, getType(newRightExpression), expression);
        return true;
    }
    return false;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode)

Example 83 with MethodNode

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

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 84 with MethodNode

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

the class SuperCallTraitTransformer method transformBinaryExpression.

private Expression transformBinaryExpression(final BinaryExpression exp) {
    Expression trn = super.transform(exp);
    if (trn instanceof BinaryExpression) {
        BinaryExpression bin = (BinaryExpression) trn;
        Expression leftExpression = bin.getLeftExpression();
        if (bin.getOperation().getType() == Types.EQUAL && leftExpression instanceof PropertyExpression) {
            ClassNode traitReceiver = null;
            PropertyExpression leftPropertyExpression = (PropertyExpression) leftExpression;
            if (isTraitSuperPropertyExpression(leftPropertyExpression.getObjectExpression())) {
                PropertyExpression pexp = (PropertyExpression) leftPropertyExpression.getObjectExpression();
                traitReceiver = pexp.getObjectExpression().getType();
            }
            if (traitReceiver != null) {
                // A.super.foo = ...
                TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
                ClassNode helper = helpers.getHelper();
                String setterName = MetaProperty.getSetterName(leftPropertyExpression.getPropertyAsString());
                List<MethodNode> methods = helper.getMethods(setterName);
                for (MethodNode method : methods) {
                    Parameter[] parameters = method.getParameters();
                    if (parameters.length == 2 && parameters[0].getType().equals(traitReceiver)) {
                        ArgumentListExpression args = new ArgumentListExpression(new VariableExpression("this"), transform(exp.getRightExpression()));
                        MethodCallExpression setterCall = new MethodCallExpression(new ClassExpression(helper), setterName, args);
                        setterCall.setMethodTarget(method);
                        setterCall.setImplicitThis(false);
                        return setterCall;
                    }
                }
                return bin;
            }
        }
    }
    return trn;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) MethodNode(org.codehaus.groovy.ast.MethodNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) 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) Parameter(org.codehaus.groovy.ast.Parameter) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression)

Example 85 with MethodNode

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

the class StaticTypeCheckingVisitor method visitStaticMethodCallExpression.

@Override
public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) {
    final String name = call.getMethod();
    if (name == null) {
        addStaticTypeError("cannot resolve dynamic method name at compile time.", call);
        return;
    }
    if (extension.beforeMethodCall(call)) {
        extension.afterMethodCall(call);
        return;
    }
    Expression callArguments = call.getArguments();
    ArgumentListExpression argumentList = InvocationWriter.makeArgumentList(callArguments);
    checkForbiddenSpreadArgument(argumentList);
    final ClassNode receiver = call.getOwnerType();
    visitMethodCallArguments(receiver, argumentList, false, null);
    ClassNode[] args = getArgumentTypes(argumentList);
    try {
        // method call receivers are :
        //   - possible "with" receivers
        //   - the actual receiver as found in the method call expression
        //   - any of the potential receivers found in the instanceof temporary table
        // in that order
        List<Receiver<String>> receivers = new LinkedList<Receiver<String>>();
        addReceivers(receivers, makeOwnerList(new ClassExpression(receiver)), false);
        List<MethodNode> mn = null;
        Receiver<String> chosenReceiver = null;
        for (Receiver<String> currentReceiver : receivers) {
            mn = findMethod(currentReceiver.getType(), name, args);
            if (!mn.isEmpty()) {
                if (mn.size() == 1)
                    typeCheckMethodsWithGenericsOrFail(currentReceiver.getType(), args, mn.get(0), call);
                chosenReceiver = currentReceiver;
                break;
            }
        }
        if (mn.isEmpty()) {
            mn = extension.handleMissingMethod(receiver, name, argumentList, args, call);
        }
        boolean callArgsVisited = false;
        if (mn.isEmpty()) {
            addNoMatchingMethodError(receiver, name, args, call);
        } else {
            mn = disambiguateMethods(mn, receiver, args, call);
            if (mn.size() == 1) {
                MethodNode directMethodCallCandidate = mn.get(0);
                ClassNode returnType = getType(directMethodCallCandidate);
                if (returnType.isUsingGenerics() && !returnType.isEnum()) {
                    visitMethodCallArguments(receiver, argumentList, true, directMethodCallCandidate);
                    ClassNode irtg = inferReturnTypeGenerics(chosenReceiver.getType(), directMethodCallCandidate, callArguments);
                    returnType = irtg != null && implementsInterfaceOrIsSubclassOf(irtg, returnType) ? irtg : returnType;
                    callArgsVisited = true;
                }
                storeType(call, returnType);
                storeTargetMethod(call, directMethodCallCandidate);
            } else {
                addAmbiguousErrorMessage(mn, name, args, call);
            }
            if (!callArgsVisited) {
                visitMethodCallArguments(receiver, argumentList, true, (MethodNode) call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
            }
        }
    } finally {
        extension.afterMethodCall(call);
    }
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedList(java.util.LinkedList) MethodNode(org.codehaus.groovy.ast.MethodNode)

Aggregations

MethodNode (org.codehaus.groovy.ast.MethodNode)294 ClassNode (org.codehaus.groovy.ast.ClassNode)193 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)94 Parameter (org.codehaus.groovy.ast.Parameter)79 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)65 FieldNode (org.codehaus.groovy.ast.FieldNode)57 LinkedList (java.util.LinkedList)50 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)50 Expression (org.codehaus.groovy.ast.expr.Expression)49 LowestUpperBoundClassNode (org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode)47 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)43 AnnotationNode (org.codehaus.groovy.ast.AnnotationNode)39 ArrayList (java.util.ArrayList)36 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)36 Statement (org.codehaus.groovy.ast.stmt.Statement)34 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)33 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)30 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)29 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)27 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)27