Search in sources :

Example 91 with MethodNode

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

the class StaticTypeCheckingVisitor method getType.

protected ClassNode getType(ASTNode exp) {
    ClassNode cn = exp.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (cn != null)
        return cn;
    if (exp instanceof ClassExpression) {
        ClassNode node = CLASS_Type.getPlainNodeReference();
        node.setGenericsTypes(new GenericsType[] { new GenericsType(((ClassExpression) exp).getType()) });
        return node;
    } else if (exp instanceof VariableExpression) {
        VariableExpression vexp = (VariableExpression) exp;
        ClassNode selfTrait = isTraitSelf(vexp);
        if (selfTrait != null)
            return makeSelf(selfTrait);
        if (vexp == VariableExpression.THIS_EXPRESSION)
            return makeThis();
        if (vexp == VariableExpression.SUPER_EXPRESSION)
            return makeSuper();
        final Variable variable = vexp.getAccessedVariable();
        if (variable instanceof FieldNode) {
            checkOrMarkPrivateAccess(vexp, (FieldNode) variable, isLHSOfEnclosingAssignment(vexp));
            return getType((FieldNode) variable);
        }
        if (variable != null && variable != vexp && variable instanceof VariableExpression) {
            return getType((Expression) variable);
        }
        if (variable instanceof Parameter) {
            Parameter parameter = (Parameter) variable;
            ClassNode type = typeCheckingContext.controlStructureVariables.get(parameter);
            TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
            ClassNode[] closureParamTypes = (ClassNode[]) (enclosingClosure != null ? enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) : null);
            if (type == null && enclosingClosure != null && "it".equals(variable.getName()) && closureParamTypes != null) {
                final Parameter[] parameters = enclosingClosure.getClosureExpression().getParameters();
                if (parameters.length == 0 && getTemporaryTypesForExpression(vexp) == null) {
                    type = closureParamTypes[0];
                }
            }
            if (type != null) {
                storeType((VariableExpression) exp, type);
                return type;
            }
        }
    }
    if (exp instanceof ListExpression) {
        return inferListExpressionType((ListExpression) exp);
    } else if (exp instanceof MapExpression) {
        return inferMapExpressionType((MapExpression) exp);
    }
    if (exp instanceof ConstructorCallExpression) {
        return ((ConstructorCallExpression) exp).getType();
    }
    if (exp instanceof MethodNode) {
        if ((exp == GET_DELEGATE || exp == GET_OWNER || exp == GET_THISOBJECT) && typeCheckingContext.getEnclosingClosure() != null) {
            return typeCheckingContext.getEnclosingClassNode();
        }
        ClassNode ret = getInferredReturnType(exp);
        return ret != null ? ret : ((MethodNode) exp).getReturnType();
    }
    if (exp instanceof ClosureExpression) {
        ClassNode irt = getInferredReturnType(exp);
        if (irt != null) {
            irt = wrapTypeIfNecessary(irt);
            ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
            result.setGenericsTypes(new GenericsType[] { new GenericsType(irt) });
            return result;
        }
    }
    if (exp instanceof RangeExpression) {
        ClassNode plain = ClassHelper.RANGE_TYPE.getPlainNodeReference();
        RangeExpression re = (RangeExpression) exp;
        ClassNode fromType = getType(re.getFrom());
        ClassNode toType = getType(re.getTo());
        if (fromType.equals(toType)) {
            plain.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(fromType)) });
        } else {
            plain.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(lowestUpperBound(fromType, toType))) });
        }
        return plain;
    }
    if (exp instanceof UnaryPlusExpression) {
        return getType(((UnaryPlusExpression) exp).getExpression());
    }
    if (exp instanceof UnaryMinusExpression) {
        return getType(((UnaryMinusExpression) exp).getExpression());
    }
    if (exp instanceof BitwiseNegationExpression) {
        return getType(((BitwiseNegationExpression) exp).getExpression());
    }
    if (exp instanceof MethodCall) {
        MethodNode target = (MethodNode) exp.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
        if (target != null) {
            return getType(target);
        }
    }
    if (exp instanceof Parameter) {
        return ((Parameter) exp).getOriginType();
    }
    if (exp instanceof FieldNode) {
        FieldNode fn = (FieldNode) exp;
        return getGenericsResolvedTypeOfFieldOrProperty(fn, fn.getOriginType());
    }
    if (exp instanceof PropertyNode) {
        PropertyNode pn = (PropertyNode) exp;
        return getGenericsResolvedTypeOfFieldOrProperty(pn, pn.getOriginType());
    }
    return exp instanceof VariableExpression ? ((VariableExpression) exp).getOriginType() : ((Expression) exp).getType();
}
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) FieldNode(org.codehaus.groovy.ast.FieldNode) MethodNode(org.codehaus.groovy.ast.MethodNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) GenericsType(org.codehaus.groovy.ast.GenericsType) Parameter(org.codehaus.groovy.ast.Parameter)

Example 92 with MethodNode

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

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(varX("{target}", enclosingMethod.getReturnType()), Token.newSymbol(EQUAL, -1, -1), varX("{source}", type));
                    virtualDecl.setSourcePosition(statement);
                    virtualDecl.visit(this);
                    ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
                    if (!missesGenericsTypes(newlyInferred))
                        type = newlyInferred;
                } else {
                    checkTypeGenerics(enclosingMethod.getReturnType(), inferred, expression);
                }
                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 93 with MethodNode

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

the class StaticTypeCheckingSupport method removeCovariantsAndInterfaceEquivalents.

