Search in sources :

Example 46 with MethodNode

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

the class StaticTypeCheckingVisitor method convertClosureTypeToSAMType.

/**
     * This method will convert a closure type to the appropriate SAM type, which will be used
     * to infer return type generics.
     *
     * @param closureType the inferred type of a closure (Closure<ClosureReturnType>)
     * @param samType the type into which the closure is coerced into
     * @return same SAM type, but completed with information from the closure node
     */
private static ClassNode convertClosureTypeToSAMType(final Expression expression, final ClassNode closureType, final ClassNode samType, final Map<String, GenericsType> placeholders) {
    if (!samType.isUsingGenerics())
        return samType;
    // use the generics information from the Closure to further specify the type
    MethodNode sam = findSAM(samType);
    if (closureType.isUsingGenerics() && sam != null) {
        //correct SAM type for generics
        //sam = applyGenericsContext(placeholders, sam);
        // the return type of the SAM method exactly corresponds to the inferred return type
        ClassNode samReturnType = sam.getReturnType();
        ClassNode closureReturnType = expression.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
        if (closureReturnType != null && closureReturnType.isUsingGenerics()) {
            ClassNode unwrapped = closureReturnType.getGenericsTypes()[0].getType();
            extractGenericsConnections(placeholders, unwrapped, samReturnType);
        } else if (samReturnType.isGenericsPlaceHolder()) {
            placeholders.put(samReturnType.getGenericsTypes()[0].getName(), closureType.getGenericsTypes()[0]);
        }
        // now repeat the same for each parameter given in the ClosureExpression
        if (expression instanceof ClosureExpression) {
            List<ClassNode[]> genericsToConnect = new LinkedList<ClassNode[]>();
            Parameter[] closureParams = ((ClosureExpression) expression).getParameters();
            ClassNode[] closureParamTypes = extractTypesFromParameters(closureParams);
            if (expression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) != null) {
                closureParamTypes = expression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
            }
            final Parameter[] parameters = sam.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                final Parameter parameter = parameters[i];
                if (parameter.getOriginType().isUsingGenerics() && closureParamTypes.length > i) {
                    genericsToConnect.add(new ClassNode[] { closureParamTypes[i], parameter.getOriginType() });
                }
            }
            for (ClassNode[] classNodes : genericsToConnect) {
                ClassNode found = classNodes[0];
                ClassNode expected = classNodes[1];
                if (!isAssignableTo(found, expected)) {
                    // probably facing a type mismatch
                    continue;
                }
                ClassNode generifiedType = GenericsUtils.parameterizeType(found, expected);
                while (expected.isArray()) {
                    expected = expected.getComponentType();
                    generifiedType = generifiedType.getComponentType();
                }
                if (expected.isGenericsPlaceHolder()) {
                    placeholders.put(expected.getGenericsTypes()[0].getName(), new GenericsType(generifiedType));
                } else {
                    GenericsType[] expectedGenericsTypes = expected.getGenericsTypes();
                    GenericsType[] foundGenericsTypes = generifiedType.getGenericsTypes();
                    for (int i = 0; i < expectedGenericsTypes.length; i++) {
                        final GenericsType type = expectedGenericsTypes[i];
                        if (type.isPlaceholder()) {
                            String name = type.getName();
                            placeholders.put(name, foundGenericsTypes[i]);
                        }
                    }
                }
            }
        }
    }
    ClassNode result = applyGenericsContext(placeholders, samType.redirect());
    return result;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) GenericsType(org.codehaus.groovy.ast.GenericsType) Parameter(org.codehaus.groovy.ast.Parameter) LinkedList(java.util.LinkedList) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint)

Example 47 with MethodNode

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

the class StaticTypeCheckingVisitor method checkReturnType.

