Search in sources :

Example 11 with InnerClassNode

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

the class StaticTypeCheckingVisitor method visitClass.

@Override
public void visitClass(final ClassNode node) {
    if (shouldSkipClassNode(node))
        return;
    if (extension.beforeVisitClass(node)) {
        extension.afterVisitClass(node);
        return;
    }
    Object type = node.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type != null) {
        // transformation has already been run on this class node
        // so we'll use a silent collector in order not to duplicate errors
        typeCheckingContext.pushErrorCollector();
    }
    typeCheckingContext.pushEnclosingClassNode(node);
    Set<MethodNode> oldVisitedMethod = typeCheckingContext.alreadyVisitedMethods;
    typeCheckingContext.alreadyVisitedMethods = new LinkedHashSet<MethodNode>();
    super.visitClass(node);
    Iterator<InnerClassNode> innerClasses = node.getInnerClasses();
    while (innerClasses.hasNext()) {
        InnerClassNode innerClassNode = innerClasses.next();
        visitClass(innerClassNode);
    }
    typeCheckingContext.alreadyVisitedMethods = oldVisitedMethod;
    node.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, node);
    // works in a two pass sequence and we don't want to skip the second pass
    for (MethodNode methodNode : node.getMethods()) {
        methodNode.putNodeMetaData(StaticTypeCheckingVisitor.class, Boolean.TRUE);
    }
    for (ConstructorNode constructorNode : node.getDeclaredConstructors()) {
        constructorNode.putNodeMetaData(StaticTypeCheckingVisitor.class, Boolean.TRUE);
    }
    extension.afterVisitClass(node);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 12 with InnerClassNode

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

the class ClosureWriter method createClosureClass.

protected ClassNode createClosureClass(ClosureExpression expression, int mods) {
    ClassNode classNode = controller.getClassNode();
    ClassNode outerClass = controller.getOutermostClass();
    MethodNode methodNode = controller.getMethodNode();
    String name = classNode.getName() + "$" + // add a more informative name
    controller.getContext().getNextClosureInnerName(outerClass, classNode, methodNode);
    boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass();
    Parameter[] parameters = expression.getParameters();
    if (parameters == null) {
        parameters = Parameter.EMPTY_ARRAY;
    } else if (parameters.length == 0) {
        // let's create a default 'it' parameter
        Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
        parameters = new Parameter[] { it };
        Variable ref = expression.getVariableScope().getDeclaredVariable("it");
        if (ref != null)
            it.setClosureSharedVariable(ref.isClosureSharedVariable());
    }
    Parameter[] localVariableParams = getClosureSharedVariables(expression);
    removeInitialValues(localVariableParams);
    InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
    answer.setEnclosingMethod(controller.getMethodNode());
    answer.setSynthetic(true);
    answer.setUsingGenerics(outerClass.isUsingGenerics());
    answer.setSourcePosition(expression);
    if (staticMethodOrInStaticClass) {
        answer.setStaticClass(true);
    }
    if (controller.isInScriptBody()) {
        answer.setScriptBody(true);
    }
    MethodNode method = answer.addMethod("doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode());
    method.setSourcePosition(expression);
    VariableScope varScope = expression.getVariableScope();
    if (varScope == null) {
        throw new RuntimeException("Must have a VariableScope by now! for expression: " + expression + " class: " + name);
    } else {
        method.setVariableScope(varScope.copy());
    }
    if (parameters.length > 1 || (parameters.length == 1 && parameters[0].getType() != null && parameters[0].getType() != ClassHelper.OBJECT_TYPE && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType()))) {
        // let's add a typesafe call method
        MethodNode call = answer.addMethod("call", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, new ReturnStatement(new MethodCallExpression(VariableExpression.THIS_EXPRESSION, "doCall", new ArgumentListExpression(parameters))));
        call.setSourcePosition(expression);
    }
    // let's make the constructor
    BlockStatement block = new BlockStatement();
    // this block does not get a source position, because we don't
    // want this synthetic constructor to show up in corbertura reports
    VariableExpression outer = new VariableExpression("_outerInstance");
    outer.setSourcePosition(expression);
    block.getVariableScope().putReferencedLocalVariable(outer);
    VariableExpression thisObject = new VariableExpression("_thisObject");
    thisObject.setSourcePosition(expression);
    block.getVariableScope().putReferencedLocalVariable(thisObject);
    TupleExpression conArgs = new TupleExpression(outer, thisObject);
    block.addStatement(new ExpressionStatement(new ConstructorCallExpression(ClassNode.SUPER, conArgs)));
    // let's assign all the parameter fields from the outer context
    for (Parameter param : localVariableParams) {
        String paramName = param.getName();
        ClassNode type = param.getType();
        if (true) {
            VariableExpression initialValue = new VariableExpression(paramName);
            initialValue.setAccessedVariable(param);
            initialValue.setUseReferenceDirectly(true);
            ClassNode realType = type;
            type = ClassHelper.makeReference();
            param.setType(ClassHelper.makeReference());
            FieldNode paramField = answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue);
            paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType()));
            paramField.setHolder(true);
            String methodName = Verifier.capitalize(paramName);
            // let's add a getter & setter
            Expression fieldExp = new FieldExpression(paramField);
            answer.addMethod("get" + methodName, ACC_PUBLIC, realType.getPlainNodeReference(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new ReturnStatement(fieldExp));
        }
    }
    Parameter[] params = new Parameter[2 + localVariableParams.length];
    params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance");
    params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject");
    System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
    ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
    sn.setSourcePosition(expression);
    correctAccessedVariable(answer, expression);
    return answer;
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) Variable(org.codehaus.groovy.ast.Variable) FieldNode(org.codehaus.groovy.ast.FieldNode) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) FieldExpression(org.codehaus.groovy.ast.expr.FieldExpression) MethodNode(org.codehaus.groovy.ast.MethodNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) TupleExpression(org.codehaus.groovy.ast.expr.TupleExpression) FieldExpression(org.codehaus.groovy.ast.expr.FieldExpression) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) ASTNode(org.codehaus.groovy.ast.ASTNode) Parameter(org.codehaus.groovy.ast.Parameter) VariableScope(org.codehaus.groovy.ast.VariableScope)

