You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by sh...@apache.org on 2016/07/02 16:56:36 UTC

groovy git commit: GROOVY-7558 Add private field accessors and bridge methods to dynamic classes with statically compiled inner classes

Repository: groovy
Updated Branches:
  refs/heads/master e9417a4cc -> 68d9f3f36


GROOVY-7558 Add private field accessors and bridge methods to dynamic classes with statically compiled inner classes


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/68d9f3f3
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/68d9f3f3
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/68d9f3f3

Branch: refs/heads/master
Commit: 68d9f3f36ad1cca96503d04d2b5c83e565786ea6
Parents: e9417a4
Author: Shil S <sh...@gmail.com>
Authored: Sun Oct 11 15:58:52 2015 -0400
Committer: Shil Sinha <sh...@apache.org>
Committed: Sat Jul 2 12:16:01 2016 -0400

----------------------------------------------------------------------
 .../groovy/control/CompilationUnit.java         | 14 ++-
 .../sc/StaticCompilationMetadataKeys.java       |  1 +
 .../transform/sc/StaticCompilationVisitor.java  | 22 ++++-
 .../sc/MixedModeStaticCompilationTest.groovy    | 93 ++++++++++++++++++++
 4 files changed, 128 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/68d9f3f3/src/main/org/codehaus/groovy/control/CompilationUnit.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/control/CompilationUnit.java b/src/main/org/codehaus/groovy/control/CompilationUnit.java
index 0c5726f..c335499 100644
--- a/src/main/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/org/codehaus/groovy/control/CompilationUnit.java
@@ -35,6 +35,7 @@ import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.tools.GroovyClass;
 import org.codehaus.groovy.transform.ASTTransformationVisitor;
 import org.codehaus.groovy.transform.AnnotationCollectorTransform;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
 import org.codehaus.groovy.transform.trait.TraitComposer;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
@@ -237,6 +238,17 @@ public class CompilationUnit extends ProcessingUnit {
                 ecv.visitClass(classNode);
             }
         }, Phases.CANONICALIZATION);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                Object callback = classNode.getNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+                if (callback instanceof PrimaryClassNodeOperation) {
+                    ((PrimaryClassNodeOperation) callback).call(source, context, classNode);
+                    classNode.removeNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+                }
+            }
+        }, Phases.INSTRUCTION_SELECTION);
 
         // apply configuration customizers if any
         if (configuration != null) {
@@ -956,7 +968,7 @@ public class CompilationUnit extends ProcessingUnit {
 
 
     /**
-     * An callback interface for use in the applyToSourceUnits loop driver.
+     * An callback interface for use in the applyToPrimaryClassNodes loop driver.
      */
     public abstract static class PrimaryClassNodeOperation {
         public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;

http://git-wip-us.apache.org/repos/asf/groovy/blob/68d9f3f3/src/main/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java b/src/main/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
index 3409368..0e4ddee 100644
--- a/src/main/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
+++ b/src/main/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
@@ -29,6 +29,7 @@ public enum StaticCompilationMetadataKeys {
     PRIVATE_BRIDGE_METHODS, // private bridge methods are methods used by an outer class to access an inner class method
     PRIVATE_FIELDS_ACCESSORS, // private fields accessors are methods used by an inner class to access an outer class field
     PRIVATE_FIELDS_MUTATORS, // private fields mutators are methods used by an inner class to set an outer class field
+    DYNAMIC_OUTER_NODE_CALLBACK, // callback for dynamic classes that contain statically compiled inner classes or methods
     PROPERTY_OWNER, // the type of the class which owns the property
     COMPONENT_TYPE, // for list.property expressions, we need the inferred component type
     RECEIVER_OF_DYNAMIC_PROPERTY // if a receiver is the receiver of a dynamic property (for mixed mode compilation)

http://git-wip-us.apache.org/repos/asf/groovy/blob/68d9f3f3/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java b/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index db99dbc..f385c49 100644
--- a/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -28,9 +28,12 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.asm.*;
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationMopWriter;
 import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
@@ -102,6 +105,21 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         }
     }
 
+    private void addDynamicOuterClassAccessorsCallback(final ClassNode outer) {
+        if (outer != null && !isStaticallyCompiled(outer)
+                && outer.getNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK) == null) {
+            outer.putNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK, new CompilationUnit.PrimaryClassNodeOperation() {
+                @Override
+                public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+                    if (classNode == outer) {
+                        addPrivateBridgeMethods(classNode);
+                        addPrivateFieldsAccessors(classNode);
+                    }
+                }
+            });
+        }
+    }
+
     @Override
     public void visitClass(final ClassNode node) {
         boolean skip = shouldSkipClassNode(node);
@@ -122,6 +140,7 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         }
         super.visitClass(node);
         addPrivateFieldAndMethodAccessors(node);