private static Collection<MethodNode> removeCovariantsAndInterfaceEquivalents(Collection<MethodNode> collection) {
    if (collection.size() <= 1)
        return collection;
    List<MethodNode> toBeRemoved = new LinkedList<MethodNode>();
    List<MethodNode> list = new LinkedList<MethodNode>(new HashSet<MethodNode>(collection));
    for (int i = 0; i < list.size() - 1; i++) {
        MethodNode one = list.get(i);
        if (toBeRemoved.contains(one))
            continue;
        for (int j = i + 1; j < list.size(); j++) {
            MethodNode two = list.get(j);
            if (toBeRemoved.contains(two))
                continue;
            if (one.getParameters().length == two.getParameters().length) {
                if (areOverloadMethodsInSameClass(one, two)) {
                    if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) {
                        removeMethodWithSuperReturnType(toBeRemoved, one, two);
                    } else {
                        // this is an imperfect solution to determining if two methods are
                        // equivalent, for example String#compareTo(Object) and String#compareTo(String)
                        // in that case, Java marks the Object version as synthetic
                        removeSyntheticMethodIfOne(toBeRemoved, one, two);
                    }
                } else if (areEquivalentInterfaceMethods(one, two)) {
                    // GROOVY-6970 choose between equivalent interface methods
                    removeMethodInSuperInterface(toBeRemoved, one, two);
                }
            }
        }
    }
    if (toBeRemoved.isEmpty())
        return list;
    List<MethodNode> result = new LinkedList<MethodNode>(list);
    result.removeAll(toBeRemoved);
    return result;
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) LinkedList(java.util.LinkedList)

Example 94 with MethodNode

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

the class InnerClassCompletionVisitor method addDispatcherMethods.

private static void addDispatcherMethods(ClassNode classNode) {
    final int objectDistance = getObjectDistance(classNode);
    // since we added an anonymous inner class we should also
    // add the dispatcher methods
    // add method dispatcher
    Parameter[] parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "args") };
    MethodNode method = classNode.addSyntheticMethod("this$dist$invoke$" + objectDistance, ACC_PUBLIC + ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    BlockStatement block = new BlockStatement();
    setMethodDispatcherCode(block, VariableExpression.THIS_EXPRESSION, parameters);
    method.setCode(block);
    // add property setter
    parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "value") };
    method = classNode.addSyntheticMethod("this$dist$set$" + objectDistance, ACC_PUBLIC + ACC_SYNTHETIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    setPropertySetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
    method.setCode(block);
    // add property getter
    parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name") };
    method = classNode.addSyntheticMethod("this$dist$get$" + objectDistance, ACC_PUBLIC + ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    setPropertyGetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
    method.setCode(block);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) Parameter(org.codehaus.groovy.ast.Parameter) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement)

Example 95 with MethodNode

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

the class InnerClassCompletionVisitor method addDefaultMethods.

private void addDefaultMethods(InnerClassNode node) {
    final boolean isStatic = isStatic(node);
    ClassNode outerClass = node.getOuterClass();
    final String classInternalName = org.codehaus.groovy.classgen.asm.BytecodeHelper.getClassInternalName(node);
    final String outerClassInternalName = getInternalName(outerClass, isStatic);
    final String outerClassDescriptor = getTypeDescriptor(outerClass, isStatic);
    final int objectDistance = getObjectDistance(outerClass);
    // add missing method dispatcher
    Parameter[] parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "args") };
    String methodName = "methodMissing";
    if (isStatic)
        addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
    MethodNode method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    BlockStatement block = new BlockStatement();
    if (isStatic) {
        setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
    } else {
        block.addStatement(new BytecodeSequence(new BytecodeInstruction() {

            public void visit(MethodVisitor mv) {
                getThis(mv, classInternalName, outerClassDescriptor, outerClassInternalName);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$invoke$" + objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", false);
                mv.visitInsn(ARETURN);
            }
        }));
    }
    method.setCode(block);
    // add static missing method dispatcher
    methodName = "$static_methodMissing";
    if (isStatic)
        addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
    method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
    method.setCode(block);
    // add property setter dispatcher
    parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "val") };
    methodName = "propertyMissing";
    if (isStatic)
        addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
    method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    if (isStatic) {
        setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
    } else {
        block.addStatement(new BytecodeSequence(new BytecodeInstruction() {

            public void visit(MethodVisitor mv) {
                getThis(mv, classInternalName, outerClassDescriptor, outerClassInternalName);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$set$" + objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
                mv.visitInsn(RETURN);
            }
        }));
    }
    method.setCode(block);
    // add static property missing setter dispatcher
    methodName = "$static_propertyMissing";
    if (isStatic)
        addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
    method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
    method.setCode(block);
    // add property getter dispatcher
    parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name") };
    methodName = "propertyMissing";
    if (isStatic)
        addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
    method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    if (isStatic) {
        setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
    } else {
        block.addStatement(new BytecodeSequence(new BytecodeInstruction() {

            public void visit(MethodVisitor mv) {
                getThis(mv, classInternalName, outerClassDescriptor, outerClassInternalName);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$get$" + objectDistance, "(Ljava/lang/String;)Ljava/lang/Object;", false);
                mv.visitInsn(ARETURN);
            }
        }));
    }
    method.setCode(block);
    // add static property missing getter dispatcher
    methodName = "$static_propertyMissing";
    if (isStatic)
        addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
    method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
    block = new BlockStatement();
    setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
    method.setCode(block);
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) Parameter(org.codehaus.groovy.ast.Parameter) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) MethodVisitor(org.objectweb.asm.MethodVisitor)

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