Search in sources :

Example 86 with PropertyNode

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

the class GeneralUtils method getAllProperties.

public static List<PropertyNode> getAllProperties(final ClassNode type) {
    ClassNode node = type;
    List<PropertyNode> result = new ArrayList<>();
    while (node != null) {
        result.addAll(node.getProperties());
        node = node.getSuperClass();
    }
    return result;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) ArrayList(java.util.ArrayList)

Example 87 with PropertyNode

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

the class BeanUtils method addIfMissing.

private static void addIfMissing(ClassNode cNode, List<PropertyNode> result, Set<String> names, MethodNode mNode, ClassNode returnType, String propName, Statement getter, Statement setter) {
    if (cNode.getProperty(propName) != null)
        return;
    if (names.contains(propName)) {
        for (PropertyNode pn : result) {
            if (pn.getName().equals(propName) && getter != null && pn.getGetterBlock() == null) {
                pn.setGetterBlock(getter);
            }
            if (pn.getName().equals(propName) && setter != null && pn.getSetterBlock() == null) {
                pn.setSetterBlock(setter);
            }
        }
    } else {
        result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, getter, setter));
        names.add(propName);
    }
}
Also used : PropertyNode(org.codehaus.groovy.ast.PropertyNode)

Example 88 with PropertyNode

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

the class StaticTypeCheckingVisitor method existsProperty.

/**
 * Checks whether a property exists on the receiver, or on any of the possible receiver classes (found in the
 * temporary type information table)
 *
 * @param pexp     a property expression
 * @param readMode if true, look for property read, else for property set
 * @param visitor  if not null, when the property node is found, visit it with the provided visitor
 * @return true if the property is defined in any of the possible receiver classes
 */
