Search in sources :

Example 56 with MethodNode

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

the class TraitASTTransformation method createHelperClass.

private ClassNode createHelperClass(final ClassNode cNode) {
    ClassNode helper = new InnerClassNode(cNode, Traits.helperClassName(cNode), ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, ClassNode.EMPTY_ARRAY, null);
    cNode.setModifiers(ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT);
    checkInnerClasses(cNode);
    MethodNode initializer = createInitMethod(false, cNode, helper);
    MethodNode staticInitializer = createInitMethod(true, cNode, helper);
    // apply the verifier to have the property nodes generated
    generatePropertyMethods(cNode);
    // prepare fields
    List<FieldNode> fields = new ArrayList<FieldNode>();
    Set<String> fieldNames = new HashSet<String>();
    for (FieldNode field : cNode.getFields()) {
        if (!"metaClass".equals(field.getName()) && (!field.isSynthetic() || field.getName().indexOf('$') < 0)) {
            fields.add(field);
            fieldNames.add(field.getName());
        }
    }
    ClassNode fieldHelper = null;
    if (!fields.isEmpty()) {
        fieldHelper = new InnerClassNode(cNode, Traits.fieldHelperClassName(cNode), ACC_STATIC | ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, ClassHelper.OBJECT_TYPE);
    }
    // add methods
    List<MethodNode> methods = new ArrayList<MethodNode>(cNode.getMethods());
    List<MethodNode> nonPublicAPIMethods = new LinkedList<MethodNode>();
    for (final MethodNode methodNode : methods) {
        boolean declared = methodNode.getDeclaringClass() == cNode;
        if (declared) {
            if (!methodNode.isSynthetic() && (methodNode.isProtected() || methodNode.getModifiers() == 0)) {
                unit.addError(new SyntaxException("Cannot have protected/package private method in a trait (" + cNode.getName() + "#" + methodNode.getTypeDescriptor() + ")", methodNode.getLineNumber(), methodNode.getColumnNumber()));
                return null;
            }
            helper.addMethod(processMethod(cNode, helper, methodNode, fieldHelper, fieldNames));
            if (methodNode.isPrivate() || methodNode.isStatic()) {
                nonPublicAPIMethods.add(methodNode);
            }
        }
    }
    // remove methods which should not appear in the trait interface
    for (MethodNode privateMethod : nonPublicAPIMethods) {
        cNode.removeMethod(privateMethod);
    }
    // add fields
    for (FieldNode field : fields) {
        processField(field, initializer, staticInitializer, fieldHelper, helper, cNode, fieldNames);
    }
    // clear properties to avoid generation of methods
    cNode.getProperties().clear();
    // copy annotations
    copyClassAnnotations(cNode, helper);
    // reuse the full list of fields
    fields = new ArrayList<FieldNode>(cNode.getFields());
    for (FieldNode field : fields) {
        cNode.removeField(field.getName());
    }
    // visit AST xforms
    registerASTTranformations(helper);
    unit.getAST().addClass(helper);
    if (fieldHelper != null) {
        unit.getAST().addClass(fieldHelper);
    }
    // resolve scope (for closures)
    resolveScope(helper);
    if (fieldHelper != null) {
        resolveScope(fieldHelper);
    }
    return helper;
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) ArrayList(java.util.ArrayList) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedList(java.util.LinkedList) MethodNode(org.codehaus.groovy.ast.MethodNode) SyntaxException(org.codehaus.groovy.syntax.SyntaxException) HashSet(java.util.HashSet)

Example 57 with MethodNode

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

the class StaticTypeCheckingVisitor method visitClass.

@Override
public void visitClass(final ClassNode node) {
    if (shouldSkipClassNode(node))
        return;
    if (extension.beforeVisitClass(node)) {
        extension.afterVisitClass(node);
        return;
    }
    Object type = node.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type != null) {
        // transformation has already been run on this class node
        // so we'll use a silent collector in order not to duplicate errors
        typeCheckingContext.pushErrorCollector();
    }
    typeCheckingContext.pushEnclosingClassNode(node);
    Set<MethodNode> oldVisitedMethod = typeCheckingContext.alreadyVisitedMethods;
    typeCheckingContext.alreadyVisitedMethods = new LinkedHashSet<MethodNode>();
    super.visitClass(node);
    Iterator<InnerClassNode> innerClasses = node.getInnerClasses();
    while (innerClasses.hasNext()) {
        InnerClassNode innerClassNode = innerClasses.next();
        visitClass(innerClassNode);
    }
    typeCheckingContext.alreadyVisitedMethods = oldVisitedMethod;
    node.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, node);
    // works in a two pass sequence and we don't want to skip the second pass
    for (MethodNode methodNode : node.getMethods()) {
        methodNode.putNodeMetaData(StaticTypeCheckingVisitor.class, Boolean.TRUE);
    }
    for (ConstructorNode constructorNode : node.getDeclaredConstructors()) {
        constructorNode.putNodeMetaData(StaticTypeCheckingVisitor.class, Boolean.TRUE);
    }
    extension.afterVisitClass(node);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 58 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 59 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 60 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)

Aggregations

MethodNode (org.codehaus.groovy.ast.MethodNode)292 ClassNode (org.codehaus.groovy.ast.ClassNode)192 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)93 Parameter (org.codehaus.groovy.ast.Parameter)78 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)38 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