Search in sources :

Example 66 with PropertyNode

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

the class CategoryASTTransformation method visit.

/**
     * Property invocations done on 'this' reference are transformed so that the invocations at runtime are
     * done on the additional parameter 'self'
     */
public void visit(ASTNode[] nodes, final SourceUnit source) {
    if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof ClassNode)) {
        source.getErrorCollector().addError(new SyntaxErrorMessage(new SyntaxException("@Category can only be added to a ClassNode but got: " + (nodes.length == 2 ? nodes[1] : "nothing"), nodes[0].getLineNumber(), nodes[0].getColumnNumber()), source));
    }
    AnnotationNode annotation = (AnnotationNode) nodes[0];
    ClassNode parent = (ClassNode) nodes[1];
    ClassNode targetClass = getTargetClass(source, annotation);
    thisExpression.setType(targetClass);
    final LinkedList<Set<String>> varStack = new LinkedList<Set<String>>();
    if (!ensureNoInstanceFieldOrProperty(source, parent))
        return;
    Set<String> names = new HashSet<String>();
    for (FieldNode field : parent.getFields()) {
        names.add(field.getName());
    }
    for (PropertyNode field : parent.getProperties()) {
        names.add(field.getName());
    }
    varStack.add(names);
    final Reference parameter = new Reference();
    final ClassCodeExpressionTransformer expressionTransformer = new ClassCodeExpressionTransformer() {

        protected SourceUnit getSourceUnit() {
            return source;
        }

        private void addVariablesToStack(Parameter[] params) {
            Set<String> names = new HashSet<String>();
            names.addAll(varStack.getLast());
            for (Parameter param : params) {
                names.add(param.getName());
            }
            varStack.add(names);
        }

        @Override
        public void visitCatchStatement(CatchStatement statement) {
            varStack.getLast().add(statement.getVariable().getName());
            super.visitCatchStatement(statement);
            varStack.getLast().remove(statement.getVariable().getName());
        }

        @Override
        public void visitMethod(MethodNode node) {
            addVariablesToStack(node.getParameters());
            super.visitMethod(node);
            varStack.removeLast();
        }

        @Override
        public void visitBlockStatement(BlockStatement block) {
            Set<String> names = new HashSet<String>();
            names.addAll(varStack.getLast());
            varStack.add(names);
            super.visitBlockStatement(block);
            varStack.remove(names);
        }

        @Override
        public void visitClosureExpression(ClosureExpression ce) {
            addVariablesToStack(ce.getParameters());
            super.visitClosureExpression(ce);
            varStack.removeLast();
        }

        @Override
        public void visitDeclarationExpression(DeclarationExpression expression) {
            if (expression.isMultipleAssignmentDeclaration()) {
                TupleExpression te = expression.getTupleExpression();
                List<Expression> list = te.getExpressions();
                for (Expression arg : list) {
                    VariableExpression ve = (VariableExpression) arg;
                    varStack.getLast().add(ve.getName());
                }
            } else {
                VariableExpression ve = expression.getVariableExpression();
                varStack.getLast().add(ve.getName());
            }
            super.visitDeclarationExpression(expression);
        }

        @Override
        public void visitForLoop(ForStatement forLoop) {
            Expression exp = forLoop.getCollectionExpression();
            exp.visit(this);
            Parameter loopParam = forLoop.getVariable();
            if (loopParam != null) {
                varStack.getLast().add(loopParam.getName());
            }
            super.visitForLoop(forLoop);
        }

        @Override
        public void visitExpressionStatement(ExpressionStatement es) {
            // GROOVY-3543: visit the declaration expressions so that declaration variables get added on the varStack
            Expression exp = es.getExpression();
            if (exp instanceof DeclarationExpression) {
                exp.visit(this);
            }
            super.visitExpressionStatement(es);
        }

        @Override
        public Expression transform(Expression exp) {
            if (exp instanceof VariableExpression) {
                VariableExpression ve = (VariableExpression) exp;
                if (ve.getName().equals("this"))
                    return thisExpression;
                else {
                    if (!varStack.getLast().contains(ve.getName())) {
                        return new PropertyExpression(thisExpression, ve.getName());
                    }
                }
            } else if (exp instanceof PropertyExpression) {
                PropertyExpression pe = (PropertyExpression) exp;
                if (pe.getObjectExpression() instanceof VariableExpression) {
                    VariableExpression vex = (VariableExpression) pe.getObjectExpression();
                    if (vex.isThisExpression()) {
                        pe.setObjectExpression(thisExpression);
                        return pe;
                    }
                }
            } else if (exp instanceof ClosureExpression) {
                ClosureExpression ce = (ClosureExpression) exp;
                ce.getVariableScope().putReferencedLocalVariable((Parameter) parameter.get());
                Parameter[] params = ce.getParameters();
                if (params == null) {
                    params = Parameter.EMPTY_ARRAY;
                } else if (params.length == 0) {
                    params = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE, "it") };
                }
                addVariablesToStack(params);
                ce.getCode().visit(this);
                varStack.removeLast();
            }
            return super.transform(exp);
        }
    };
    for (MethodNode method : parent.getMethods()) {
        if (!method.isStatic()) {
            method.setModifiers(method.getModifiers() | Opcodes.ACC_STATIC);
            final Parameter[] origParams = method.getParameters();
            final Parameter[] newParams = new Parameter[origParams.length + 1];
            Parameter p = new Parameter(targetClass, "$this");
            p.setClosureSharedVariable(true);
            newParams[0] = p;
            parameter.set(p);
            System.arraycopy(origParams, 0, newParams, 1, origParams.length);
            method.setParameters(newParams);
            expressionTransformer.visitMethod(method);
        }
    }
    new VariableScopeVisitor(source, true).visitClass(parent);
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) MethodNode(org.codehaus.groovy.ast.MethodNode) AnnotationNode(org.codehaus.groovy.ast.AnnotationNode) SyntaxException(org.codehaus.groovy.syntax.SyntaxException) PropertyNode(org.codehaus.groovy.ast.PropertyNode) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) HashSet(java.util.HashSet) ClassCodeExpressionTransformer(org.codehaus.groovy.ast.ClassCodeExpressionTransformer) ClassNode(org.codehaus.groovy.ast.ClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) SyntaxErrorMessage(org.codehaus.groovy.control.messages.SyntaxErrorMessage) Reference(groovy.lang.Reference) DeclarationExpression(org.codehaus.groovy.ast.expr.DeclarationExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) LinkedList(java.util.LinkedList) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) Expression(org.codehaus.groovy.ast.expr.Expression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) DeclarationExpression(org.codehaus.groovy.ast.expr.DeclarationExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Parameter(org.codehaus.groovy.ast.Parameter) VariableScopeVisitor(org.codehaus.groovy.classgen.VariableScopeVisitor)

Example 67 with PropertyNode

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

the class ImmutableASTTransformation method createConstructors.

private void createConstructors(ClassNode cNode, List<String> knownImmutableClasses, List<String> knownImmutables, boolean includeSuperProperties) {
    if (!validateConstructors(cNode))
        return;
    List<PropertyNode> list = getInstanceProperties(cNode);
    if (includeSuperProperties) {
        ClassNode next = cNode.getSuperClass();
        while (next != null) {
            List<PropertyNode> tail = list;
            list = getInstanceProperties(next);
            list.addAll(tail);
            next = next.getSuperClass();
        }
    }
    boolean specialHashMapCase = list.size() == 1 && list.get(0).getField().getType().equals(HASHMAP_TYPE);
    if (specialHashMapCase) {
        createConstructorMapSpecial(cNode, list);
    } else {
        createConstructorMap(cNode, list, knownImmutableClasses, knownImmutables);
        createConstructorOrdered(cNode, list);
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode)

Example 68 with PropertyNode

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

the class ImmutableASTTransformation method createCopyWith.

private static void createCopyWith(final ClassNode cNode, final List<PropertyNode> pList) {
    BlockStatement body = new BlockStatement();
    body.addStatement(ifS(orX(equalsNullX(varX("map", ClassHelper.MAP_TYPE)), eqX(callX(varX("map", HASHMAP_TYPE), "size"), constX(0))), returnS(varX("this", cNode))));
    body.addStatement(declS(varX("dirty", ClassHelper.boolean_TYPE), ConstantExpression.PRIM_FALSE));
    body.addStatement(declS(varX("construct", HASHMAP_TYPE), ctorX(HASHMAP_TYPE)));
    // Check for each property
    for (final PropertyNode pNode : pList) {
        body.addStatement(createCheckForProperty(pNode));
    }
    body.addStatement(returnS(ternaryX(isTrueX(varX("dirty", ClassHelper.boolean_TYPE)), ctorX(cNode, args(varX("construct", HASHMAP_TYPE))), varX("this", cNode))));
    final ClassNode clonedNode = cNode.getPlainNodeReference();
    cNode.addMethod(COPY_WITH_METHOD, ACC_PUBLIC | ACC_FINAL, clonedNode, params(new Parameter(new ClassNode(Map.class), "map")), null, body);
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) Parameter(org.codehaus.groovy.ast.Parameter) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Map(java.util.Map) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap)

Example 69 with PropertyNode

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

the class PropertyTest method testInheritedProperties.

public void testInheritedProperties() throws Exception {
    ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC + ACC_SUPER, ClassHelper.make(DummyBean.class));
    classNode.addProperty(new PropertyNode("bar", ACC_PUBLIC, ClassHelper.STRING_TYPE, classNode, null, null, null));
    Class fooClass = loadClass(classNode);
    assertTrue("Loaded a new class", fooClass != null);
    Object bean = fooClass.newInstance();
    assertTrue("Managed to create bean", bean != null);
    assertField(fooClass, "bar", 0, ClassHelper.STRING_TYPE);
    assertGetProperty(bean, "name", "James");
    assertSetProperty(bean, "name", "Bob");
    assertGetProperty(bean, "bar", null);
    assertSetProperty(bean, "bar", "newValue");
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) DummyBean(org.codehaus.groovy.runtime.DummyBean)

