Search in sources :

Example 11 with Variable

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

the class StaticTypeCheckingVisitor method visitMethodCallExpression.

@Override
public void visitMethodCallExpression(MethodCallExpression call) {
    final String name = call.getMethodAsString();
    if (name == null) {
        addStaticTypeError("cannot resolve dynamic method name at compile time.", call.getMethod());
        return;
    }
    if (extension.beforeMethodCall(call)) {
        extension.afterMethodCall(call);
        return;
    }
    typeCheckingContext.pushEnclosingMethodCall(call);
    final Expression objectExpression = call.getObjectExpression();
    objectExpression.visit(this);
    call.getMethod().visit(this);
    // the call is made on a collection type
    if (call.isSpreadSafe()) {
        //TODO check if this should not be change to iterator based call logic
        ClassNode expressionType = getType(objectExpression);
        if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) && !expressionType.isArray()) {
            addStaticTypeError("Spread operator can only be used on collection types", objectExpression);
            return;
        } else {
            // type check call as if it was made on component type
            ClassNode componentType = inferComponentType(expressionType, int_TYPE);
            MethodCallExpression subcall = callX(castX(componentType, EmptyExpression.INSTANCE), name, call.getArguments());
            subcall.setLineNumber(call.getLineNumber());
            subcall.setColumnNumber(call.getColumnNumber());
            subcall.setImplicitThis(call.isImplicitThis());
            visitMethodCallExpression(subcall);
            // the inferred type here should be a list of what the subcall returns
            ClassNode subcallReturnType = getType(subcall);
            ClassNode listNode = LIST_TYPE.getPlainNodeReference();
            listNode.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(subcallReturnType)) });
            storeType(call, listNode);
            // store target method
            storeTargetMethod(call, (MethodNode) subcall.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
            typeCheckingContext.popEnclosingMethodCall();
            return;
        }
    }
    Expression callArguments = call.getArguments();
    ArgumentListExpression argumentList = InvocationWriter.makeArgumentList(callArguments);
    checkForbiddenSpreadArgument(argumentList);
    // for arguments, we need to visit closures *after* the method has been chosen
    final ClassNode receiver = getType(objectExpression);
    visitMethodCallArguments(receiver, argumentList, false, null);
    ClassNode[] args = getArgumentTypes(argumentList);
    final boolean isCallOnClosure = isClosureCall(name, objectExpression, callArguments);
    try {
        boolean callArgsVisited = false;
        if (isCallOnClosure) {
            // this is a closure.call() call
            if (objectExpression == VariableExpression.THIS_EXPRESSION) {
                // isClosureCall() check verified earlier that a field exists
                FieldNode field = typeCheckingContext.getEnclosingClassNode().getDeclaredField(name);
                GenericsType[] genericsTypes = field.getType().getGenericsTypes();
                if (genericsTypes != null) {
                    ClassNode closureReturnType = genericsTypes[0].getType();
                    Object data = field.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
                    if (data != null) {
                        Parameter[] parameters = (Parameter[]) data;
                        typeCheckClosureCall(callArguments, args, parameters);
                    }
                    storeType(call, closureReturnType);
                }
            } else if (objectExpression instanceof VariableExpression) {
                Variable variable = findTargetVariable((VariableExpression) objectExpression);
                if (variable instanceof ASTNode) {
                    Object data = ((ASTNode) variable).getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
                    if (data != null) {
                        Parameter[] parameters = (Parameter[]) data;
                        typeCheckClosureCall(callArguments, args, parameters);
                    }
                    ClassNode type = getType(((ASTNode) variable));
                    if (type != null && type.equals(CLOSURE_TYPE)) {
                        GenericsType[] genericsTypes = type.getGenericsTypes();
                        type = OBJECT_TYPE;
                        if (genericsTypes != null) {
                            if (!genericsTypes[0].isPlaceholder()) {
                                type = genericsTypes[0].getType();
                            }
                        }
                    }
                    if (type != null) {
                        storeType(call, type);
                    }
                }
            } else if (objectExpression instanceof ClosureExpression) {
                // we can get actual parameters directly
                Parameter[] parameters = ((ClosureExpression) objectExpression).getParameters();
                typeCheckClosureCall(callArguments, args, parameters);
                ClassNode data = getInferredReturnType(objectExpression);
                if (data != null) {
                    storeType(call, data);
                }
            }
            int nbOfArgs;
            if (callArguments instanceof ArgumentListExpression) {
                ArgumentListExpression list = (ArgumentListExpression) callArguments;
                nbOfArgs = list.getExpressions().size();
            } else {
                // todo : other cases
                nbOfArgs = 0;
            }
            storeTargetMethod(call, nbOfArgs == 0 ? CLOSURE_CALL_NO_ARG : nbOfArgs == 1 ? CLOSURE_CALL_ONE_ARG : CLOSURE_CALL_VARGS);
        } else {
            // 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>>();
            List<Receiver<String>> owners = makeOwnerList(objectExpression);
            addReceivers(receivers, owners, call.isImplicitThis());
            List<MethodNode> mn = null;
            Receiver<String> chosenReceiver = null;
            for (Receiver<String> currentReceiver : receivers) {
                ClassNode receiverType = currentReceiver.getType();
                mn = findMethod(receiverType, name, args);
                // ensure that all methods are either static or declared by the current receiver or a superclass
                if (!mn.isEmpty() && (typeCheckingContext.isInStaticContext || (receiverType.getModifiers() & Opcodes.ACC_STATIC) != 0) && (call.isImplicitThis() || (objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression()))) {
                    // we create separate method lists just to be able to print out
                    // a nice error message to the user
                    // a method is accessible if it is static, or if we are not in a static context and it is
                    // declared by the current receiver or a superclass
                    List<MethodNode> accessibleMethods = new LinkedList<MethodNode>();
                    List<MethodNode> inaccessibleMethods = new LinkedList<MethodNode>();
                    for (final MethodNode node : mn) {
                        if (node.isStatic() || (!typeCheckingContext.isInStaticContext && implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))) {
                            accessibleMethods.add(node);
                        } else {
                            inaccessibleMethods.add(node);
                        }
                    }
                    mn = accessibleMethods;
                    if (accessibleMethods.isEmpty()) {
                        // choose an arbitrary method to display an error message
                        MethodNode node = inaccessibleMethods.get(0);
                        ClassNode owner = node.getDeclaringClass();
                        addStaticTypeError("Non static method " + owner.getName() + "#" + node.getName() + " cannot be called from static context", call);
                    }
                }
                if (!mn.isEmpty()) {
                    chosenReceiver = currentReceiver;
                    break;
                }
            }
            if (mn.isEmpty() && typeCheckingContext.getEnclosingClosure() != null && args.length == 0) {
                // add special handling of getDelegate() and getOwner()
                if ("getDelegate".equals(name)) {
                    mn = Collections.singletonList(GET_DELEGATE);
                } else if ("getOwner".equals(name)) {
                    mn = Collections.singletonList(GET_OWNER);
                } else if ("getThisObject".equals(name)) {
                    mn = Collections.singletonList(GET_THISOBJECT);
                }
            }
            if (mn.isEmpty()) {
                mn = extension.handleMissingMethod(receiver, name, argumentList, args, call);
            }
            if (mn.isEmpty()) {
                addNoMatchingMethodError(receiver, name, args, call);
            } else {
                if (areCategoryMethodCalls(mn, name, args)) {
                    addCategoryMethodCallError(call);
                }
                mn = disambiguateMethods(mn, chosenReceiver != null ? chosenReceiver.getType() : null, args, call);
                if (mn.size() == 1) {
                    MethodNode directMethodCallCandidate = mn.get(0);
                    if (call.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION) == null && !directMethodCallCandidate.isStatic() && objectExpression instanceof ClassExpression && !"java.lang.Class".equals(directMethodCallCandidate.getDeclaringClass().getName())) {
                        ClassNode owner = directMethodCallCandidate.getDeclaringClass();
                        addStaticTypeError("Non static method " + owner.getName() + "#" + directMethodCallCandidate.getName() + " cannot be called from static context", call);
                    }
                    if (chosenReceiver == null) {
                        chosenReceiver = Receiver.make(directMethodCallCandidate.getDeclaringClass());
                    }
                    ClassNode returnType = getType(directMethodCallCandidate);
                    if (isUsingGenericsOrIsArrayUsingGenerics(returnType)) {
                        visitMethodCallArguments(chosenReceiver.getType(), argumentList, true, directMethodCallCandidate);
                        ClassNode irtg = inferReturnTypeGenerics(chosenReceiver.getType(), directMethodCallCandidate, callArguments, call.getGenericsTypes());
                        returnType = irtg != null && implementsInterfaceOrIsSubclassOf(irtg, returnType) ? irtg : returnType;
                        callArgsVisited = true;
                    }
                    if (directMethodCallCandidate == GET_DELEGATE && typeCheckingContext.getEnclosingClosure() != null) {
                        DelegationMetadata md = getDelegationMetadata(typeCheckingContext.getEnclosingClosure().getClosureExpression());
                        returnType = typeCheckingContext.getEnclosingClassNode();
                        if (md != null) {
                            returnType = md.getType();
                        }
                    }
                    if (typeCheckMethodsWithGenericsOrFail(chosenReceiver.getType(), args, mn.get(0), call)) {
                        returnType = adjustWithTraits(directMethodCallCandidate, chosenReceiver.getType(), args, returnType);
                        storeType(call, returnType);
                        storeTargetMethod(call, directMethodCallCandidate);
                        String data = chosenReceiver.getData();
                        if (data != null) {
                            // the method which has been chosen is supposed to be a call on delegate or owner
                            // so we store the information so that the static compiler may reuse it
                            call.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, data);
                        }
                        // if the object expression is a closure shared variable, we will have to perform a second pass
                        if (objectExpression instanceof VariableExpression) {
                            VariableExpression var = (VariableExpression) objectExpression;
                            if (var.isClosureSharedVariable()) {
                                SecondPassExpression<ClassNode[]> wrapper = new SecondPassExpression<ClassNode[]>(call, args);
                                typeCheckingContext.secondPassExpressions.add(wrapper);
                            }
                        }
                    }
                } else {
                    addAmbiguousErrorMessage(mn, name, args, call);
                }
            }
        }
        // now that a method has been chosen, we are allowed to visit the closures
        if (!callArgsVisited) {
            MethodNode mn = (MethodNode) call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
            visitMethodCallArguments(receiver, argumentList, true, mn);
            // GROOVY-6219
            if (mn != null) {
                List<Expression> argExpressions = argumentList.getExpressions();
                Parameter[] parameters = mn.getParameters();
                for (int i = 0; i < argExpressions.size() && i < parameters.length; i++) {
                    Expression arg = argExpressions.get(i);
                    ClassNode pType = parameters[i].getType();
                    ClassNode aType = getType(arg);
                    if (CLOSURE_TYPE.equals(pType) && CLOSURE_TYPE.equals(aType)) {
                        if (!isAssignableTo(aType, pType)) {
                            addNoMatchingMethodError(receiver, name, getArgumentTypes(argumentList), call);
                            call.removeNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
                        }
                    }
                }
            }
        }
    } finally {
        typeCheckingContext.popEnclosingMethodCall();
        extension.afterMethodCall(call);
    }
}
Also used : Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) MethodNode(org.codehaus.groovy.ast.MethodNode) GenericsType(org.codehaus.groovy.ast.GenericsType) ASTNode(org.codehaus.groovy.ast.ASTNode) LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint) LinkedList(java.util.LinkedList) Parameter(org.codehaus.groovy.ast.Parameter)

