Search in sources :

Example 36 with Variable

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

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);
    } else if (exp instanceof PropertyExpression && ((PropertyExpression) 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 37 with Variable

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

the class BinaryExpressionMultiTypeDispatcher method doAssignmentToLocalVariable.

private boolean doAssignmentToLocalVariable(String method, BinaryExpression binExp) {
    Expression left = binExp.getLeftExpression();
    if (left instanceof VariableExpression) {
        VariableExpression ve = (VariableExpression) left;
        Variable v = ve.getAccessedVariable();
        if (v instanceof DynamicVariable)
            return false;
        if (v instanceof PropertyExpression)
            return false;
    /* field and declaration we don't return false */
    } else {
        return false;
    }
    evaluateBinaryExpression(method, binExp);
    getController().getOperandStack().dup();
    getController().getCompileStack().pushLHS(true);
    binExp.getLeftExpression().visit(getController().getAcg());
    getController().getCompileStack().popLHS();
    return true;
}
Also used : Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) Expression(org.codehaus.groovy.ast.expr.Expression) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression)

Example 38 with Variable

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

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 39 with Variable

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

the class ClosureWriter method getClosureSharedVariables.

protected Parameter[] getClosureSharedVariables(ClosureExpression ce) {
    VariableScope scope = ce.getVariableScope();
    Parameter[] ret = new Parameter[scope.getReferencedLocalVariablesCount()];
    int index = 0;
    for (Iterator iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext(); ) {
        Variable element = (org.codehaus.groovy.ast.Variable) iter.next();
        Parameter p = new Parameter(element.getType(), element.getName());
        p.setOriginType(element.getOriginType());
        p.setClosureSharedVariable(element.isClosureSharedVariable());
        ret[index] = p;
        index++;
    }
    return ret;
}
Also used : Variable(org.codehaus.groovy.ast.Variable) Iterator(java.util.Iterator) Parameter(org.codehaus.groovy.ast.Parameter) VariableScope(org.codehaus.groovy.ast.VariableScope)

Example 40 with Variable

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

the class StaticTypeCheckingVisitor method performSecondPass.

public void performSecondPass() {
    for (SecondPassExpression wrapper : typeCheckingContext.secondPassExpressions) {
        Expression expression = wrapper.getExpression();
        if (expression instanceof BinaryExpression) {
            Expression left = ((BinaryExpression) expression).getLeftExpression();
            if (left instanceof VariableExpression) {
                // should always be the case
                // this should always be the case, but adding a test is safer
                Variable target = findTargetVariable((VariableExpression) left);
                if (target instanceof VariableExpression) {
                    VariableExpression var = (VariableExpression) target;
                    List<ClassNode> classNodes = typeCheckingContext.closureSharedVariablesAssignmentTypes.get(var);
                    if (classNodes != null && classNodes.size() > 1) {
                        ClassNode lub = lowestUpperBound(classNodes);
                        String message = getOperationName(((BinaryExpression) expression).getOperation().getType());
                        if (message != null) {
                            List<MethodNode> method = findMethod(lub, message, getType(((BinaryExpression) expression).getRightExpression()));
                            if (method.isEmpty()) {
                                addStaticTypeError("A closure shared variable [" + target.getName() + "] has been assigned with various types and the method" + " [" + toMethodParametersString(message, getType(((BinaryExpression) expression).getRightExpression())) + "]" + " does not exist in the lowest upper bound of those types: [" + lub.toString(false) + "]. In general, this is a bad practice (variable reuse) because the compiler cannot" + " determine safely what is the type of the variable at the moment of the call in a multithreaded context.", expression);
                            }
                        }
                    }
                }
            }
        } else if (expression instanceof MethodCallExpression) {
            MethodCallExpression call = (MethodCallExpression) expression;
            Expression objectExpression = call.getObjectExpression();
            if (objectExpression instanceof VariableExpression) {
                // this should always be the case, but adding a test is safer
                Variable target = findTargetVariable((VariableExpression) objectExpression);
                if (target instanceof VariableExpression) {
                    VariableExpression var = (VariableExpression) target;
                    List<ClassNode> classNodes = typeCheckingContext.closureSharedVariablesAssignmentTypes.get(var);
                    if (classNodes != null && classNodes.size() > 1) {
                        ClassNode lub = lowestUpperBound(classNodes);
                        MethodNode methodNode = (MethodNode) call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
                        // we must check that such a method exists on the LUB
                        Parameter[] parameters = methodNode.getParameters();
                        ClassNode[] params = extractTypesFromParameters(parameters);
                        ClassNode[] argTypes = (ClassNode[]) wrapper.getData();
                        List<MethodNode> method = findMethod(lub, methodNode.getName(), argTypes);
                        if (method.size() != 1) {
                            addStaticTypeError("A closure shared variable [" + target.getName() + "] has been assigned with various types and the method" + " [" + toMethodParametersString(methodNode.getName(), params) + "]" + " does not exist in the lowest upper bound of those types: [" + lub.toString(false) + "]. In general, this is a bad practice (variable reuse) because the compiler cannot" + " determine safely what is the type of the variable at the moment of the call in a multithreaded context.", call);
                        }
                    }
                }
            }
        }
    }
    // give a chance to type checker extensions to throw errors based on information gathered afterwards
    extension.finish();
}
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) 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