Search in sources :

Example 26 with Variable

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

the class StatementMetaTypeChooser method resolveType.

public ClassNode resolveType(final Expression exp, final ClassNode current) {
    if (exp instanceof ClassExpression)
        return ClassHelper.CLASS_Type;
    OptimizingStatementWriter.StatementMeta meta = (OptimizingStatementWriter.StatementMeta) exp.getNodeMetaData(OptimizingStatementWriter.StatementMeta.class);
    ClassNode type = null;
    if (meta != null)
        type = meta.type;
    if (type != null)
        return type;
    if (exp instanceof VariableExpression) {
        VariableExpression ve = (VariableExpression) exp;
        if (ve.isClosureSharedVariable())
            return ve.getType();
        type = ve.getOriginType();
        if (ve.getAccessedVariable() instanceof FieldNode) {
            FieldNode fn = (FieldNode) ve.getAccessedVariable();
            if (!fn.getDeclaringClass().equals(current))
                return fn.getOriginType();
        }
    } else if (exp instanceof Variable) {
        Variable v = (Variable) exp;
        type = v.getOriginType();
    } else {
        type = exp.getType();
    }
    return type.redirect();
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) Variable(org.codehaus.groovy.ast.Variable) FieldNode(org.codehaus.groovy.ast.FieldNode) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression)

Example 27 with Variable

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

the class StaticTypeCheckingVisitor method storeType.

protected void storeType(Expression exp, ClassNode cn) {
    if (exp instanceof VariableExpression && ((VariableExpression) exp).isClosureSharedVariable() && isPrimitiveType(cn)) {
        cn = getWrapper(cn);
    } else if (exp instanceof MethodCallExpression && ((MethodCallExpression) exp).isSafe() && isPrimitiveType(cn)) {
        cn = getWrapper(cn);
    }
    if (cn == UNKNOWN_PARAMETER_TYPE) {
        // this can happen for example when "null" is used in an assignment or a method parameter.
        // In that case, instead of storing the virtual type, we must "reset" type information
        // by determining the declaration type of the expression
        storeType(exp, getOriginalDeclarationType(exp));
        return;
    }
    ClassNode oldValue = (ClassNode) exp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, cn);
    if (oldValue != null) {
        // this may happen when a variable declaration type is wider than the subsequent assignment values
        // for example :
        // def o = 1 // first, an int
        // o = 'String' // then a string
        // o = new Object() // and eventually an object !
        // in that case, the INFERRED_TYPE corresponds to the current inferred type, while
        // DECLARATION_INFERRED_TYPE is the type which should be used for the initial type declaration
        ClassNode oldDIT = (ClassNode) exp.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
        if (oldDIT != null) {
            exp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, cn == null ? oldDIT : lowestUpperBound(oldDIT, cn));
        } else {
            exp.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, cn == null ? null : lowestUpperBound(oldValue, cn));
        }
    }
    if (exp instanceof VariableExpression) {
        VariableExpression var = (VariableExpression) exp;
        final Variable accessedVariable = var.getAccessedVariable();
        if (accessedVariable != null && accessedVariable != exp && accessedVariable instanceof VariableExpression) {
            storeType((Expression) accessedVariable, cn);
        }
        if (var.isClosureSharedVariable() && cn != null) {
            List<ClassNode> assignedTypes = typeCheckingContext.closureSharedVariablesAssignmentTypes.get(var);
            if (assignedTypes == null) {
                assignedTypes = new LinkedList<ClassNode>();
                typeCheckingContext.closureSharedVariablesAssignmentTypes.put(var, assignedTypes);
            }
            assignedTypes.add(cn);
        }
        if (!typeCheckingContext.temporaryIfBranchTypeInformation.empty()) {
            List<ClassNode> temporaryTypesForExpression = getTemporaryTypesForExpression(exp);
            if (temporaryTypesForExpression != null && !temporaryTypesForExpression.isEmpty()) {
                // a type inference has been made on a variable which type was defined in an instanceof block
                // we erase available information with the new type
                temporaryTypesForExpression.clear();
            }
        }
    }
}
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)

Example 28 with Variable

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

the class StaticTypeCheckingVisitor method isSecondPassNeededForControlStructure.

protected boolean isSecondPassNeededForControlStructure(final Map<VariableExpression, ClassNode> varOrigType, final Map<VariableExpression, List<ClassNode>> oldTracker) {
    Map<VariableExpression, ClassNode> assignedVars = popAssignmentTracking(oldTracker);
    for (Map.Entry<VariableExpression, ClassNode> entry : assignedVars.entrySet()) {
        Variable key = findTargetVariable(entry.getKey());
        if (key instanceof VariableExpression) {
            ClassNode origType = varOrigType.get(key);
            ClassNode newType = entry.getValue();
            if (varOrigType.containsKey(key) && (origType == null || !newType.equals(origType))) {
                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) Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) ListHashMap(org.codehaus.groovy.util.ListHashMap) HashMap(java.util.HashMap)

Example 29 with Variable

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

the class StaticTypeCheckingVisitor method visitBinaryExpression.

@Override
public void visitBinaryExpression(BinaryExpression expression) {
    BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
    typeCheckingContext.pushEnclosingBinaryExpression(expression);
    try {
        final Expression leftExpression = expression.getLeftExpression();
        final Expression rightExpression = expression.getRightExpression();
        int op = expression.getOperation().getType();
        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 = new BinaryExpression(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 30 with Variable

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

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 = false;
    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)

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