Example 12 with Variable

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

the class StaticTypeCheckingVisitor method allowStaticAccessToMember.

/**
     * This method is used to filter search results in which null means "no match",
     * to filter out illegal access to instance members from a static context.
     *
     * Return null if the given member is not static, but we want to access in
     * a static way (staticOnly=true). If we want to access in a non-static way
     * we always return the member, since then access to static members and
     * non-static members is allowed.
     */
@SuppressWarnings("unchecked")
private <T> T allowStaticAccessToMember(T member, boolean staticOnly) {
    if (member == null)
        return null;
    if (!staticOnly)
        return member;
    boolean isStatic;
    if (member instanceof Variable) {
        Variable v = (Variable) member;
        isStatic = Modifier.isStatic(v.getModifiers());
    } else if (member instanceof List) {
        List<MethodNode> list = (List<MethodNode>) member;
        if (list.size() == 1) {
            return (T) Collections.singletonList(allowStaticAccessToMember(list.get(0), staticOnly));
        }
        return (T) Collections.emptyList();
    } else {
        MethodNode mn = (MethodNode) member;
        isStatic = mn.isStatic();
    }
    if (staticOnly && !isStatic)
        return null;
    return member;
}
Also used : Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) MethodNode(org.codehaus.groovy.ast.MethodNode) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Example 13 with Variable

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

