Search in sources :

Example 21 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 22 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 23 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 24 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 25 with ASTNode

use of org.codehaus.groovy.ast.ASTNode in project spring-boot by spring-projects.

the class AnnotatedNodeASTTransformation method visit.

@Override
public void visit(ASTNode[] nodes, SourceUnit source) {
    this.sourceUnit = source;
    List<AnnotationNode> annotationNodes = new ArrayList<>();
    ClassVisitor classVisitor = new ClassVisitor(source, annotationNodes);
    for (ASTNode node : nodes) {
        if (node instanceof ModuleNode) {
            ModuleNode module = (ModuleNode) node;
            visitAnnotatedNode(module.getPackage(), annotationNodes);
            for (ImportNode importNode : module.getImports()) {
                visitAnnotatedNode(importNode, annotationNodes);
            }
            for (ImportNode importNode : module.getStarImports()) {
                visitAnnotatedNode(importNode, annotationNodes);
            }
            for (Map.Entry<String, ImportNode> entry : module.getStaticImports().entrySet()) {
                visitAnnotatedNode(entry.getValue(), annotationNodes);
            }
            for (Map.Entry<String, ImportNode> entry : module.getStaticStarImports().entrySet()) {
                visitAnnotatedNode(entry.getValue(), annotationNodes);
            }
            for (ClassNode classNode : module.getClasses()) {
                visitAnnotatedNode(classNode, annotationNodes);
                classNode.visitContents(classVisitor);
            }
        }
    }
    processAnnotationNodes(annotationNodes);
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) AnnotationNode(org.codehaus.groovy.ast.AnnotationNode) ArrayList(java.util.ArrayList) ASTNode(org.codehaus.groovy.ast.ASTNode) ImportNode(org.codehaus.groovy.ast.ImportNode) Map(java.util.Map) ModuleNode(org.codehaus.groovy.ast.ModuleNode)

Aggregations

ASTNode (org.codehaus.groovy.ast.ASTNode)27 MethodNode (org.codehaus.groovy.ast.MethodNode)17 ClassNode (org.codehaus.groovy.ast.ClassNode)15 Parameter (org.codehaus.groovy.ast.Parameter)10 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)8 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)8 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)7 Variable (org.codehaus.groovy.ast.Variable)6 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)6 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)6 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)6 Expression (org.codehaus.groovy.ast.expr.Expression)6 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)6 TupleExpression (org.codehaus.groovy.ast.expr.TupleExpression)6 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)6 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)6 LinkedList (java.util.LinkedList)5 FieldNode (org.codehaus.groovy.ast.FieldNode)5 ClosureSignatureHint (groovy.transform.stc.ClosureSignatureHint)4 DynamicVariable (org.codehaus.groovy.ast.DynamicVariable)4