Example 13 with InnerClassNode

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

the class AsmClassGenerator method visitAttributeOrProperty.

private void visitAttributeOrProperty(PropertyExpression expression, MethodCallerMultiAdapter adapter) {
    MethodVisitor mv = controller.getMethodVisitor();
    Expression objectExpression = expression.getObjectExpression();
    ClassNode classNode = controller.getClassNode();
    if (isThisOrSuper(objectExpression)) {
        // let's use the field expression if it's available
        String name = expression.getPropertyAsString();
        if (name != null) {
            FieldNode field = null;
            boolean privateSuperField = false;
            if (isSuperExpression(objectExpression)) {
                field = classNode.getSuperClass().getDeclaredField(name);
                if (field != null && ((field.getModifiers() & ACC_PRIVATE) != 0)) {
                    privateSuperField = true;
                }
            } else {
                if (controller.isNotExplicitThisInClosure(expression.isImplicitThis())) {
                    field = classNode.getDeclaredField(name);
                    if (field == null && classNode instanceof InnerClassNode) {
                        ClassNode outer = classNode.getOuterClass();
                        FieldNode outerClassField;
                        while (outer != null) {
                            outerClassField = outer.getDeclaredField(name);
                            if (outerClassField != null && outerClassField.isStatic() && outerClassField.isFinal()) {
                                if (outer != classNode.getOuterClass() && Modifier.isPrivate(outerClassField.getModifiers())) {
                                    throw new GroovyBugError("Trying to access private constant field [" + outerClassField.getDeclaringClass() + "#" + outerClassField.getName() + "] from inner class");
                                }
                                PropertyExpression pexp = new PropertyExpression(new ClassExpression(outer), expression.getProperty());
                                pexp.visit(controller.getAcg());
                                return;
                            }
                            outer = outer.getSuperClass();
                        }
                    }
                    if (field == null && expression instanceof AttributeExpression && isThisExpression(objectExpression) && controller.isStaticContext()) {
                        // GROOVY-6183
                        ClassNode current = classNode.getSuperClass();
                        while (field == null && current != null) {
                            field = current.getDeclaredField(name);
                            current = current.getSuperClass();
                        }
                        if (field != null && (field.isProtected() || field.isPublic())) {
                            visitFieldExpression(new FieldExpression(field));
                            return;
                        }
                    }
                }
            }
            if (field != null && !privateSuperField) {
                //GROOVY-4497: don't visit super field if it is private
                visitFieldExpression(new FieldExpression(field));
                return;
            }
        }
        if (isSuperExpression(objectExpression)) {
            String prefix;
            if (controller.getCompileStack().isLHS()) {
                throw new GroovyBugError("Unexpected super property set for:" + expression.getText());
            } else {
                prefix = "get";
            }
            String propName = prefix + MetaClassHelper.capitalize(name);
            visitMethodCallExpression(new MethodCallExpression(objectExpression, propName, MethodCallExpression.NO_ARGUMENTS));
            return;
        }
    }
    final String propName = expression.getPropertyAsString();
    //TODO: add support for super here too
    if (expression.getObjectExpression() instanceof ClassExpression && propName != null && propName.equals("this")) {
        // we have something like A.B.this, and need to make it
        // into this.this$0.this$0, where this.this$0 returns
        // A.B and this.this$0.this$0 return A.
        ClassNode type = objectExpression.getType();
        ClassNode iterType = classNode;
        if (controller.getCompileStack().isInSpecialConstructorCall() && classNode instanceof InnerClassNode) {
            boolean staticInnerClass = classNode.isStaticClass();
            // Outer.this in a special constructor call
            if (classNode.getOuterClass().equals(type)) {
                ConstructorNode ctor = controller.getConstructorNode();
                Expression receiver = !staticInnerClass ? new VariableExpression(ctor.getParameters()[0]) : new ClassExpression(type);
                receiver.setSourcePosition(expression);
                receiver.visit(this);
                return;
            }
        }
        mv.visitVarInsn(ALOAD, 0);
        while (!iterType.equals(type)) {
            String ownerName = BytecodeHelper.getClassInternalName(iterType);
            if (iterType.getOuterClass() == null)
                break;
            FieldNode thisField = iterType.getField("this$0");
            if (thisField == null)
                break;
            ClassNode thisFieldType = thisField.getType();
            iterType = iterType.getOuterClass();
            if (ClassHelper.CLOSURE_TYPE.equals(thisFieldType)) {
                mv.visitFieldInsn(GETFIELD, ownerName, "this$0", BytecodeHelper.getTypeDescription(ClassHelper.CLOSURE_TYPE));
                mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ClassHelper.CLOSURE_TYPE), "getThisObject", "()Ljava/lang/Object;", false);
                mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(iterType));
            } else {
                String typeName = BytecodeHelper.getTypeDescription(iterType);
                mv.visitFieldInsn(GETFIELD, ownerName, "this$0", typeName);
            }
        }
        controller.getOperandStack().push(type);
        return;
    }
    if (adapter == getProperty && !expression.isSpreadSafe() && propName != null) {
        controller.getCallSiteWriter().makeGetPropertySite(objectExpression, propName, expression.isSafe(), expression.isImplicitThis());
    } else if (adapter == getGroovyObjectProperty && !expression.isSpreadSafe() && propName != null) {
        controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression, propName, expression.isSafe(), expression.isImplicitThis());
    } else {
        // todo: for improved modularity and extensibility, this should be moved into a writer
        if (controller.getCompileStack().isLHS())
            controller.getOperandStack().box();
        controller.getInvocationWriter().makeCall(expression, // receiver
        objectExpression, // messageName
        new CastExpression(ClassHelper.STRING_TYPE, expression.getProperty()), MethodCallExpression.NO_ARGUMENTS, adapter, expression.isSafe(), expression.isSpreadSafe(), expression.isImplicitThis());
    }
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) InterfaceHelperClassNode(org.codehaus.groovy.ast.InterfaceHelperClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) GroovyBugError(org.codehaus.groovy.GroovyBugError) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodVisitor(org.objectweb.asm.MethodVisitor) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode)

