Search in sources :

Example 26 with InnerClassNode

use of org.codehaus.groovy.ast.InnerClassNode in project gradle by gradle.

the class GradleResolveVisitor method checkThisAndSuperAsPropertyAccess.

private void checkThisAndSuperAsPropertyAccess(PropertyExpression expression) {
    if (expression.isImplicitThis()) {
        return;
    }
    String prop = expression.getPropertyAsString();
    if (prop == null) {
        return;
    }
    if (!prop.equals("this") && !prop.equals("super")) {
        return;
    }
    ClassNode type = expression.getObjectExpression().getType();
    if (expression.getObjectExpression() instanceof ClassExpression) {
        if (!(currentClass instanceof InnerClassNode) && !Traits.isTrait(type)) {
            addError("The usage of 'Class.this' and 'Class.super' is only allowed in nested/inner classes.", expression);
            return;
        }
        if (currentScope != null && !currentScope.isInStaticContext() && Traits.isTrait(type) && "super".equals(prop) && directlyImplementsTrait(type)) {
            return;
        }
        ClassNode iterType = currentClass;
        while (iterType != null) {
            if (iterType.equals(type)) {
                break;
            }
            iterType = iterType.getOuterClass();
        }
        if (iterType == null) {
            addError("The class '" + type.getName() + "' needs to be an outer class of '" + currentClass.getName() + "' when using '.this' or '.super'.", expression);
        }
        if ((currentClass.getModifiers() & Opcodes.ACC_STATIC) == 0) {
            return;
        }
        if (currentScope != null && !currentScope.isInStaticContext()) {
            return;
        }
        addError("The usage of 'Class.this' and 'Class.super' within static nested class '" + currentClass.getName() + "' is not allowed in a static context.", expression);
    }
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 27 with InnerClassNode

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

the class InnerClassVisitor method visitConstructorCallExpression.

@Override
public void visitConstructorCallExpression(ConstructorCallExpression call) {
    super.visitConstructorCallExpression(call);
    if (!call.isUsingAnonymousInnerClass()) {
        passThisReference(call);
        return;
    }
    InnerClassNode innerClass = (InnerClassNode) call.getType();
    ClassNode outerClass = innerClass.getOuterClass();
    ClassNode superClass = innerClass.getSuperClass();
    if (superClass instanceof InnerClassNode && !superClass.isInterface() && !(superClass.isStaticClass() || ((superClass.getModifiers() & ACC_STATIC) == ACC_STATIC))) {
        insertThis0ToSuperCall(call, innerClass);
    }
    if (!innerClass.getDeclaredConstructors().isEmpty())
        return;
    if ((innerClass.getModifiers() & ACC_STATIC) != 0)
        return;
    VariableScope scope = innerClass.getVariableScope();
    if (scope == null)
        return;
    // expressions = constructor call arguments
    List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions();
    // block = init code for the constructor we produce
    BlockStatement block = new BlockStatement();
    // parameters = parameters of the constructor
    final int additionalParamCount = 1 + scope.getReferencedLocalVariablesCount();
    List<Parameter> parameters = new ArrayList<Parameter>(expressions.size() + additionalParamCount);
    // superCallArguments = arguments for the super call == the constructor call arguments
    List<Expression> superCallArguments = new ArrayList<Expression>(expressions.size());
    // first we add a super() call for all expressions given in the 
    // constructor call expression
    int pCount = additionalParamCount;
    for (Expression expr : expressions) {
        pCount++;
        // add one parameter for each expression in the
        // constructor call
        Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + pCount);
        parameters.add(param);
        // add to super call
        superCallArguments.add(new VariableExpression(param));
    }
    // add the super call
    ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression(superCallArguments));
    block.addStatement(new ExpressionStatement(cce));
    // we need to add "this" to access unknown methods/properties
    // this is saved in a field named this$0
    pCount = 0;
    expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
    boolean isStatic = isStaticThis(innerClass, scope);
    ClassNode outerClassType = getClassNode(outerClass, isStatic);
    if (!isStatic && inClosure)
        outerClassType = ClassHelper.CLOSURE_TYPE;
    outerClassType = outerClassType.getPlainNodeReference();
    Parameter thisParameter = new Parameter(outerClassType, "p" + pCount);
    parameters.add(pCount, thisParameter);
    thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, outerClassType, null);
    addFieldInit(thisParameter, thisField, block);
    // for each shared variable we add a reference and save it as field
    for (Iterator it = scope.getReferencedLocalVariablesIterator(); it.hasNext(); ) {
        pCount++;
        org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) it.next();
        VariableExpression ve = new VariableExpression(var);
        ve.setClosureSharedVariable(true);
        ve.setUseReferenceDirectly(true);
        expressions.add(pCount, ve);
        ClassNode rawReferenceType = ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
        Parameter p = new Parameter(rawReferenceType, "p" + pCount);
        parameters.add(pCount, p);
        p.setOriginType(var.getOriginType());
        final VariableExpression initial = new VariableExpression(p);
        initial.setSynthetic(true);
        initial.setUseReferenceDirectly(true);
        final FieldNode pField = innerClass.addFieldFirst(ve.getName(), PUBLIC_SYNTHETIC, rawReferenceType, initial);
        pField.setHolder(true);
        pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
    }
    innerClass.addConstructor(ACC_SYNTHETIC, parameters.toArray(new Parameter[parameters.size()]), ClassNode.EMPTY_ARRAY, block);
}
Also used : 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) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) ArrayList(java.util.ArrayList) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) PropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Iterator(java.util.Iterator) Parameter(org.codehaus.groovy.ast.Parameter) VariableScope(org.codehaus.groovy.ast.VariableScope)