protected boolean existsProperty(final PropertyExpression pexp, final boolean readMode, final ClassCodeVisitorSupport visitor) {
    super.visitPropertyExpression(pexp);
    String propertyName = pexp.getPropertyAsString();
    if (propertyName == null)
        return false;
    Expression objectExpression = pexp.getObjectExpression();
    ClassNode objectExpressionType = getType(objectExpression);
    if (objectExpression instanceof ConstructorCallExpression) {
        ClassNode rawType = objectExpressionType.getPlainNodeReference();
        inferDiamondType((ConstructorCallExpression) objectExpression, rawType);
    }
    // enclosing excludes classes that skip STC
    Set<ClassNode> enclosingTypes = new LinkedHashSet<>();
    enclosingTypes.add(typeCheckingContext.getEnclosingClassNode());
    enclosingTypes.addAll(enclosingTypes.iterator().next().getOuterClasses());
    boolean staticOnlyAccess = isClassClassNodeWrappingConcreteType(objectExpressionType);
    if (staticOnlyAccess && "this".equals(propertyName)) {
        // handle "Outer.this" for any level of nesting
        ClassNode outer = objectExpressionType.getGenericsTypes()[0].getType();
        ClassNode found = null;
        for (ClassNode enclosingType : enclosingTypes) {
            if (!enclosingType.isStaticClass() && outer.equals(enclosingType.getOuterClass())) {
                found = enclosingType;
                break;
            }
        }
        if (found != null) {
            storeType(pexp, outer);
            return true;
        }
    }
    boolean foundGetterOrSetter = false;
    String capName = capitalize(propertyName);
    Set<ClassNode> handledNodes = new HashSet<>();
    List<Receiver<String>> receivers = new ArrayList<>();
    addReceivers(receivers, makeOwnerList(objectExpression), pexp.isImplicitThis());
    for (Receiver<String> receiver : receivers) {
        ClassNode receiverType = receiver.getType();
        if (receiverType.isArray() && "length".equals(propertyName)) {
            pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
            storeType(pexp, int_TYPE);
            if (visitor != null) {
                FieldNode length = new FieldNode("length", Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, int_TYPE, receiverType, null);
                length.setDeclaringClass(receiverType);
                visitor.visitField(length);
            }
            return true;
        }
        LinkedList<ClassNode> queue = new LinkedList<>();
        queue.add(receiverType);
        if (isPrimitiveType(receiverType)) {
            queue.add(getWrapper(receiverType));
        }
        while (!queue.isEmpty()) {
            ClassNode current = queue.remove();
            if (!handledNodes.add(current))
                continue;
            FieldNode field = current.getDeclaredField(propertyName);
            if (field == null) {
                if (current.getSuperClass() != null)
                    queue.addFirst(current.getSuperClass());
                Collections.addAll(queue, current.getInterfaces());
            }
            boolean staticOnly = (receiver.getData() == null ? staticOnlyAccess : false);
            // as well; in case of static property access Class<Type> and Type are listed
            if (isClassClassNodeWrappingConcreteType(current))
                staticOnly = false;
            field = allowStaticAccessToMember(field, staticOnly);
            // skip property/accessor checks for "x.@field"
            if (pexp instanceof AttributeExpression) {
                if (field != null && storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
                    return true;
                }
                continue;
            }
            // skip property/accessor checks for "field", "this.field", "this.with { field }", etc. in declaring class of field
            if (field != null && enclosingTypes.contains(current)) {
                if (storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
                    return true;
                }
            }
            MethodNode getter = findGetter(current, "is" + capName, pexp.isImplicitThis());
            getter = allowStaticAccessToMember(getter, staticOnly);
            if (getter == null)
                getter = findGetter(current, getGetterName(propertyName), pexp.isImplicitThis());
            getter = allowStaticAccessToMember(getter, staticOnly);
            List<MethodNode> setters = findSetters(current, getSetterName(propertyName), /*enforce void:*/
            false);
            setters = allowStaticAccessToMember(setters, staticOnly);
            // need to visit even if we only look for setters for compatibility
            if (visitor != null && getter != null)
                visitor.visitMethod(getter);
            PropertyNode property = current.getProperty(propertyName);
            property = allowStaticAccessToMember(property, staticOnly);
            // prefer explicit getter or setter over property if receiver is not 'this'
            if (property == null || !enclosingTypes.contains(receiverType)) {
                if (readMode) {
                    if (getter != null && hasAccessToMember(enclosingTypes.iterator().next(), getter.getDeclaringClass(), getter.getModifiers())) {
                        ClassNode returnType = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
                        storeInferredTypeForPropertyExpression(pexp, returnType);
                        storeTargetMethod(pexp, getter);
                        String delegationData = receiver.getData();
                        if (delegationData != null) {
                            pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
                        }
                        return true;
                    }
                } else {
                    if (!setters.isEmpty()) {
                        if (visitor != null) {
                            if (field != null) {
                                visitor.visitField(field);
                            } else {
                                for (MethodNode setter : setters) {
                                    // visiting setter will not infer the property type since return type is void, so visit a dummy field instead
                                    FieldNode virtual = new FieldNode(propertyName, 0, setter.getParameters()[0].getOriginType(), current, null);
                                    virtual.setDeclaringClass(setter.getDeclaringClass());
                                    visitor.visitField(virtual);
                                }
                            }
                        }
                        SetterInfo info = new SetterInfo(current, getSetterName(propertyName), setters);
                        BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
                        if (enclosingBinaryExpression != null) {
                            putSetterInfo(enclosingBinaryExpression.getLeftExpression(), info);
                        }
                        String delegationData = receiver.getData();
                        if (delegationData != null) {
                            pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
                        }
                        pexp.removeNodeMetaData(READONLY_PROPERTY);
                        return true;
                    } else if (getter != null && field == null) {
                        // GROOVY-9127
                        pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
                    }
                }
            }
            if (property != null && storeProperty(property, pexp, receiverType, visitor, receiver.getData(), !readMode))
                return true;
            if (field != null && storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode))
                return true;
            foundGetterOrSetter = (foundGetterOrSetter || !setters.isEmpty() || getter != null);
        }
        // GROOVY-5568: the property may be defined by DGM
        for (ClassNode dgmReceiver : isPrimitiveType(receiverType) ? new ClassNode[] { receiverType, getWrapper(receiverType) } : new ClassNode[] { receiverType }) {
            List<MethodNode> methods = findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "get" + capName, ClassNode.EMPTY_ARRAY);
            for (MethodNode method : findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
                if (isPrimitiveBoolean(method.getReturnType()))
                    methods.add(method);
            }
            if (isUsingGenericsOrIsArrayUsingGenerics(dgmReceiver)) {
                methods.removeIf(// GROOVY-10075: "List<Integer>" vs "List<String>"
                method -> !typeCheckMethodsWithGenerics(dgmReceiver, ClassNode.EMPTY_ARRAY, method));
            }
            if (!methods.isEmpty()) {
                List<MethodNode> bestMethods = chooseBestMethod(dgmReceiver, methods, ClassNode.EMPTY_ARRAY);
                if (bestMethods.size() == 1) {
                    MethodNode getter = bestMethods.get(0);
                    if (visitor != null) {
                        visitor.visitMethod(getter);
                    }
                    ClassNode returnType = inferReturnTypeGenerics(dgmReceiver, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
                    storeInferredTypeForPropertyExpression(pexp, returnType);
                    if (readMode)
                        storeTargetMethod(pexp, getter);
                    return true;
                }
            }
        }
        // GROOVY-7996: check if receiver implements get(String)/set(String,Object) or propertyMissing(String) or $static_propertyMissing(String)?
        if (!receiverType.isArray() && !isPrimitiveType(getUnwrapper(receiverType)) && pexp.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null) {
            MethodNode mopMethod;
            if (readMode) {
                mopMethod = receiverType.getMethod("get", new Parameter[] { new Parameter(STRING_TYPE, "name") });
            } else {
                mopMethod = receiverType.getMethod("set", new Parameter[] { new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value") });
            }
            if (mopMethod == null)
                mopMethod = receiverType.getMethod("propertyMissing", new Parameter[] { new Parameter(STRING_TYPE, "propertyName") });
            if (mopMethod != null && !mopMethod.isStatic() && !mopMethod.isSynthetic()) {
                pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE);
                pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE);
                pexp.removeNodeMetaData(INFERRED_TYPE);
                visitor.visitMethod(mopMethod);
                return true;
            }
        }
    }
    for (Receiver<String> receiver : receivers) {
        ClassNode receiverType = receiver.getType();
        ClassNode propertyType = getTypeForMapPropertyExpression(receiverType, pexp);
        if (propertyType == null)
            propertyType = getTypeForListPropertyExpression(receiverType, pexp);
        if (propertyType == null)
            propertyType = getTypeForSpreadExpression(receiverType, pexp);
        if (propertyType == null)
            continue;
        if (visitor != null) {
            // TODO: type inference on maps and lists, if possible
            PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiver.getType(), null, null, null);
            node.setDeclaringClass(receiver.getType());
            visitor.visitProperty(node);
        }
        storeType(pexp, propertyType);
        String delegationData = receiver.getData();
        if (delegationData != null)
            pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
        return true;
    }
    return foundGetterOrSetter;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) StaticTypeCheckingSupport.findDGMMethodsForClassNode(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsForClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ArrayList(java.util.ArrayList) StaticTypeCheckingSupport.toMethodParametersString(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.toMethodParametersString) StaticTypeCheckingSupport.isParameterizedWithString(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isParameterizedWithString) StaticTypeCheckingSupport.isParameterizedWithGStringOrGStringString(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isParameterizedWithGStringOrGStringString) AttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression) LinkedList(java.util.LinkedList) MethodNode(org.codehaus.groovy.ast.MethodNode) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) UnaryMinusExpression(org.codehaus.groovy.ast.expr.UnaryMinusExpression) ClosureListExpression(org.codehaus.groovy.ast.expr.ClosureListExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) MethodReferenceExpression(org.codehaus.groovy.ast.expr.MethodReferenceExpression) TernaryExpression(org.codehaus.groovy.ast.expr.TernaryExpression) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) PrefixExpression(org.codehaus.groovy.ast.expr.PrefixExpression) PostfixExpression(org.codehaus.groovy.ast.expr.PostfixExpression) Expression(org.codehaus.groovy.ast.expr.Expression) UnaryPlusExpression(org.codehaus.groovy.ast.expr.UnaryPlusExpression) AnnotationConstantExpression(org.codehaus.groovy.ast.expr.AnnotationConstantExpression) BitwiseNegationExpression(org.codehaus.groovy.ast.expr.BitwiseNegationExpression) MapExpression(org.codehaus.groovy.ast.expr.MapExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) StaticTypeCheckingSupport.evaluateExpression(org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.evaluateExpression) NotExpression(org.codehaus.groovy.ast.expr.NotExpression) FieldExpression(org.codehaus.groovy.ast.expr.FieldExpression) EmptyExpression(org.codehaus.groovy.ast.expr.EmptyExpression) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) MethodPointerExpression(org.codehaus.groovy.ast.expr.MethodPointerExpression) MapEntryExpression(org.codehaus.groovy.ast.expr.MapEntryExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) CastExpression(org.codehaus.groovy.ast.expr.CastExpression) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) LambdaExpression(org.codehaus.groovy.ast.expr.LambdaExpression) ListExpression(org.codehaus.groovy.ast.expr.ListExpression) RangeExpression(org.codehaus.groovy.ast.expr.RangeExpression) SpreadExpression(org.codehaus.groovy.ast.expr.SpreadExpression) ArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) ElvisOperatorExpression(org.codehaus.groovy.ast.expr.ElvisOperatorExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) DeclarationExpression(org.codehaus.groovy.ast.expr.DeclarationExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) AttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression) PropertyNode(org.codehaus.groovy.ast.PropertyNode) ClosureUtils.hasImplicitParameter(org.codehaus.groovy.ast.tools.ClosureUtils.hasImplicitParameter) Parameter(org.codehaus.groovy.ast.Parameter) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 89 with PropertyNode

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

