groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pa...@apache.org
Subject [groovy] 07/07: GROOVY-9051: The default constructor should be annotated with @Generated (add also for inner class case)
Date Fri, 22 Mar 2019 01:41:32 GMT
This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 15b3299db4cc6132bc87f4795dc5dcd68895c647
Author: Paul King <paulk@asert.com.au>
AuthorDate: Fri Mar 22 10:35:44 2019 +1000

    GROOVY-9051: The default constructor should be annotated with @Generated (add also for
inner class case)
---
 .../classgen/InnerClassCompletionVisitor.java      | 927 +++++++++++----------
 1 file changed, 464 insertions(+), 463 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
index 4e07503..452ac65 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -1,463 +1,464 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.codehaus.groovy.classgen;
-
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.ConstructorNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.InnerClassNode;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.TupleExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
-import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.classgen.asm.BytecodeHelper;
-import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.SourceUnit;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-import java.util.List;
-
-import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
-
-public class InnerClassCompletionVisitor extends InnerClassVisitorHelper implements Opcodes
{
-
-    private final SourceUnit sourceUnit;
-    private ClassNode classNode;
-    private FieldNode thisField = null;
-
-    private static final String
-            CLOSURE_INTERNAL_NAME   = BytecodeHelper.getClassInternalName(CLOSURE_TYPE),
-            CLOSURE_DESCRIPTOR      = BytecodeHelper.getTypeDescription(CLOSURE_TYPE);
-
-    public InnerClassCompletionVisitor(CompilationUnit cu, SourceUnit su) {
-        sourceUnit = su;
-    }
-
-    @Override
-    protected SourceUnit getSourceUnit() {
-        return sourceUnit;
-    }
-
-    @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);
-    }
-
-    @Override
-    public void visitConstructor(ConstructorNode node) {
-        addThisReference(node);
-        super.visitConstructor(node);
-    }
-
-    private static String getTypeDescriptor(ClassNode node, boolean isStatic) {
-        return BytecodeHelper.getTypeDescription(getClassNode(node, isStatic));
-    }
-
-    private static String getInternalName(ClassNode node, boolean isStatic) {
-        return BytecodeHelper.getClassInternalName(getClassNode(node, isStatic));
-    }
-
-    private static void addDispatcherMethods(ClassNode classNode) {
-        final int objectDistance = getObjectDistance(classNode);
-
-        // since we added an anonymous inner class we should also
-        // add the dispatcher methods
-
-        // add method dispatcher
-        Parameter[] parameters = new Parameter[]{
-                new Parameter(ClassHelper.STRING_TYPE, "name"),
-                new Parameter(ClassHelper.OBJECT_TYPE, "args")
-        };
-        MethodNode method = classNode.addSyntheticMethod(
-                "this$dist$invoke$" + objectDistance,
-                ACC_PUBLIC + ACC_SYNTHETIC,
-                ClassHelper.OBJECT_TYPE,
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                null
-        );
-
-        BlockStatement block = new BlockStatement();
-        setMethodDispatcherCode(block, VariableExpression.THIS_EXPRESSION, parameters);
-        method.setCode(block);
-
-        // add property setter
-        parameters = new Parameter[]{
-                new Parameter(ClassHelper.STRING_TYPE, "name"),
-                new Parameter(ClassHelper.OBJECT_TYPE, "value")
-        };
-        method = classNode.addSyntheticMethod(
-                "this$dist$set$" + objectDistance,
-                ACC_PUBLIC + ACC_SYNTHETIC,
-                ClassHelper.VOID_TYPE,
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                null
-        );
-
-        block = new BlockStatement();
-        setPropertySetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
-        method.setCode(block);
-
-        // add property getter
-        parameters = new Parameter[]{
-                new Parameter(ClassHelper.STRING_TYPE, "name")
-        };
-        method = classNode.addSyntheticMethod(
-                "this$dist$get$" + objectDistance,
-                ACC_PUBLIC + ACC_SYNTHETIC,
-                ClassHelper.OBJECT_TYPE,
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                null
-        );
-
-        block = new BlockStatement();
-        setPropertyGetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
-        method.setCode(block);
-    }
-
-    private void getThis(MethodVisitor mv, String classInternalName, String outerClassDescriptor,
String innerClassInternalName) {
-        mv.visitVarInsn(ALOAD, 0);
-        if (CLOSURE_TYPE.equals(thisField.getType())) {
-            mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", CLOSURE_DESCRIPTOR);
-            mv.visitMethodInsn(INVOKEVIRTUAL, CLOSURE_INTERNAL_NAME, "getThisObject", "()Ljava/lang/Object;",
false);
-            mv.visitTypeInsn(CHECKCAST, innerClassInternalName);
-        } else {
-            mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", outerClassDescriptor);
-        }
-    }
-    
-    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 missing 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 static missing method dispatcher
-        methodName = "$static_methodMissing";
-        if (isStatic)
-            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
-
-        method = node.addSyntheticMethod(
-                methodName,
-                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
-                ClassHelper.OBJECT_TYPE,
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                null
-        );
-
-        block = new BlockStatement();
-        setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
-        method.setCode(block);
-
-        // add property setter 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(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$set$"
+ objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
-                            mv.visitInsn(RETURN);
-                        }
-                    })
-            );
-        }
-        method.setCode(block);
-
-        // add static property missing setter dispatcher
-        methodName = "$static_propertyMissing";
-        if (isStatic)
-            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
-
-        method = node.addSyntheticMethod(
-                methodName,
-                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
-                ClassHelper.VOID_TYPE,
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                null
-        );
-
-        block = new BlockStatement();
-        setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
-        method.setCode(block);
-
-        // add property getter 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(outerClass), 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);
-
-        // add static property missing getter dispatcher
-        methodName = "$static_propertyMissing";
-        if (isStatic)
-            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
-
-        method = node.addSyntheticMethod(
-                methodName,
-                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
-                ClassHelper.OBJECT_TYPE,
-                parameters,
-                ClassNode.EMPTY_ARRAY,
-                null
-        );
-
-        block = new BlockStatement();
-        setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
-        method.setCode(block);
-    }
-
-    /**
-     * Adds a compilation error if a {@link MethodNode} with the given <tt>methodName</tt>
and
-     * <tt>parameters</tt> exists in the {@link InnerClassNode}.
-     */
-    private void addCompilationErrorOnCustomMethodNode(InnerClassNode node, String methodName,
Parameter[] parameters) {
-        MethodNode existingMethodNode = node.getMethod(methodName, parameters);
-        // if there is a user-defined methodNode, add compiler error msg and continue
-        if (existingMethodNode != null && !isSynthetic(existingMethodNode))  {
-            addError("\"" +methodName + "\" implementations are not supported on static inner
classes as " +
-                    "a synthetic version of \"" + methodName + "\" is added during compilation
for the purpose " +
-                    "of outer class delegation.",
-                    existingMethodNode);
-        }
-    }
-
-    // GROOVY-8914: pre-compiled classes lose synthetic boolean - TODO fix earlier as per
GROOVY-4346 then remove extra check here
-    private boolean isSynthetic(MethodNode existingMethodNode) {
-        return existingMethodNode.isSynthetic() || hasSyntheticModifier(existingMethodNode);
-    }
-
-    private boolean hasSyntheticModifier(MethodNode existingMethodNode) {
-        return (existingMethodNode.getModifiers() & Opcodes.ACC_SYNTHETIC) != 0;
-    }
-
-    private void addThisReference(ConstructorNode node) {
-        if (!shouldHandleImplicitThisForInnerClass(classNode)) return;
-        Statement code = node.getCode();
-
-        // add "this$0" field init
-
-        //add this parameter to node
-        Parameter[] params = node.getParameters();
-        Parameter[] newParams = new Parameter[params.length + 1];
-        System.arraycopy(params, 0, newParams, 1, params.length);
-        String name = getUniqueName(params, node);
-
-        Parameter thisPara = new Parameter(classNode.getOuterClass().getPlainNodeReference(),
name);
-        newParams[0] = thisPara;
-        node.setParameters(newParams);
-
-        BlockStatement block = null;
-        if (code == null) {
-            block = new BlockStatement();
-        } else if (!(code instanceof BlockStatement)) {
-            block = new BlockStatement();
-            block.addStatement(code);
-        } else {
-            block = (BlockStatement) code;
-        }
-        BlockStatement newCode = new BlockStatement();
-        addFieldInit(thisPara, thisField, newCode);
-        ConstructorCallExpression cce = getFirstIfSpecialConstructorCall(block);
-        if (cce == null) {
-            cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression());
-            block.getStatements().add(0, new ExpressionStatement(cce));
-        }
-        if (shouldImplicitlyPassThisPara(cce)) {
-            // add thisPara to this(...)
-            TupleExpression args = (TupleExpression) cce.getArguments();
-            List<Expression> expressions = args.getExpressions();
-            VariableExpression ve = new VariableExpression(thisPara.getName());
-            ve.setAccessedVariable(thisPara);
-            expressions.add(0, ve);
-        }
-        if (cce.isSuperCall()) {
-            // we have a call to super here, so we need to add
-            // our code after that
-            block.getStatements().add(1, newCode);
-        }
-        node.setCode(block);
-    }
-
-    private boolean shouldImplicitlyPassThisPara(ConstructorCallExpression cce) {
-        boolean pass = false;
-        ClassNode superCN = classNode.getSuperClass();
-        if (cce.isThisCall()) {
-            pass = true;
-        } else if (cce.isSuperCall()) {
-            // if the super class is another non-static inner class in the same outer class
hierarchy, implicit this
-            // 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;
-    }
-
-    private String getUniqueName(Parameter[] params, ConstructorNode node) {
-        String namePrefix = "$p";
-        outer:
-        for (int i = 0; i < 100; i++) {
-            namePrefix = namePrefix + "$";
-            for (Parameter p : params) {
-                if (p.getName().equals(namePrefix)) continue outer;
-            }
-            return namePrefix;
-        }
-        addError("unable to find a unique prefix name for synthetic this reference in inner
class constructor", node);
-        return namePrefix;
-    }
-
-    private static ConstructorCallExpression getFirstIfSpecialConstructorCall(BlockStatement
code) {
-        if (code == null) return null;
-
-        final List<Statement> statementList = code.getStatements();
-        if (statementList.isEmpty()) return null;
-
-        final Statement statement = statementList.get(0);
-        if (!(statement instanceof ExpressionStatement)) return null;
-
-        Expression expression = ((ExpressionStatement) statement).getExpression();
-        if (!(expression instanceof ConstructorCallExpression)) return null;
-        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
-        if (cce.isSpecialCall()) return cce;
-        return null;
-    }
-}
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.List;
+
+import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedConstructor;
+import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+
+public class InnerClassCompletionVisitor extends InnerClassVisitorHelper implements Opcodes
{
+
+    private final SourceUnit sourceUnit;
+    private ClassNode classNode;
+    private FieldNode thisField = null;
+
+    private static final String
+            CLOSURE_INTERNAL_NAME   = BytecodeHelper.getClassInternalName(CLOSURE_TYPE),
+            CLOSURE_DESCRIPTOR      = BytecodeHelper.getTypeDescription(CLOSURE_TYPE);
+
+    public InnerClassCompletionVisitor(CompilationUnit cu, SourceUnit su) {
+        sourceUnit = su;
+    }
+
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    @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 empty default constructor
+                addGeneratedConstructor(innerClass, 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);
+    }
+
+    @Override
+    public void visitConstructor(ConstructorNode node) {
+        addThisReference(node);
+        super.visitConstructor(node);
+    }
+
+    private static String getTypeDescriptor(ClassNode node, boolean isStatic) {
+        return BytecodeHelper.getTypeDescription(getClassNode(node, isStatic));
+    }
+
+    private static String getInternalName(ClassNode node, boolean isStatic) {
+        return BytecodeHelper.getClassInternalName(getClassNode(node, isStatic));
+    }
+
+    private static void addDispatcherMethods(ClassNode classNode) {
+        final int objectDistance = getObjectDistance(classNode);
+
+        // since we added an anonymous inner class we should also
+        // add the dispatcher methods
+
+        // add method dispatcher
+        Parameter[] parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name"),
+                new Parameter(ClassHelper.OBJECT_TYPE, "args")
+        };
+        MethodNode method = classNode.addSyntheticMethod(
+                "this$dist$invoke$" + objectDistance,
+                ACC_PUBLIC + ACC_SYNTHETIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        BlockStatement block = new BlockStatement();
+        setMethodDispatcherCode(block, VariableExpression.THIS_EXPRESSION, parameters);
+        method.setCode(block);
+
+        // add property setter
+        parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name"),
+                new Parameter(ClassHelper.OBJECT_TYPE, "value")
+        };
+        method = classNode.addSyntheticMethod(
+                "this$dist$set$" + objectDistance,
+                ACC_PUBLIC + ACC_SYNTHETIC,
+                ClassHelper.VOID_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertySetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
+        method.setCode(block);
+
+        // add property getter
+        parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name")
+        };
+        method = classNode.addSyntheticMethod(
+                "this$dist$get$" + objectDistance,
+                ACC_PUBLIC + ACC_SYNTHETIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertyGetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
+        method.setCode(block);
+    }
+
+    private void getThis(MethodVisitor mv, String classInternalName, String outerClassDescriptor,
String innerClassInternalName) {
+        mv.visitVarInsn(ALOAD, 0);
+        if (CLOSURE_TYPE.equals(thisField.getType())) {
+            mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", CLOSURE_DESCRIPTOR);
+            mv.visitMethodInsn(INVOKEVIRTUAL, CLOSURE_INTERNAL_NAME, "getThisObject", "()Ljava/lang/Object;",
false);
+            mv.visitTypeInsn(CHECKCAST, innerClassInternalName);
+        } else {
+            mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", outerClassDescriptor);
+        }
+    }
+    
+    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 missing 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 static missing method dispatcher
+        methodName = "$static_methodMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
+        method.setCode(block);
+
+        // add property setter 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(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$set$"
+ objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
+                            mv.visitInsn(RETURN);
+                        }
+                    })
+            );
+        }
+        method.setCode(block);
+
+        // add static property missing setter dispatcher
+        methodName = "$static_propertyMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                ClassHelper.VOID_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
+        method.setCode(block);
+
+        // add property getter 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(outerClass), 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);
+
+        // add static property missing getter dispatcher
+        methodName = "$static_propertyMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
+        method.setCode(block);
+    }
+
+    /**
+     * Adds a compilation error if a {@link MethodNode} with the given <tt>methodName</tt>
and
+     * <tt>parameters</tt> exists in the {@link InnerClassNode}.
+     */
+    private void addCompilationErrorOnCustomMethodNode(InnerClassNode node, String methodName,
Parameter[] parameters) {
+        MethodNode existingMethodNode = node.getMethod(methodName, parameters);
+        // if there is a user-defined methodNode, add compiler error msg and continue
+        if (existingMethodNode != null && !isSynthetic(existingMethodNode))  {
+            addError("\"" +methodName + "\" implementations are not supported on static inner
classes as " +
+                    "a synthetic version of \"" + methodName + "\" is added during compilation
for the purpose " +
+                    "of outer class delegation.",
+                    existingMethodNode);
+        }
+    }
+
+    // GROOVY-8914: pre-compiled classes lose synthetic boolean - TODO fix earlier as per
GROOVY-4346 then remove extra check here
+    private boolean isSynthetic(MethodNode existingMethodNode) {
+        return existingMethodNode.isSynthetic() || hasSyntheticModifier(existingMethodNode);
+    }
+
+    private boolean hasSyntheticModifier(MethodNode existingMethodNode) {
+        return (existingMethodNode.getModifiers() & Opcodes.ACC_SYNTHETIC) != 0;
+    }
+
+    private void addThisReference(ConstructorNode node) {
+        if (!shouldHandleImplicitThisForInnerClass(classNode)) return;
+        Statement code = node.getCode();
+
+        // add "this$0" field init
+
+        //add this parameter to node
+        Parameter[] params = node.getParameters();
+        Parameter[] newParams = new Parameter[params.length + 1];
+        System.arraycopy(params, 0, newParams, 1, params.length);
+        String name = getUniqueName(params, node);
+
+        Parameter thisPara = new Parameter(classNode.getOuterClass().getPlainNodeReference(),
name);
+        newParams[0] = thisPara;
+        node.setParameters(newParams);
+
+        BlockStatement block = null;
+        if (code == null) {
+            block = new BlockStatement();
+        } else if (!(code instanceof BlockStatement)) {
+            block = new BlockStatement();
+            block.addStatement(code);
+        } else {
+            block = (BlockStatement) code;
+        }
+        BlockStatement newCode = new BlockStatement();
+        addFieldInit(thisPara, thisField, newCode);
+        ConstructorCallExpression cce = getFirstIfSpecialConstructorCall(block);
+        if (cce == null) {
+            cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression());
+            block.getStatements().add(0, new ExpressionStatement(cce));
+        }
+        if (shouldImplicitlyPassThisPara(cce)) {
+            // add thisPara to this(...)
+            TupleExpression args = (TupleExpression) cce.getArguments();
+            List<Expression> expressions = args.getExpressions();
+            VariableExpression ve = new VariableExpression(thisPara.getName());
+            ve.setAccessedVariable(thisPara);
+            expressions.add(0, ve);
+        }
+        if (cce.isSuperCall()) {
+            // we have a call to super here, so we need to add
+            // our code after that
+            block.getStatements().add(1, newCode);
+        }
+        node.setCode(block);
+    }
+
+    private boolean shouldImplicitlyPassThisPara(ConstructorCallExpression cce) {
+        boolean pass = false;
+        ClassNode superCN = classNode.getSuperClass();
+        if (cce.isThisCall()) {
+            pass = true;
+        } else if (cce.isSuperCall()) {
+            // if the super class is another non-static inner class in the same outer class
hierarchy, implicit this
+            // 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;
+    }
+
+    private String getUniqueName(Parameter[] params, ConstructorNode node) {
+        String namePrefix = "$p";
+        outer:
+        for (int i = 0; i < 100; i++) {
+            namePrefix = namePrefix + "$";
+            for (Parameter p : params) {
+                if (p.getName().equals(namePrefix)) continue outer;
+            }
+            return namePrefix;
+        }
+        addError("unable to find a unique prefix name for synthetic this reference in inner
class constructor", node);
+        return namePrefix;
+    }
+
+    private static ConstructorCallExpression getFirstIfSpecialConstructorCall(BlockStatement
code) {
+        if (code == null) return null;
+
+        final List<Statement> statementList = code.getStatements();
+        if (statementList.isEmpty()) return null;
+
+        final Statement statement = statementList.get(0);
+        if (!(statement instanceof ExpressionStatement)) return null;
+
+        Expression expression = ((ExpressionStatement) statement).getExpression();
+        if (!(expression instanceof ConstructorCallExpression)) return null;
+        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+        if (cce.isSpecialCall()) return cce;
+        return null;
+    }
+}


Mime
View raw message