protected ClassNode checkReturnType(final ReturnStatement statement) {
    Expression expression = statement.getExpression();
    ClassNode type = getType(expression);
    if (typeCheckingContext.getEnclosingClosure() != null) {
        return type;
    }
    MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
    if (enclosingMethod != null && typeCheckingContext.getEnclosingClosure() == null) {
        if (!enclosingMethod.isVoidMethod() && !type.equals(void_WRAPPER_TYPE) && !type.equals(VOID_TYPE) && !checkCompatibleAssignmentTypes(enclosingMethod.getReturnType(), type, null, false) && !(isNullConstant(expression))) {
            if (!extension.handleIncompatibleReturnType(statement, type)) {
                addStaticTypeError("Cannot return value of type " + type.toString(false) + " on method returning type " + enclosingMethod.getReturnType().toString(false), expression);
            }
        } else if (!enclosingMethod.isVoidMethod()) {
            ClassNode previousType = getInferredReturnType(enclosingMethod);
            ClassNode inferred = previousType == null ? type : lowestUpperBound(type, previousType);
            if (implementsInterfaceOrIsSubclassOf(inferred, enclosingMethod.getReturnType())) {
                if (missesGenericsTypes(inferred)) {
                    DeclarationExpression virtualDecl = new DeclarationExpression(new VariableExpression("{target}", enclosingMethod.getReturnType()), Token.newSymbol(EQUAL, -1, -1), new VariableExpression("{source}", type));
                    virtualDecl.setSourcePosition(statement);
                    virtualDecl.visit(this);
                    ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
                    if (!missesGenericsTypes(newlyInferred))
                        type = newlyInferred;
                }
                return type;
            } else {
                return enclosingMethod.getReturnType();
            }
        }
    }
    return type;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode)

Example 48 with MethodNode

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

the class MethodCallExpressionTransformer method tryTransformIsToCompareIdentity.

/**
     * Identifies a method call expression on {@link DefaultGroovyMethods#is(Object, Object)} and if recognized, transforms it into a {@link CompareIdentityExpression}.
     * @param call a method call to be transformed
     * @return null if the method call is not DGM#is, or {@link CompareIdentityExpression}
     */
private static Expression tryTransformIsToCompareIdentity(MethodCallExpression call) {
    MethodNode methodTarget = call.getMethodTarget();
    if (methodTarget instanceof ExtensionMethodNode && "is".equals(methodTarget.getName()) && methodTarget.getParameters().length == 1) {
        methodTarget = ((ExtensionMethodNode) methodTarget).getExtensionMethodNode();
        ClassNode owner = methodTarget.getDeclaringClass();
        if (DGM_CLASSNODE.equals(owner)) {
            Expression args = call.getArguments();
            if (args instanceof ArgumentListExpression) {
                ArgumentListExpression arguments = (ArgumentListExpression) args;
                List<Expression> exprs = arguments.getExpressions();
                if (exprs.size() == 1) {
                    CompareIdentityExpression cid = new CompareIdentityExpression(call.getObjectExpression(), exprs.get(0));
                    cid.setSourcePosition(call);
                    return cid;
                }
            }
        }
    }
    return null;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode) MethodNode(org.codehaus.groovy.ast.MethodNode) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) ExtensionMethodNode(org.codehaus.groovy.transform.stc.ExtensionMethodNode)

Example 49 with MethodNode

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

the class StaticMethodCallExpressionTransformer method transformStaticMethodCallExpression.

Expression transformStaticMethodCallExpression(final StaticMethodCallExpression orig) {
    MethodNode target = (MethodNode) orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
    if (target != null) {
        MethodCallExpression call = new MethodCallExpression(new ClassExpression(orig.getOwnerType()), orig.getMethod(), orig.getArguments());
        call.setMethodTarget(target);
        call.setSourcePosition(orig);
        call.copyNodeMetaData(orig);
        return transformer.transform(call);
    }
    return transformer.superTransform(orig);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression)

Example 50 with MethodNode

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

the class StaticTypeCheckingVisitor method visitClosureExpression.