the class TraitReceiverTransformer method transform.

@Override
public Expression transform(final Expression exp) {
    ClassNode weavedType = weaved.getOriginType();
    if (exp instanceof BinaryExpression) {
        return transformBinaryExpression((BinaryExpression) exp, weavedType);
    } else if (exp instanceof StaticMethodCallExpression) {
        StaticMethodCallExpression call = (StaticMethodCallExpression) exp;
        ClassNode ownerType = call.getOwnerType();
        if (traitClass.equals(ownerType)) {
            MethodCallExpression mce = callX(varX(weaved), call.getMethod(), transform(call.getArguments()));
            mce.setSafe(false);
            mce.setSpreadSafe(false);
            mce.setImplicitThis(false);
            mce.setSourcePosition(exp);
            return mce;
        }
    } else if (exp instanceof MethodCallExpression) {
        MethodCallExpression mce = (MethodCallExpression) exp;
        String obj = mce.getObjectExpression().getText();
        if (mce.isImplicitThis() || "this".equals(obj)) {
            return transformMethodCallOnThis(mce);
        } else if ("super".equals(obj)) {
            return transformSuperMethodCall(mce);
        }
    } else if (exp instanceof FieldExpression) {
        FieldNode fn = ((FieldExpression) exp).getField();
        return transformFieldReference(exp, fn, fn.isStatic());
    } else if (exp instanceof VariableExpression) {
        VariableExpression vexp = (VariableExpression) exp;
        Variable accessedVariable = vexp.getAccessedVariable();
        if (accessedVariable instanceof FieldNode || accessedVariable instanceof PropertyNode) {
            if (knownFields.contains(vexp.getName())) {
                boolean isStatic = Modifier.isStatic(accessedVariable.getModifiers());
                return transformFieldReference(exp, accessedVariable instanceof FieldNode ? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField(), isStatic);
            } else {
                PropertyExpression propertyExpression = propX(varX(weaved), vexp.getName());
                propertyExpression.getProperty().setSourcePosition(exp);
                return propertyExpression;
            }
        } else if (accessedVariable instanceof DynamicVariable && !inClosure) {
            // GROOVY-9386
            PropertyExpression propertyExpression = propX(varX(weaved), vexp.getName());
            propertyExpression.getProperty().setSourcePosition(exp);
            return propertyExpression;
        }
        if (vexp.isThisExpression()) {
            VariableExpression variableExpression = varX(weaved);
            variableExpression.setSourcePosition(exp);
            return variableExpression;
        }
        if (vexp.isSuperExpression()) {
            throwSuperError(vexp);
        }
    } else if (exp instanceof PropertyExpression) {
        PropertyExpression pexp = (PropertyExpression) exp;
        String obj = pexp.getObjectExpression().getText();
        if (pexp.isImplicitThis() || "this".equals(obj)) {
            String propName = pexp.getPropertyAsString();
            if (knownFields.contains(propName)) {
                FieldNode fn = new FieldNode(propName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
                return transformFieldReference(exp, fn, false);
            }
        }
    } else if (exp instanceof ClosureExpression) {
        MethodCallExpression mce = callX(exp, "rehydrate", args(varX(weaved), varX(weaved), varX(weaved)));
        mce.setImplicitThis(false);
        mce.setSourcePosition(exp);
        boolean oldInClosure = inClosure;
        inClosure = true;
        ((ClosureExpression) exp).getCode().visit(this);
        inClosure = oldInClosure;
        // The rewrite we do is causing some troubles with type checking, which will
        // not be able to perform closure parameter type inference
        // so we store the replacement, which will be done *after* type checking.
        exp.putNodeMetaData(TraitASTTransformation.POST_TYPECHECKING_REPLACEMENT, mce);
        return exp;
    }
    // TODO: unary expressions (field++, field+=, ...)
    return super.transform(exp);
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) Variable(org.codehaus.groovy.ast.Variable) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) FieldNode(org.codehaus.groovy.ast.FieldNode) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) FieldExpression(org.codehaus.groovy.ast.expr.FieldExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) DynamicVariable(org.codehaus.groovy.ast.DynamicVariable) PropertyNode(org.codehaus.groovy.ast.PropertyNode) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression)