Example 70 with PropertyNode

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

the class StaticTypeCheckingVisitor method findMethod.

protected List<MethodNode> findMethod(ClassNode receiver, String name, ClassNode... args) {
    if (isPrimitiveType(receiver))
        receiver = getWrapper(receiver);
    List<MethodNode> methods;
    if (!receiver.isInterface() && "<init>".equals(name)) {
        methods = addGeneratedMethods(receiver, new ArrayList<MethodNode>(receiver.getDeclaredConstructors()));
        if (methods.isEmpty()) {
            MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
            node.setDeclaringClass(receiver);
            methods = Collections.singletonList(node);
            if (receiver.isArray()) {
                // arbitrary number of parameters.
                return methods;
            }
        }
    } else {
        methods = findMethodsWithGenerated(receiver, name);
        if (receiver.isInterface()) {
            collectAllInterfaceMethodsByName(receiver, name, methods);
            methods.addAll(OBJECT_TYPE.getMethods(name));
        }
        // not static method can't be called from a static context
        if (typeCheckingContext.getEnclosingClosure() == null || (receiver instanceof InnerClassNode && !receiver.getName().endsWith("$Trait$Helper"))) {
            // not in a closure or within an inner class
            ClassNode parent = receiver;
            while (parent instanceof InnerClassNode && !parent.isStaticClass()) {
                parent = parent.getOuterClass();
                methods.addAll(findMethodsWithGenerated(parent, name));
            }
        }
        if (methods.isEmpty()) {
            addArrayMethods(methods, receiver, name, args);
        }
        if (methods.isEmpty() && (args == null || args.length == 0)) {
            // check if it's a property
            String pname = extractPropertyNameFromMethodName("get", name);
            if (pname == null) {
                pname = extractPropertyNameFromMethodName("is", name);
            }
            if (pname != null) {
                // we don't use property exists there because findMethod is called on super clases recursively
                PropertyNode property = null;
                ClassNode curNode = receiver;
                while (property == null && curNode != null) {
                    property = curNode.getProperty(pname);
                    ClassNode svCur = curNode;
                    while (property == null && svCur instanceof InnerClassNode && !svCur.isStaticClass()) {
                        svCur = svCur.getOuterClass();
                        property = svCur.getProperty(pname);
                        if (property != null) {
                            receiver = svCur;
                            break;
                        }
                    }
                    curNode = curNode.getSuperClass();
                }
                if (property != null) {
                    MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                    if (property.isStatic()) {
                        node.setModifiers(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC);
                    }
                    node.setDeclaringClass(receiver);
                    return Collections.singletonList(node);
                }
            }
        } else if (methods.isEmpty() && args != null && args.length == 1) {
            // maybe we are looking for a setter ?
            String pname = extractPropertyNameFromMethodName("set", name);
            if (pname != null) {
                ClassNode curNode = receiver;
                PropertyNode property = null;
                while (property == null && curNode != null) {
                    property = curNode.getProperty(pname);
                    curNode = curNode.getSuperClass();
                }
                if (property != null) {
                    ClassNode type = property.getOriginType();
                    if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) {
                        MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, VOID_TYPE, new Parameter[] { new Parameter(type, "arg") }, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                        if (property.isStatic()) {
                            node.setModifiers(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC);
                        }
                        node.setDeclaringClass(receiver);
                        return Collections.singletonList(node);
                    }
                }
            }
        }
    }
    if (methods.isEmpty()) {
        // look at the interfaces, there's a chance that a method is not implemented and we should not hide the
        // error from the compiler
        collectAllInterfaceMethodsByName(receiver, name, methods);
    }
    // lookup in DGM methods too
    findDGMMethodsByNameAndArguments(getTransformLoader(), receiver, name, args, methods);
    List<MethodNode> chosen = chooseBestMethod(receiver, methods, args);
    if (!chosen.isEmpty())
        return chosen;
    // GROOVY-5566
    if (receiver instanceof InnerClassNode && ((InnerClassNode) receiver).isAnonymous() && methods.size() == 1 && args != null && "<init>".equals(name)) {
        MethodNode constructor = methods.get(0);
        if (constructor.getParameters().length == args.length) {
            return methods;
        }
    }
    if (receiver.equals(CLASS_Type) && receiver.getGenericsTypes() != null) {
        List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
        if (!result.isEmpty())
            return result;
    }
    if (ClassHelper.GSTRING_TYPE.equals(receiver))
        return findMethod(ClassHelper.STRING_TYPE, name, args);
    if (isBeingCompiled(receiver)) {
        chosen = findMethod(GROOVY_OBJECT_TYPE, name, args);
        if (!chosen.isEmpty())
            return chosen;
    }
    return EMPTY_METHODNODE_LIST;
}
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) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) ArrayList(java.util.ArrayList) Parameter(org.codehaus.groovy.ast.Parameter) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Aggregations

PropertyNode (org.codehaus.groovy.ast.PropertyNode)71 ClassNode (org.codehaus.groovy.ast.ClassNode)36 FieldNode (org.codehaus.groovy.ast.FieldNode)30 ArrayList (java.util.ArrayList)25 MethodNode (org.codehaus.groovy.ast.MethodNode)19 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)16 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)12 Parameter (org.codehaus.groovy.ast.Parameter)11 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)10 Expression (org.codehaus.groovy.ast.expr.Expression)10 LowestUpperBoundClassNode (org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode)8 AnnotationNode (org.codehaus.groovy.ast.AnnotationNode)7 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)6 DynamicVariable (org.codehaus.groovy.ast.DynamicVariable)6 CastExpression (org.codehaus.groovy.ast.expr.CastExpression)6 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)6 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)6 SyntaxErrorMessage (org.codehaus.groovy.control.messages.SyntaxErrorMessage)6 SyntaxException (org.codehaus.groovy.syntax.SyntaxException)6 HashSet (java.util.HashSet)5