+        if (isStaticallyCompiled(node)) addDynamicOuterClassAccessorsCallback(node.getOuterClass());
         classNode = oldCN;
     }
 
@@ -136,7 +155,7 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
      * If we are in a constructor, that is static compiled, but in a class, that
      * is not, it may happen that init code from object initializers, fields
      * or properties is added into the constructor code. The backend assumes
-     * a purely static contructor, so it may fail if it encounters dynamic
+     * a purely static constructor, so it may fail if it encounters dynamic
      * code here. Thus we make this kind of code fail
      */
     private void checkForConstructorWithCSButClassWithout(MethodNode node) {
@@ -163,6 +182,7 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         }
         super.visitMethod(node);
         checkForConstructorWithCSButClassWithout(node);
+        if (isStaticallyCompiled(node)) addDynamicOuterClassAccessorsCallback(node.getDeclaringClass());
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/groovy/blob/68d9f3f3/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy
index 3f11eb6..395e682 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy
@@ -292,4 +292,97 @@ class MixedModeStaticCompilationTest extends StaticTypeCheckingTestCase implemen
 
     }
 
+    void testSCClosureCanAccessPrivateFieldsOfNonSCEnclosingClass() {
+        assertScript '''
+            class Test {
+                private String str = "hi"
+
+                @groovy.transform.CompileStatic
+                String strInSCClosure() {
+                    Closure c = { str }
+                    c()
+                }
+            }
+            assert new Test().strInSCClosure() == 'hi'
+        '''
+    }
+
+    void testSCClosureCanAccessPrivateMethodsOfNonSCEnclosingClass() {
+        assertScript '''
+            class Test {
+                private String str() { 'hi' }
+
+                @groovy.transform.CompileStatic
+                String strInSCClosure() {
+                    Closure c = { str() }
+                    c()
+                }
+            }
+            assert new Test().strInSCClosure() == 'hi'
+        '''
+    }
+
+    void testSCInnerClassCanAccessPrivateFieldsOfNonSCOuterClass() {
+        assertScript '''
+            class Test {
+                private String str = "hi"
+
+                @groovy.transform.CompileStatic
+                class Inner {
+                    String outerStr() { str }
+                }
+
+                String strInSCInner() { new Inner().outerStr() }
+            }
+            assert new Test().strInSCInner() == 'hi'
+        '''
+    }
+
+    void testSCInnerClassCanAccessPrivateMethodsOfNonSCOuterClass() {
+        assertScript '''
+            class Test {
+                private String str() { 'hi' }
+
+                @groovy.transform.CompileStatic
+                class Inner {
+                    String outerStr() { str() }
+                }
+
+                String strInSCInner() { new Inner().outerStr() }
+            }
+            assert new Test().strInSCInner() == 'hi'
+        '''
+    }
+
+    void testSCAICCanAccessPrivateFieldsOfNonSCOuterClass() {
+        assertScript '''
+            class Test {
+                private String str = "hi"
+
+                @groovy.transform.CompileStatic
+                String strInSCAIC() {
+                    new Object() {
+                        String outerStr() { str }
+                    }.outerStr()
+                }
+            }
+            assert new Test().strInSCAIC() == 'hi'
+        '''
+    }
+
+    void testSCAICCanAccessPrivateMethodsOfNonSCOuterClass() {
+        assertScript '''
+            class Test {
+                private String str() { 'hi' }
+
+                @groovy.transform.CompileStatic
+                String strInSCAIC() {
+                    new Object() {
+                        String outerStr() { str() }
+                    }.outerStr()
+                }
+            }
+            assert new Test().strInSCAIC() == 'hi'
+        '''
+    }
 }