the class StaticTypeCheckingVisitor method visitBinaryExpression.

@Override
public void visitBinaryExpression(BinaryExpression expression) {
    int op = expression.getOperation().getType();
    if (op == COMPARE_IDENTICAL || op == COMPARE_NOT_IDENTICAL) {
        // we'll report those as errors later
        return;
    }
    BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
    typeCheckingContext.pushEnclosingBinaryExpression(expression);
    try {
        final Expression leftExpression = expression.getLeftExpression();
        final Expression rightExpression = expression.getRightExpression();
        leftExpression.visit(this);
        SetterInfo setterInfo = removeSetterInfo(leftExpression);
        if (setterInfo != null) {
            if (ensureValidSetter(expression, leftExpression, rightExpression, setterInfo)) {
                return;
            }
        } else {
            rightExpression.visit(this);
        }
        ClassNode lType = getType(leftExpression);
        ClassNode rType = getType(rightExpression);
        if (isNullConstant(rightExpression)) {
            if (!isPrimitiveType(lType))
                // primitive types should be ignored as they will result in another failure
                rType = UNKNOWN_PARAMETER_TYPE;
        }
        BinaryExpression reversedBinaryExpression = binX(rightExpression, expression.getOperation(), leftExpression);
        ClassNode resultType = op == KEYWORD_IN ? getResultType(rType, op, lType, reversedBinaryExpression) : getResultType(lType, op, rType, expression);
        if (op == KEYWORD_IN) {
            // in case of the "in" operator, the receiver and the arguments are reversed
            // so we use the reversedExpression and get the target method from it
            storeTargetMethod(expression, (MethodNode) reversedBinaryExpression.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
        } else if (op == LEFT_SQUARE_BRACKET && leftExpression instanceof VariableExpression && leftExpression.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE) == null) {
            storeType(leftExpression, lType);
        }
        if (resultType == null) {
            resultType = lType;
        }
        // if left expression is a closure shared variable, a second pass should be done
        if (leftExpression instanceof VariableExpression) {
            VariableExpression leftVar = (VariableExpression) leftExpression;
            if (leftVar.isClosureSharedVariable()) {
                // if left expression is a closure shared variable, we should check it twice
                // see GROOVY-5874
                typeCheckingContext.secondPassExpressions.add(new SecondPassExpression<Void>(expression));
            }
        }
        if (lType.isUsingGenerics() && missesGenericsTypes(resultType) && isAssignment(op)) {
            // unchecked assignment
            // examples:
            // List<A> list = new LinkedList()
            // List<A> list = []
            // Iterable<A> list = new LinkedList()
            // in that case, the inferred type of the binary expression is the type of the RHS
            // "completed" with generics type information available in the LHS
            ClassNode completedType = GenericsUtils.parameterizeType(lType, resultType.getPlainNodeReference());
            resultType = completedType;
        }
        if (isArrayOp(op) && enclosingBinaryExpression != null && enclosingBinaryExpression.getLeftExpression() == expression && isAssignment(enclosingBinaryExpression.getOperation().getType()) && !lType.isArray()) {
            // left hand side of an assignment : map['foo'] = ...
            Expression enclosingBE_rightExpr = enclosingBinaryExpression.getRightExpression();
            if (!(enclosingBE_rightExpr instanceof ClosureExpression)) {
                enclosingBE_rightExpr.visit(this);
            }
            ClassNode[] arguments = { rType, getType(enclosingBE_rightExpr) };
            List<MethodNode> nodes = findMethod(lType.redirect(), "putAt", arguments);
            if (nodes.size() == 1) {
                typeCheckMethodsWithGenericsOrFail(lType, arguments, nodes.get(0), enclosingBE_rightExpr);
            } else if (nodes.isEmpty()) {
                addNoMatchingMethodError(lType, "putAt", arguments, enclosingBinaryExpression);
            }
        }
        boolean isEmptyDeclaration = expression instanceof DeclarationExpression && rightExpression instanceof EmptyExpression;
        if (!isEmptyDeclaration && isAssignment(op)) {
            if (rightExpression instanceof ConstructorCallExpression) {
                inferDiamondType((ConstructorCallExpression) rightExpression, lType);
            }
            ClassNode originType = getOriginalDeclarationType(leftExpression);
            typeCheckAssignment(expression, leftExpression, originType, rightExpression, resultType);
            // and we must update the result type
            if (!implementsInterfaceOrIsSubclassOf(getWrapper(resultType), getWrapper(originType))) {
                resultType = originType;
            } else if (lType.isUsingGenerics() && !lType.isEnum() && hasRHSIncompleteGenericTypeInfo(resultType)) {
                // for example, LHS is List<ConcreteClass> and RHS is List<T> where T is a placeholder
                resultType = lType;
            }
            // make sure we keep primitive types
            if (isPrimitiveType(originType) && resultType.equals(getWrapper(originType))) {
                resultType = originType;
            }
            // if we are in an if/else branch, keep track of assignment
            if (typeCheckingContext.ifElseForWhileAssignmentTracker != null && leftExpression instanceof VariableExpression && !isNullConstant(rightExpression)) {
                Variable accessedVariable = ((VariableExpression) leftExpression).getAccessedVariable();
                if (accessedVariable instanceof VariableExpression) {
                    VariableExpression var = (VariableExpression) accessedVariable;
                    List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
                    if (types == null) {
                        types = new LinkedList<ClassNode>();
                        ClassNode type = var.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
                        types.add(type);
                        typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
                    }
                    types.add(resultType);
                }
            }
            storeType(leftExpression, resultType);
            // if right expression is a ClosureExpression, store parameter type information
            if (leftExpression instanceof VariableExpression) {
                if (rightExpression instanceof ClosureExpression) {
                    Parameter[] parameters = ((ClosureExpression) rightExpression).getParameters();
                    leftExpression.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, parameters);
                } else if (rightExpression instanceof VariableExpression && ((VariableExpression) rightExpression).getAccessedVariable() instanceof Expression && ((Expression) ((VariableExpression) rightExpression).getAccessedVariable()).getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) != null) {
                    Variable targetVariable = findTargetVariable((VariableExpression) leftExpression);
                    if (targetVariable instanceof ASTNode) {
                        ((ASTNode) targetVariable).putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, ((Expression) ((VariableExpression) rightExpression).getAccessedVariable()).getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS));
                    }
                }
            }
        } else if (op == KEYWORD_INSTANCEOF) {
            pushInstanceOfTypeInfo(leftExpression, rightExpression);
        }
        if (!isEmptyDeclaration) {
            storeType(expression, resultType);
        }
    } finally {
        typeCheckingContext.popEnclosingBinaryExpression();
    }
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint) MethodNode(org.codehaus.groovy.ast.MethodNode) ASTNode(org.codehaus.groovy.ast.ASTNode) Parameter(org.codehaus.groovy.ast.Parameter)

