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'
+ '''
+ }
}