@Override
public void visitClosureExpression(final ClosureExpression expression) {
    boolean oldStaticContext = typeCheckingContext.isInStaticContext;
    typeCheckingContext.isInStaticContext = false;
    // collect every variable expression used in the loop body
    final Map<VariableExpression, ClassNode> varOrigType = new HashMap<VariableExpression, ClassNode>();
    Statement code = expression.getCode();
    code.visit(new VariableExpressionTypeMemoizer(varOrigType));
    Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
    // first, collect closure shared variables and reinitialize types
    SharedVariableCollector collector = new SharedVariableCollector(getSourceUnit());
    collector.visitClosureExpression(expression);
    Set<VariableExpression> closureSharedExpressions = collector.getClosureSharedExpressions();
    Map<VariableExpression, ListHashMap> typesBeforeVisit = null;
    if (!closureSharedExpressions.isEmpty()) {
        typesBeforeVisit = new HashMap<VariableExpression, ListHashMap>();
        saveVariableExpressionMetadata(closureSharedExpressions, typesBeforeVisit);
    }
    // perform visit
    typeCheckingContext.pushEnclosingClosureExpression(expression);
    DelegationMetadata dmd = getDelegationMetadata(expression);
    if (dmd == null) {
        typeCheckingContext.delegationMetadata = new DelegationMetadata(typeCheckingContext.getEnclosingClassNode(), Closure.OWNER_FIRST, typeCheckingContext.delegationMetadata);
    } else {
        typeCheckingContext.delegationMetadata = new DelegationMetadata(dmd.getType(), dmd.getStrategy(), typeCheckingContext.delegationMetadata);
    }
    super.visitClosureExpression(expression);
    typeCheckingContext.delegationMetadata = typeCheckingContext.delegationMetadata.getParent();
    MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
    returnAdder.visitMethod(node);
    TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
    if (!enclosingClosure.getReturnTypes().isEmpty()) {
        ClassNode returnType = lowestUpperBound(enclosingClosure.getReturnTypes());
        storeInferredReturnType(expression, returnType);
        ClassNode inferredType = wrapClosureType(returnType);
        storeType(enclosingClosure.getClosureExpression(), inferredType);
    }
    typeCheckingContext.popEnclosingClosure();
    boolean typeChanged = isSecondPassNeededForControlStructure(varOrigType, oldTracker);
    if (typeChanged)
        visitClosureExpression(expression);
    // restore original metadata
    restoreVariableExpressionMetadata(typesBeforeVisit);
    typeCheckingContext.isInStaticContext = oldStaticContext;
    Parameter[] parameters = expression.getParameters();
    if (parameters != null) {
        for (Parameter parameter : parameters) {
            typeCheckingContext.controlStructureVariables.remove(parameter);
        }
    }
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedHashMap(java.util.LinkedHashMap) ListHashMap(org.codehaus.groovy.util.ListHashMap) HashMap(java.util.HashMap) CaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement) WhileStatement(org.codehaus.groovy.ast.stmt.WhileStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) SwitchStatement(org.codehaus.groovy.ast.stmt.SwitchStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) ListHashMap(org.codehaus.groovy.util.ListHashMap) MethodNode(org.codehaus.groovy.ast.MethodNode) Parameter(org.codehaus.groovy.ast.Parameter) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Aggregations

MethodNode (org.codehaus.groovy.ast.MethodNode)294 ClassNode (org.codehaus.groovy.ast.ClassNode)193 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)94 Parameter (org.codehaus.groovy.ast.Parameter)79 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)65 FieldNode (org.codehaus.groovy.ast.FieldNode)57 LinkedList (java.util.LinkedList)50 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)50 Expression (org.codehaus.groovy.ast.expr.Expression)49 LowestUpperBoundClassNode (org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode)47 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)43 AnnotationNode (org.codehaus.groovy.ast.AnnotationNode)39 ArrayList (java.util.ArrayList)36 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)36 Statement (org.codehaus.groovy.ast.stmt.Statement)34 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)33 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)30 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)29 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)27 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)27