Example 14 with InnerClassNode

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

the class AsmClassGenerator method makeInnerClassEntry.

private void makeInnerClassEntry(ClassNode cn) {
    if (!(cn instanceof InnerClassNode))
        return;
    InnerClassNode innerClass = (InnerClassNode) cn;
    String innerClassName = innerClass.getName();
    String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
    {
        int index = innerClassName.lastIndexOf('$');
        if (index >= 0)
            innerClassName = innerClassName.substring(index + 1);
    }
    String outerClassName = BytecodeHelper.getClassInternalName(innerClass.getOuterClass().getName());
    MethodNode enclosingMethod = innerClass.getEnclosingMethod();
    if (enclosingMethod != null) {
        // local inner classes do not specify the outer class name
        outerClassName = null;
        innerClassName = null;
    }
    int mods = adjustedClassModifiersForInnerClassTable(cn);
    if (Modifier.isPrivate(mods)) {
        mods = mods ^ Modifier.PRIVATE;
        innerClass.setModifiers(mods);
    }
    cv.visitInnerClass(innerClassInternalName, outerClassName, innerClassName, mods);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 15 with InnerClassNode

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

the class AsmClassGenerator method visitStdMethod.

private void visitStdMethod(MethodNode node, boolean isConstructor, Parameter[] parameters, Statement code) {
    MethodVisitor mv = controller.getMethodVisitor();
    final ClassNode superClass = controller.getClassNode().getSuperClass();
    if (isConstructor && (code == null || !((ConstructorNode) node).firstStatementIsSpecialConstructorCall())) {
        boolean hasCallToSuper = false;
        if (code != null && controller.getClassNode() instanceof InnerClassNode) {
            // so we must ensure not to add it twice (see GROOVY-4471)
            if (code instanceof BlockStatement) {
                for (Statement statement : ((BlockStatement) code).getStatements()) {
                    if (statement instanceof ExpressionStatement) {
                        final Expression expression = ((ExpressionStatement) statement).getExpression();
                        if (expression instanceof ConstructorCallExpression) {
                            ConstructorCallExpression call = (ConstructorCallExpression) expression;
                            if (call.isSuperCall()) {
                                hasCallToSuper = true;
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (!hasCallToSuper) {
            // invokes the super class constructor
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superClass), "<init>", "()V", false);
        }
    }
    controller.getCompileStack().init(node.getVariableScope(), parameters);
    controller.getCallSiteWriter().makeSiteEntry();
    // handle body
    super.visitConstructorOrMethod(node, isConstructor);
    controller.getCompileStack().clear();
    if (node.isVoidMethod()) {
        mv.visitInsn(RETURN);
    } else {
        // we make a dummy return for label ranges that reach here
        ClassNode type = node.getReturnType().redirect();
        if (ClassHelper.isPrimitiveType(type)) {
            mv.visitLdcInsn(0);
            controller.getOperandStack().push(ClassHelper.int_TYPE);
            controller.getOperandStack().doGroovyCast(type);
            BytecodeHelper.doReturn(mv, type);
            controller.getOperandStack().remove(1);
        } else {
            mv.visitInsn(ACONST_NULL);
            BytecodeHelper.doReturn(mv, type);
        }
    }
}
Also used : InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) InterfaceHelperClassNode(org.codehaus.groovy.ast.InterfaceHelperClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) CaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement) ForStatement(org.codehaus.groovy.ast.stmt.ForStatement) CatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) AssertStatement(org.codehaus.groovy.ast.stmt.AssertStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) WhileStatement(org.codehaus.groovy.ast.stmt.WhileStatement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ThrowStatement(org.codehaus.groovy.ast.stmt.ThrowStatement) DoWhileStatement(org.codehaus.groovy.ast.stmt.DoWhileStatement) ContinueStatement(org.codehaus.groovy.ast.stmt.ContinueStatement) BreakStatement(org.codehaus.groovy.ast.stmt.BreakStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) SynchronizedStatement(org.codehaus.groovy.ast.stmt.SynchronizedStatement) SwitchStatement(org.codehaus.groovy.ast.stmt.SwitchStatement) TryCatchStatement(org.codehaus.groovy.ast.stmt.TryCatchStatement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)57 ClassNode (org.codehaus.groovy.ast.ClassNode)49 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 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)8 InterfaceHelperClassNode (org.codehaus.groovy.ast.InterfaceHelperClassNode)8 Expression (org.codehaus.groovy.ast.expr.Expression)8 LinkedList (java.util.LinkedList)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 GenericsType (org.codehaus.groovy.ast.GenericsType)6 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)6 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)6 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)6