Example 14 with Variable

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

the class StaticTypeCheckingVisitor method getType.

protected ClassNode getType(ASTNode exp) {
    ClassNode cn = exp.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (cn != null)
        return cn;
    if (exp instanceof ClassExpression) {
        ClassNode node = CLASS_Type.getPlainNodeReference();
        node.setGenericsTypes(new GenericsType[] { new GenericsType(((ClassExpression) exp).getType()) });
        return node;
    } else if (exp instanceof VariableExpression) {
        VariableExpression vexp = (VariableExpression) exp;
        ClassNode selfTrait = isTraitSelf(vexp);
        if (selfTrait != null)
            return makeSelf(selfTrait);
        if (vexp == VariableExpression.THIS_EXPRESSION)
            return makeThis();
        if (vexp == VariableExpression.SUPER_EXPRESSION)
            return makeSuper();
        final Variable variable = vexp.getAccessedVariable();
        if (variable instanceof FieldNode) {
            checkOrMarkPrivateAccess(vexp, (FieldNode) variable, isLHSOfEnclosingAssignment(vexp));
            return getType((FieldNode) variable);
        }
        if (variable != null && variable != vexp && variable instanceof VariableExpression) {
            return getType((Expression) variable);
        }
        if (variable instanceof Parameter) {
            Parameter parameter = (Parameter) variable;
            ClassNode type = typeCheckingContext.controlStructureVariables.get(parameter);
            TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
            ClassNode[] closureParamTypes = (ClassNode[]) (enclosingClosure != null ? enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) : null);
            if (type == null && enclosingClosure != null && "it".equals(variable.getName()) && closureParamTypes != null) {
                final Parameter[] parameters = enclosingClosure.getClosureExpression().getParameters();
                if (parameters.length == 0 && getTemporaryTypesForExpression(vexp) == null) {
                    type = closureParamTypes[0];
                }
            }
            if (type != null) {
                storeType((VariableExpression) exp, type);
                return type;
            }
        }
    }
    if (exp instanceof ListExpression) {
        return inferListExpressionType((ListExpression) exp);
    } else if (exp instanceof MapExpression) {
        return inferMapExpressionType((MapExpression) exp);
    }
    if (exp instanceof ConstructorCallExpression) {
        return ((ConstructorCallExpression) exp).getType();
    }
    if (exp instanceof MethodNode) {
        if ((exp == GET_DELEGATE || exp == GET_OWNER || exp == GET_THISOBJECT) && typeCheckingContext.getEnclosingClosure() != null) {
            return typeCheckingContext.getEnclosingClassNode();
        }
        ClassNode ret = getInferredReturnType(exp);
        return ret != null ? ret : ((MethodNode) exp).getReturnType();
    }
    if (exp instanceof ClosureExpression) {
        ClassNode irt = getInferredReturnType(exp);
        if (irt != null) {
            irt = wrapTypeIfNecessary(irt);
            ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
            result.setGenericsTypes(new GenericsType[] { new GenericsType(irt) });
            return result;
        }
    }
    if (exp instanceof RangeExpression) {
        ClassNode plain = ClassHelper.RANGE_TYPE.getPlainNodeReference();
        RangeExpression re = (RangeExpression) exp;
        ClassNode fromType = getType(re.getFrom());
        ClassNode toType = getType(re.getTo());
        if (fromType.equals(toType)) {
            plain.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(fromType)) });
        } else {
            plain.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(lowestUpperBound(fromType, toType))) });
        }
        return plain;
    }
    if (exp instanceof UnaryPlusExpression) {
        return getType(((UnaryPlusExpression) exp).getExpression());
    }
    if (exp instanceof UnaryMinusExpression) {
        return getType(((UnaryMinusExpression) exp).getExpression());
    }
    if (exp instanceof BitwiseNegationExpression) {
        return getType(((BitwiseNegationExpression) exp).getExpression());
    }
    if (exp instanceof MethodCall) {
        MethodNode target = (MethodNode) exp.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
        if (target != null) {
            return getType(target);
        }
    }
    if (exp instanceof Parameter) {
        return ((Parameter) exp).getOriginType();
    }
    if (exp instanceof FieldNode) {
        FieldNode fn = (FieldNode) exp;
        return getGenericsResolvedTypeOfFieldOrProperty(fn, fn.getOriginType());
    }
    if (exp instanceof PropertyNode) {
        PropertyNode pn = (PropertyNode) exp;
        return getGenericsResolvedTypeOfFieldOrProperty(pn, pn.getOriginType());
    }
    return exp instanceof VariableExpression ? ((VariableExpression) exp).getOriginType() : ((Expression) exp).getType();
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) FieldNode(org.codehaus.groovy.ast.FieldNode) MethodNode(org.codehaus.groovy.ast.MethodNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) GenericsType(org.codehaus.groovy.ast.GenericsType) Parameter(org.codehaus.groovy.ast.Parameter)

