You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/08/23 03:19:04 UTC

groovy git commit: GROOVY-8758: @WithReadLock in inner class of @CompileStatic class causes java.lang.VerifyError (closes #787)

Repository: groovy
Updated Branches:
  refs/heads/master e63fec79e -> 52f82765b


GROOVY-8758: @WithReadLock in inner class of @CompileStatic class causes java.lang.VerifyError (closes #787)


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

Branch: refs/heads/master
Commit: 52f82765b5e7a426aa67610cb2c30fac11025ed9
Parents: e63fec7
Author: Paul King <pa...@asert.com.au>
Authored: Tue Aug 21 15:22:21 2018 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Thu Aug 23 13:17:55 2018 +1000

----------------------------------------------------------------------
 .../ReadWriteLockASTTransformation.java         | 33 ++++----
 .../groovy/transform/ReadWriteLockTest.groovy   | 89 ++++++++++++--------
 2 files changed, 71 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/52f82765/src/main/java/org/codehaus/groovy/transform/ReadWriteLockASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/ReadWriteLockASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/ReadWriteLockASTTransformation.java
index 52bc58c..7ef8778 100644
--- a/src/main/java/org/codehaus/groovy/transform/ReadWriteLockASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/ReadWriteLockASTTransformation.java
@@ -28,6 +28,7 @@ import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
 import org.codehaus.groovy.control.CompilePhase;
@@ -49,8 +50,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
  * Any method annotated with {@code @}WithReadLock will obtain a read lock and release it in a finally block.<br>
  * Any method annotated with {@code @}WithWriteLock will obtain a write lock and release it in a finally block.<br>
  * For more information see {@link WithReadLock} and {@link WithWriteLock}
- *
- * @author Hamlet D'Arcy
  */
 @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
 public class ReadWriteLockASTTransformation extends AbstractASTTransformation {
@@ -81,19 +80,19 @@ public class ReadWriteLockASTTransformation extends AbstractASTTransformation {
         if (parent instanceof MethodNode) {
             MethodNode mNode = (MethodNode) parent;
             ClassNode cNode = mNode.getDeclaringClass();
-            String lockExpr = determineLock(value, cNode, mNode.isStatic(), myTypeName);
+            FieldNode lockExpr = determineLock(value, cNode, mNode.isStatic(), myTypeName);
             if (lockExpr == null) return;
 
             // get lock type
-            final Expression lockType;
-            if (isWriteLock) {
-                lockType = callX(varX(lockExpr, LOCK_TYPE), "writeLock");
-            } else {
-                lockType = callX(varX(lockExpr, LOCK_TYPE), "readLock");
-            }
+            final MethodCallExpression lockType = callX(varX(lockExpr), isWriteLock ? "writeLock" : "readLock");
+            lockType.setImplicitThis(false);
+
+            MethodCallExpression acquireLock = callX(lockType, "lock");
+            acquireLock.setImplicitThis(false);
+
+            MethodCallExpression releaseLock = callX(lockType, "unlock");
+            releaseLock.setImplicitThis(false);
 
-            Expression acquireLock = callX(lockType, "lock");
-            Expression releaseLock = callX(lockType, "unlock");
             Statement originalCode = mNode.getCode();
 
             mNode.setCode(block(
@@ -102,7 +101,7 @@ public class ReadWriteLockASTTransformation extends AbstractASTTransformation {
         }
     }
 
-    private String determineLock(String value, ClassNode targetClass, boolean isStatic, String myTypeName) {
+    private FieldNode determineLock(String value, ClassNode targetClass, boolean isStatic, String myTypeName) {
         if (value != null && value.length() > 0 && !value.equalsIgnoreCase(DEFAULT_INSTANCE_LOCKNAME)) {
             FieldNode existingLockField = targetClass.getDeclaredField(value);
             if (existingLockField == null) {
@@ -113,28 +112,28 @@ public class ReadWriteLockASTTransformation extends AbstractASTTransformation {
                 addError("Error during " + myTypeName + " processing: lock field with name '" + value + "' should " + (isStatic ? "" : "not ") + "be static", existingLockField);
                 return null;
             }
-            return value;
+            return existingLockField;
         }
         if (isStatic) {
             FieldNode field = targetClass.getDeclaredField(DEFAULT_STATIC_LOCKNAME);
             if (field == null) {
                 int visibility = ACC_PRIVATE | ACC_STATIC | ACC_FINAL;
-                targetClass.addField(DEFAULT_STATIC_LOCKNAME, visibility, LOCK_TYPE, createLockObject());
+                field = targetClass.addField(DEFAULT_STATIC_LOCKNAME, visibility, LOCK_TYPE, createLockObject());
             } else if (!field.isStatic()) {
                 addError("Error during " + myTypeName + " processing: " + DEFAULT_STATIC_LOCKNAME + " field must be static", field);
                 return null;
             }
-            return DEFAULT_STATIC_LOCKNAME;
+            return field;
         }
         FieldNode field = targetClass.getDeclaredField(DEFAULT_INSTANCE_LOCKNAME);
         if (field == null) {
             int visibility = ACC_PRIVATE | ACC_FINAL;
-            targetClass.addField(DEFAULT_INSTANCE_LOCKNAME, visibility, LOCK_TYPE, createLockObject());
+            field = targetClass.addField(DEFAULT_INSTANCE_LOCKNAME, visibility, LOCK_TYPE, createLockObject());
         } else if (field.isStatic()) {
             addError("Error during " + myTypeName + " processing: " + DEFAULT_INSTANCE_LOCKNAME + " field must not be static", field);
             return null;
         }
-        return DEFAULT_INSTANCE_LOCKNAME;
+        return field;
     }
 
     private static Expression createLockObject() {

http://git-wip-us.apache.org/repos/asf/groovy/blob/52f82765/src/test/groovy/transform/ReadWriteLockTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/ReadWriteLockTest.groovy b/src/test/groovy/transform/ReadWriteLockTest.groovy
index 3609235..2944f8e 100644
--- a/src/test/groovy/transform/ReadWriteLockTest.groovy
+++ b/src/test/groovy/transform/ReadWriteLockTest.groovy
@@ -23,12 +23,10 @@ import java.lang.reflect.Modifier
 
 /**
  * Unit test for WithReadLock and WithWriteLock annotations.
- *
- * @author Hamlet D'Arcy
  */
 class ReadWriteLockTest extends GroovyTestCase {
 
-    public void testLockFieldDefaultsForReadLock() {
+    void testLockFieldDefaultsForReadLock() {
         def tester = new GroovyClassLoader().parseClass('''
         class MyClass {
             @groovy.transform.WithReadLock
@@ -44,7 +42,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         assert field.type == ReentrantReadWriteLock
     }
 
-    public void testLockFieldDefaultsForWriteLock() {
+    void testLockFieldDefaultsForWriteLock() {
         def tester = new GroovyClassLoader().parseClass('''
         class MyClass {
             @groovy.transform.WithWriteLock
@@ -60,7 +58,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         assert field.type == ReentrantReadWriteLock
     }
 
-    public void testLockFieldDefaultsForStaticReadLock() {
+    void testLockFieldDefaultsForStaticReadLock() {
         def tester = new GroovyClassLoader().parseClass('''
         class MyClass {
             @groovy.transform.WithReadLock
@@ -76,7 +74,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         assert field.type == ReentrantReadWriteLock
     }
 
-    public void testLockFieldDefaultsForStaticWriteLock() {
+    void testLockFieldDefaultsForStaticWriteLock() {
         def tester = new GroovyClassLoader().parseClass('''
         class MyClass {
             @groovy.transform.WithWriteLock
@@ -92,7 +90,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         assert field.type == ReentrantReadWriteLock
     }
 
-    public void testLocking() {
+    void testLocking() {
 
         def tester = new MyClass()
         tester.readerMethod1()
@@ -111,7 +109,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         tester.readerMethod1()
     }
 
-    public void testStaticLocking() {
+    void testStaticLocking() {
 
         def tester = new MyClass()
         tester.staticReaderMethod1()
@@ -130,7 +128,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         tester.staticReaderMethod1()
     }
 
-    public void testDeadlockingDoesNotOccur() {
+    void testDeadlockingDoesNotOccur() {
         def tester = new MyClass()
 
         // this tests for deadlocks from not releaseing in finally block 
@@ -145,7 +143,7 @@ class ReadWriteLockTest extends GroovyTestCase {
         shouldFail { tester.namedReaderMethod1() }
     }
 
-    public void testCompileError_NamingConflict() {
+    void testCompileError_NamingConflict() {
         shouldFail("lock field with name 'unknown' not found") {
             '''
             class MyClass {
@@ -175,6 +173,29 @@ class ReadWriteLockTest extends GroovyTestCase {
         }
     }
 
+    // GROOVY-8758
+    void testShouldBeAllowedInInnerClassWithCompileStatic() {
+        assertScript '''
+            import groovy.transform.*
+
+            @CompileStatic
+            class A {
+                private class B {
+                    @WithReadLock
+                    int getFoo() { 0 }
+                }
+
+                private B b
+
+                A() {
+                    b = new B()
+                }
+            }
+
+            def a = new A()
+        '''
+    }
+
     def shouldFail(String expectedText, Closure c) {
         String script = c()
         try {
@@ -198,54 +219,54 @@ class MyClass {
     def staticWriterMethod2Called = false
     def myLock = new ReentrantReadWriteLock()
     
-    @groovy.transform.WithReadLock
-    public void readerMethod1() {
+    @WithReadLock
+    void readerMethod1() {
         readerMethod1Called = true
     }
-    @groovy.transform.WithReadLock
-    public void readerMethod2() {
+    @WithReadLock
+    void readerMethod2() {
         readerMethod2Called = true
     }
-    @groovy.transform.WithWriteLock
-    public void writerMethod1() {
+    @WithWriteLock
+    void writerMethod1() {
         writerMethod1Called = true
     }
-    @groovy.transform.WithWriteLock
-    public void writerMethod2() {
+    @WithWriteLock
+    void writerMethod2() {
         writerMethod2Called = true
     }
 
-    @groovy.transform.WithReadLock('myLock')
-    public void namedReaderMethod1() {
+    @WithReadLock('myLock')
+    void namedReaderMethod1() {
         throw new Exception()
     }
-    @groovy.transform.WithReadLock('myLock')
-    public void namedReaderMethod2() {
+    @WithReadLock('myLock')
+    void namedReaderMethod2() {
         throw new Exception()
     }
-    @groovy.transform.WithWriteLock('myLock')
-    public void namedWriterMethod1() {
+    @WithWriteLock('myLock')
+    void namedWriterMethod1() {
         throw new Exception()
     }
-    @groovy.transform.WithWriteLock('myLock')
-    public void namedWriterMethod2() {
+    @WithWriteLock('myLock')
+    void namedWriterMethod2() {
         throw new Exception()
     }
 
-    @groovy.transform.WithReadLock
-    public void staticReaderMethod1() {
+    @WithReadLock
+    void staticReaderMethod1() {
         staticReaderMethod1Called = true
     }
-    @groovy.transform.WithReadLock
-    public void staticReaderMethod2() {
+    @WithReadLock
+    void staticReaderMethod2() {
         staticReaderMethod2Called = true
     }
-    @groovy.transform.WithWriteLock
-    public void staticWriterMethod1() {
+    @WithWriteLock
+    void staticWriterMethod1() {
         staticWriterMethod1Called = true
     }
-    @groovy.transform.WithWriteLock
-    public void staticWriterMethod2() {
+    @WithWriteLock
+    void staticWriterMethod2() {
         staticWriterMethod2Called = true
     }
 }