Search in sources :

Example 31 with InnerClassNode

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

the class StaticTypeCheckingVisitor method visitConstructorCallExpression.

@Override
public void visitConstructorCallExpression(ConstructorCallExpression call) {
    super.visitConstructorCallExpression(call);
    if (extension.beforeMethodCall(call)) {
        extension.afterMethodCall(call);
        return;
    }
    ClassNode receiver = call.isThisCall() ? typeCheckingContext.getEnclosingClassNode() : call.isSuperCall() ? typeCheckingContext.getEnclosingClassNode().getSuperClass() : call.getType();
    Expression arguments = call.getArguments();
    ArgumentListExpression argumentList = InvocationWriter.makeArgumentList(arguments);
    checkForbiddenSpreadArgument(argumentList);
    ClassNode[] args = getArgumentTypes(argumentList);
    if (args.length > 0 && typeCheckingContext.getEnclosingClosure() != null && argumentList.getExpression(0) instanceof VariableExpression && ((VariableExpression) argumentList.getExpression(0)).isThisExpression() && call.getType() instanceof InnerClassNode && call.getType().getOuterClass().equals(args[0]) && !call.getType().isStaticClass()) {
        args[0] = CLOSURE_TYPE;
    }
    MethodNode node = null;
    if (args.length == 1 && implementsInterfaceOrIsSubclassOf(args[0], MAP_TYPE) && findMethod(receiver, "<init>", ClassNode.EMPTY_ARRAY).size() == 1 && findMethod(receiver, "<init>", args).isEmpty()) {
        // bean-style constructor
        node = typeCheckMapConstructor(call, receiver, arguments);
        if (node != null) {
            storeTargetMethod(call, node);
            extension.afterMethodCall(call);
            return;
        }
    }
    node = findMethodOrFail(call, receiver, "<init>", args);
    if (node != null) {
        if (node.getParameters().length == 0 && args.length == 1 && implementsInterfaceOrIsSubclassOf(args[0], MAP_TYPE)) {
            node = typeCheckMapConstructor(call, receiver, arguments);
        } else {
            typeCheckMethodsWithGenericsOrFail(receiver, args, node, call);
        }
        if (node != null)
            storeTargetMethod(call, node);
    }
    extension.afterMethodCall(call);
}
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) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 32 with InnerClassNode

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

the class EnumVisitor method addInit.