Example 90 with PropertyNode

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

the class ClassNodeUtils method hasPossibleStaticProperty.

/**
 * Return true if we have a static accessor
 */
public static boolean hasPossibleStaticProperty(final ClassNode cNode, final String methodName) {
    // assume explicit static method call checked first so we can assume a simple check here
    if (!methodName.startsWith("get") && !methodName.startsWith("is")) {
        return false;
    }
    String propName = getPropNameForAccessor(methodName);
    PropertyNode pNode = getStaticProperty(cNode, propName);
    return pNode != null && (methodName.startsWith("get") || isPrimitiveBoolean(pNode.getType()));
}
Also used : PropertyNode(org.codehaus.groovy.ast.PropertyNode)

Aggregations

PropertyNode (org.codehaus.groovy.ast.PropertyNode)105 ClassNode (org.codehaus.groovy.ast.ClassNode)50 FieldNode (org.codehaus.groovy.ast.FieldNode)44 ArrayList (java.util.ArrayList)41 MethodNode (org.codehaus.groovy.ast.MethodNode)28 Expression (org.codehaus.groovy.ast.expr.Expression)27 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)24 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)23 Parameter (org.codehaus.groovy.ast.Parameter)22 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)19 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)19 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)16 HashSet (java.util.HashSet)14 AnnotationNode (org.codehaus.groovy.ast.AnnotationNode)14 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)14 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)14 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)13 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)13 Statement (org.codehaus.groovy.ast.stmt.Statement)12 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)11