Search in sources :

Example 51 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 52 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 53 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 54 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)

Example 55 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)

Aggregations

InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)78 ClassNode (org.codehaus.groovy.ast.ClassNode)67 MethodNode (org.codehaus.groovy.ast.MethodNode)33 FieldNode (org.codehaus.groovy.ast.FieldNode)20 Parameter (org.codehaus.groovy.ast.Parameter)20 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)20 ArrayList (java.util.ArrayList)17 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)16 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)15 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)15 Expression (org.codehaus.groovy.ast.expr.Expression)15 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)14 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)13 Statement (org.codehaus.groovy.ast.stmt.Statement)13 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)12 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)12 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)11 EnumConstantClassNode (org.codehaus.groovy.ast.EnumConstantClassNode)10 GenericsType (org.codehaus.groovy.ast.GenericsType)10 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)9