private void addInit(ClassNode enumClass, FieldNode minValue, FieldNode maxValue, FieldNode values, boolean isAic) {
    // constructor helper
    // This method is used instead of calling the constructor as
    // calling the constructor may require a table with MetaClass
    // selecting the constructor for each enum value. So instead we
    // use this method to have a central point for constructor selection
    // and only one table. The whole construction is needed because 
    // Reflection forbids access to the enum constructor.
    // code:
    // def $INIT(Object[] para) {
    //  return this(*para)
    // }
    ClassNode enumRef = enumClass.getPlainNodeReference();
    Parameter[] parameter = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "para") };
    MethodNode initMethod = new MethodNode("$INIT", PUBLIC_FS | Opcodes.ACC_SYNTHETIC, enumRef, parameter, ClassNode.EMPTY_ARRAY, null);
    initMethod.setSynthetic(true);
    ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.THIS, new ArgumentListExpression(new SpreadExpression(new VariableExpression("para"))));
    BlockStatement code = new BlockStatement();
    code.addStatement(new ReturnStatement(cce));
    initMethod.setCode(code);
    enumClass.addMethod(initMethod);
    // static init
    List<FieldNode> fields = enumClass.getFields();
    List<Expression> arrayInit = new ArrayList<Expression>();
    int value = -1;
    Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
    List<Statement> block = new ArrayList<Statement>();
    FieldNode tempMin = null;
    FieldNode tempMax = null;
    for (FieldNode field : fields) {
        if ((field.getModifiers() & Opcodes.ACC_ENUM) == 0)
            continue;
        value++;
        if (tempMin == null)
            tempMin = field;
        tempMax = field;
        ClassNode enumBase = enumClass;
        ArgumentListExpression args = new ArgumentListExpression();
        args.addExpression(new ConstantExpression(field.getName()));
        args.addExpression(new ConstantExpression(value));
        if (field.getInitialExpression() == null) {
            if ((enumClass.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
                addError(field, "The enum constant " + field.getName() + " must override abstract methods from " + enumBase.getName() + ".");
                continue;
            }
        } else {
            ListExpression oldArgs = (ListExpression) field.getInitialExpression();
            List<MapEntryExpression> savedMapEntries = new ArrayList<MapEntryExpression>();
            for (Expression exp : oldArgs.getExpressions()) {
                if (exp instanceof MapEntryExpression) {
                    savedMapEntries.add((MapEntryExpression) exp);
                    continue;
                }
                InnerClassNode inner = null;
                if (exp instanceof ClassExpression) {
                    ClassExpression clazzExp = (ClassExpression) exp;
                    ClassNode ref = clazzExp.getType();
                    if (ref instanceof EnumConstantClassNode) {
                        inner = (InnerClassNode) ref;
                    }
                }
                if (inner != null) {
                    List<MethodNode> baseMethods = enumBase.getMethods();
                    for (MethodNode methodNode : baseMethods) {
                        if (!methodNode.isAbstract())
                            continue;
                        MethodNode enumConstMethod = inner.getMethod(methodNode.getName(), methodNode.getParameters());
                        if (enumConstMethod == null || (enumConstMethod.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
                            addError(field, "Can't have an abstract method in enum constant " + field.getName() + ". Implement method '" + methodNode.getTypeDescriptor() + "'.");
                        }
                    }
                    if (inner.getVariableScope() == null) {
                        enumBase = inner;
                        /*
                             * GROOVY-3985: Remove the final modifier from $INIT method in this case
                             * so that subclasses of enum generated for enum constants (aic) can provide
                             * their own $INIT method
                             */
                        initMethod.setModifiers(initMethod.getModifiers() & ~Opcodes.ACC_FINAL);
                        continue;
                    }
                }
                args.addExpression(exp);
            }
            if (savedMapEntries.size() > 0) {
                args.getExpressions().add(2, new MapExpression(savedMapEntries));
            }
        }
        field.setInitialValueExpression(null);
        block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(field), assign, new StaticMethodCallExpression(enumBase, "$INIT", args))));
        arrayInit.add(new FieldExpression(field));
    }
    if (!isAic) {
        if (tempMin != null) {
            block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(minValue), assign, new FieldExpression(tempMin))));
            block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(maxValue), assign, new FieldExpression(tempMax))));
            enumClass.addField(minValue);
            enumClass.addField(maxValue);
        }
        block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(values), assign, new ArrayExpression(enumClass, arrayInit))));
        enumClass.addField(values);
    }
    enumClass.addStaticInitializerStatements(block, true);
}
Also used : EnumConstantClassNode(org.codehaus.groovy.ast.EnumConstantClassNode) ArrayList(java.util.ArrayList) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Token(org.codehaus.groovy.syntax.Token) MethodNode(org.codehaus.groovy.ast.MethodNode) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EnumConstantClassNode(org.codehaus.groovy.ast.EnumConstantClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) Statement(org.codehaus.groovy.ast.stmt.Statement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Parameter(org.codehaus.groovy.ast.Parameter)

Example 33 with InnerClassNode

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

the class InnerClassCompletionVisitor method shouldImplicitlyPassThisPara.

private boolean shouldImplicitlyPassThisPara(ConstructorCallExpression cce) {
    boolean pass = false;
    ClassNode superCN = classNode.getSuperClass();
    if (cce.isThisCall()) {
        pass = true;
    } else if (cce.isSuperCall()) {
        // needs to be passed
        if (!superCN.isEnum() && !superCN.isInterface() && superCN instanceof InnerClassNode) {
            InnerClassNode superInnerCN = (InnerClassNode) superCN;
            if (!isStatic(superInnerCN) && classNode.getOuterClass().isDerivedFrom(superCN.getOuterClass())) {
                pass = true;
            }
        }
    }
    return pass;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 34 with InnerClassNode

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

the class InnerClassCompletionVisitor method visitClass.

@Override
public void visitClass(ClassNode node) {
    this.classNode = node;
    thisField = null;
    InnerClassNode innerClass = null;
    if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
        innerClass = (InnerClassNode) node;
        thisField = innerClass.getField("this$0");
        if (innerClass.getVariableScope() == null && innerClass.getDeclaredConstructors().isEmpty()) {
            // add dummy constructor
            innerClass.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, null, null);
        }
    }
    if (node.isEnum() || node.isInterface())
        return;
    // use Iterator.hasNext() to check for available inner classes
    if (node.getInnerClasses().hasNext())
        addDispatcherMethods(node);
    if (innerClass == null)
        return;
    super.visitClass(node);
    addDefaultMethods(innerClass);
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 35 with InnerClassNode

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

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 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 property getter 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(node.getOuterClass()), 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 property setter 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(node.getOuterClass()), 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);
}
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

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