Search in sources :

Example 41 with ASTNode

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

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

the class AbstractTypeCheckingExtension method makeDynamic.

/**
 * Used to instruct the type checker that the call is a dynamic method call.
 * Calling this method automatically sets the handled flag to true.
 * @param call the method call which is a dynamic method call
 * @param returnType the expected return type of the dynamic call
 * @return a virtual method node with the same name as the expected call
 */
public MethodNode makeDynamic(MethodCall call, ClassNode returnType) {
    TypeCheckingContext.EnclosingClosure enclosingClosure = context.getEnclosingClosure();
    MethodNode enclosingMethod = context.getEnclosingMethod();
    ((ASTNode) call).putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, returnType);
    if (enclosingClosure != null) {
        enclosingClosure.getClosureExpression().putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE);
    } else {
        enclosingMethod.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE);
    }
    setHandled(true);
    if (debug) {
        LOG.info("Turning " + call.getText() + " into a dynamic method call returning " + returnType.toString(false));
    }
    return new MethodNode(call.getMethodAsString(), 0, returnType, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) ASTNode(org.codehaus.groovy.ast.ASTNode)

Example 43 with ASTNode

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

the class BytecodeSequence method visit.

/**
 * Delegates to the visit method used for this class.
 * If the visitor is a ClassGenerator, then
 * {@link ClassGenerator#visitBytecodeSequence(BytecodeSequence)}
 * is called with this instance. If the visitor is no
 * ClassGenerator, then this method will call visit on
 * each ASTNode element sorted by this class. If one
 * element is a BytecodeInstruction, then it will be skipped
 * as it is no ASTNode.
 *
 * @param visitor the visitor
 * @see ClassGenerator
 */
public void visit(GroovyCodeVisitor visitor) {
    if (visitor instanceof ClassGenerator) {
        ClassGenerator gen = (ClassGenerator) visitor;
        gen.visitBytecodeSequence(this);
        return;
    }
    for (Iterator iterator = instructions.iterator(); iterator.hasNext(); ) {
        Object part = (Object) iterator.next();
        if (part instanceof ASTNode) {
            ((ASTNode) part).visit(visitor);
        }
    }
}
Also used : Iterator(java.util.Iterator) ASTNode(org.codehaus.groovy.ast.ASTNode)

Example 44 with ASTNode

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

the class GenericsUtils method resolveClassNode.

private static ClassNode resolveClassNode(final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage, final ClassNode parsedNode) {
    ClassNode dummyClass = new ClassNode("dummy", 0, ClassHelper.OBJECT_TYPE);
    dummyClass.setModule(new ModuleNode(sourceUnit));
    dummyClass.setGenericsTypes(mn.getDeclaringClass().getGenericsTypes());
    MethodNode dummyMN = new MethodNode("dummy", 0, parsedNode, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
    dummyMN.setGenericsTypes(mn.getGenericsTypes());
    dummyClass.addMethod(dummyMN);
    ResolveVisitor visitor = new ResolveVisitor(compilationUnit) {

        @Override
        protected void addError(final String msg, final ASTNode expr) {
            sourceUnit.addError(new IncorrectTypeHintException(mn, msg, usage.getLineNumber(), usage.getColumnNumber()));
        }
    };
    visitor.startResolving(dummyClass, sourceUnit);
    return dummyMN.getReturnType();
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) IncorrectTypeHintException(groovy.transform.stc.IncorrectTypeHintException) MethodNode(org.codehaus.groovy.ast.MethodNode) ASTNode(org.codehaus.groovy.ast.ASTNode) ResolveVisitor(org.codehaus.groovy.control.ResolveVisitor) ModuleNode(org.codehaus.groovy.ast.ModuleNode)

Example 45 with ASTNode

use of org.codehaus.groovy.ast.ASTNode in project repository-permissions-updater by jenkins-infra.

the class GradleVerifier method getGroupId.

public static String getGroupId(String contents) {
    String res = null;
    AstBuilder astBuilder = new AstBuilder();
    List<ASTNode> nodes = astBuilder.buildFromString(CompilePhase.SEMANTIC_ANALYSIS, false, contents);
    BlockStatement node = (BlockStatement) nodes.get(0);
    for (Statement s : node.getStatements()) {
        Expression e = ((ExpressionStatement) s).getExpression();
        if (e instanceof BinaryExpression) {
            BinaryExpression be = (BinaryExpression) e;
            VariableExpression v = (VariableExpression) be.getLeftExpression();
            if (v.getName().equals("group")) {
                if (be.getRightExpression() instanceof ConstantExpression) {
                    res = be.getRightExpression().getText();
                    break;
                }
            }
        }
    }
    return res;
}
Also used : AstBuilder(org.codehaus.groovy.ast.builder.AstBuilder) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) Statement(org.codehaus.groovy.ast.stmt.Statement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) ASTNode(org.codehaus.groovy.ast.ASTNode) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression)

Aggregations

ASTNode (org.codehaus.groovy.ast.ASTNode)52 MethodNode (org.codehaus.groovy.ast.MethodNode)21 ClassNode (org.codehaus.groovy.ast.ClassNode)20 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)19 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)19 Expression (org.codehaus.groovy.ast.expr.Expression)18 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)15 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)14 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)13 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)13 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)12 Statement (org.codehaus.groovy.ast.stmt.Statement)12 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)11 Parameter (org.codehaus.groovy.ast.Parameter)11 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)11 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)10 ArrayList (java.util.ArrayList)9 TupleExpression (org.codehaus.groovy.ast.expr.TupleExpression)9 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)8 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)7