Example 15 with Variable

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

the class StaticTypeCheckingSupport method isTraitSelf.

public static ClassNode isTraitSelf(VariableExpression vexp) {
    if (Traits.THIS_OBJECT.equals(vexp.getName())) {
        Variable accessedVariable = vexp.getAccessedVariable();
        ClassNode type = accessedVariable != null ? accessedVariable.getType() : null;
        if (accessedVariable instanceof Parameter && Traits.isTrait(type)) {
            return type;
        }
    }
    return null;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) Variable(org.codehaus.groovy.ast.Variable) Parameter(org.codehaus.groovy.ast.Parameter)

Aggregations

Variable (org.codehaus.groovy.ast.Variable)43 DynamicVariable (org.codehaus.groovy.ast.DynamicVariable)23 ClassNode (org.codehaus.groovy.ast.ClassNode)21 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)16 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)15 FieldNode (org.codehaus.groovy.ast.FieldNode)14 MethodNode (org.codehaus.groovy.ast.MethodNode)13 LowestUpperBoundClassNode (org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode)13 Parameter (org.codehaus.groovy.ast.Parameter)12 Expression (org.codehaus.groovy.ast.expr.Expression)9 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)7 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)7 LinkedList (java.util.LinkedList)6 ASTNode (org.codehaus.groovy.ast.ASTNode)6 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)6 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)6 VariableScope (org.codehaus.groovy.ast.VariableScope)5 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)5 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)5 ClosureSignatureHint (groovy.transform.stc.ClosureSignatureHint)4