Example 28 with InnerClassNode

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

the class EnumHelper method makeEnumNode.

public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) {
    modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
    ClassNode enumClass;
    if (outerClass == null) {
        enumClass = new ClassNode(name, modifiers, null, interfaces, MixinNode.EMPTY_ARRAY);
    } else {
        name = outerClass.getName() + "$" + name;
        enumClass = new InnerClassNode(outerClass, name, modifiers, null, interfaces, MixinNode.EMPTY_ARRAY);
    }
    // set super class and generics info
    // "enum X" -> class X extends Enum<X>
    GenericsType gt = new GenericsType(enumClass);
    ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum");
    superClass.setGenericsTypes(new GenericsType[] { gt });
    enumClass.setSuperClass(superClass);
    superClass.setRedirect(ClassHelper.Enum_Type);
    return enumClass;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) GenericsType(org.codehaus.groovy.ast.GenericsType) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 29 with InnerClassNode

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

the class TraitASTTransformation method createHelperClass.

private void 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;
            }
            helper.addMethod(processMethod(cNode, 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, 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);
    }
}
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 30 with InnerClassNode

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

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();
    final ClassNode objectExpressionType = getType(objectExpression);
    boolean staticOnlyAccess = isClassClassNodeWrappingConcreteType(objectExpressionType);
    if ("this".equals(propertyName) && staticOnlyAccess) {
        // Outer.this
        ClassNode outerNode = objectExpressionType.getGenericsTypes()[0].getType();
        ClassNode current = typeCheckingContext.getEnclosingClassNode();
        if (!current.isStaticClass() && current instanceof InnerClassNode) {
            InnerClassNode icn = (InnerClassNode) current;
            if (outerNode.equals(icn.getOuterClass())) {
                storeType(pexp, outerNode);
                return true;
            }
        }
    }
    if (objectExpressionType.isArray() && "length".equals(pexp.getPropertyAsString())) {
        storeType(pexp, int_TYPE);
        if (visitor != null) {
            PropertyNode node = new PropertyNode("length", Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, int_TYPE, objectExpressionType, null, null, null);
            visitor.visitProperty(node);
        }
        return true;
    }
    boolean foundGetterOrSetter = false;
    List<Receiver<String>> receivers = new LinkedList<Receiver<String>>();
    List<Receiver<String>> owners = makeOwnerList(objectExpression);
    addReceivers(receivers, owners, pexp.isImplicitThis());
    String capName = MetaClassHelper.capitalize(propertyName);
    boolean isAttributeExpression = pexp instanceof AttributeExpression;
    HashSet<ClassNode> handledNodes = new HashSet<ClassNode>();
    for (Receiver<String> receiver : receivers) {
        ClassNode testClass = receiver.getType();
        LinkedList<ClassNode> queue = new LinkedList<ClassNode>();
        queue.add(testClass);
        if (isPrimitiveType(testClass)) {
            queue.add(getWrapper(testClass));
        }
        while (!queue.isEmpty()) {
            ClassNode current = queue.removeFirst();
            if (handledNodes.contains(current))
                continue;
            handledNodes.add(current);
            Set<ClassNode> allInterfaces = current.getAllInterfaces();
            for (ClassNode intf : allInterfaces) {
                //TODO: apply right generics here!
                queue.add(GenericsUtils.parameterizeType(current, intf));
            }
            // in case of a lookup on Class we look for instance methods on Class
            // as well, since in case of a static property access we have the class
            // itself in the list of receivers already;
            boolean staticOnly;
            if (isClassClassNodeWrappingConcreteType(current)) {
                staticOnly = false;
            } else {
                staticOnly = staticOnlyAccess;
            }
            FieldNode field = current.getDeclaredField(propertyName);
            field = allowStaticAccessToMember(field, staticOnly);
            if (storeField(field, isAttributeExpression, pexp, current, visitor, receiver.getData()))
                return true;
            PropertyNode propertyNode = current.getProperty(propertyName);
            propertyNode = allowStaticAccessToMember(propertyNode, staticOnly);
            if (storeProperty(propertyNode, pexp, current, visitor, receiver.getData()))
                return true;
            boolean isThisExpression = objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression();
            if (storeField(field, isThisExpression, pexp, receiver.getType(), visitor, receiver.getData()))
                return true;
            MethodNode getter = current.getGetterMethod("get" + capName);
            getter = allowStaticAccessToMember(getter, staticOnly);
            if (getter == null)
                getter = current.getGetterMethod("is" + capName);
            getter = allowStaticAccessToMember(getter, staticOnly);
            final String setterName = "set" + capName;
            List<MethodNode> setters = findSetters(current, setterName, false);
            setters = allowStaticAccessToMember(setters, staticOnly);
            // need to visit even if we only look for a setters for compatibility
            if (visitor != null && getter != null)
                visitor.visitMethod(getter);
            if (readMode) {
                if (getter != null) {
                    ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
                    storeInferredTypeForPropertyExpression(pexp, cn);
                    pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
                    String delegationData = receiver.getData();
                    if (delegationData != null)
                        pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
                    return true;
                }
            } else {
                if (!setters.isEmpty()) {
                    if (visitor != null) {
                        if (field != null) {
                            visitor.visitField(field);
                        } else {
                            for (MethodNode setter : setters) {
                                ClassNode setterType = setter.getParameters()[0].getOriginType();
                                FieldNode virtual = new FieldNode(propertyName, 0, setterType, current, EmptyExpression.INSTANCE);
                                visitor.visitField(virtual);
                            }
                        }
                    }
                    //TODO: apply generics on parameter[0]?
                    //                                storeType(pexp, setter.getParameters()[0].getType());
                    SetterInfo info = new SetterInfo(current, setterName, setters);
                    BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
                    if (enclosingBinaryExpression != null) {
                        putSetterInfo(enclosingBinaryExpression.getLeftExpression(), info);
                    }
                    String delegationData = receiver.getData();
                    if (delegationData != null) {
                        pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
                    }
                    return true;
                } else if (getter != null) {
                    pexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY, true);
                }
            }
            foundGetterOrSetter = foundGetterOrSetter || !setters.isEmpty() || getter != null;
            if (storeField(field, true, pexp, current, visitor, receiver.getData()))
                return true;
            // we stop now, otherwise we must check the parent class
            if (/*!isAttributeExpression && */
            current.getSuperClass() != null) {
                queue.add(current.getUnresolvedSuperClass());
            }
        }
        // GROOVY-5568, the property may be defined by DGM
        List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), testClass, "get" + capName, ClassNode.EMPTY_ARRAY);
        if (!methods.isEmpty()) {
            List<MethodNode> methodNodes = chooseBestMethod(testClass, methods, ClassNode.EMPTY_ARRAY);
            if (methodNodes.size() == 1) {
                MethodNode getter = methodNodes.get(0);
                if (visitor != null) {
                    visitor.visitMethod(getter);
                }
                ClassNode cn = inferReturnTypeGenerics(testClass, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
                storeInferredTypeForPropertyExpression(pexp, cn);
                return true;
            }
        }
    }
    for (Receiver<String> receiver : receivers) {
        ClassNode testClass = receiver.getType();
        ClassNode propertyType = getTypeForMapPropertyExpression(testClass, objectExpressionType, pexp);
        if (propertyType == null)
            propertyType = getTypeForListPropertyExpression(testClass, objectExpressionType, pexp);
        if (propertyType == null)
            propertyType = getTypeForSpreadExpression(testClass, objectExpressionType, 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(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
        return true;
    }
    return foundGetterOrSetter;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedList(java.util.LinkedList) MethodNode(org.codehaus.groovy.ast.MethodNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet)

Aggregations

InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)60 ClassNode (org.codehaus.groovy.ast.ClassNode)52 MethodNode (org.codehaus.groovy.ast.MethodNode)26 FieldNode (org.codehaus.groovy.ast.FieldNode)17 Parameter (org.codehaus.groovy.ast.Parameter)12 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)12 ArrayList (java.util.ArrayList)11 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)9 LinkedList (java.util.LinkedList)8 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)8 InterfaceHelperClassNode (org.codehaus.groovy.ast.InterfaceHelperClassNode)8 Expression (org.codehaus.groovy.ast.expr.Expression)8 GenericsType (org.codehaus.groovy.ast.GenericsType)7 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)7 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)7 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)7 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)7 MethodVisitor (org.objectweb.asm.MethodVisitor)7 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)6 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)6