You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/02/03 19:37:32 UTC

[groovy] branch GROOVY_2_5_X updated (048925d -> d0cbcfe)

This is an automated email from the ASF dual-hosted git repository.

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


    from 048925d  GROOVY-9974: extract generics connections: Closure<T> vs SAM return type
     new 40b49a8  GROOVY-10352: class model: load anno enum value as property expression
     new bb1789f  GROOVY-10457: support `@CompileStatic` class with `@CompileDynamic` ctor
     new cb33448  GROOVY-7033: visit AIC's field, method, and parameter annotations
     new d0cbcfe  GROOVY-5736: xform loader for annotations and class loader for libraries

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../groovy/classgen/VariableScopeVisitor.java      |  21 ++--
 .../groovy/transform/LogASTTransformation.java     |  24 ++--
 .../transform/sc/StaticCompilationVisitor.java     |  58 +++++-----
 .../org/codehaus/groovy/vmplugin/v5/Java5.java     |  14 ++-
 src/test/gls/annotations/AnnotationTest.groovy     |  17 +++
 .../closures/AnnotationClosureTest.groovy          |  16 ++-
 .../classgen/asm/sc/CompileDynamicTest.groovy      |  40 +++++--
 .../asm/sc/MixedModeStaticCompilationTest.groovy   |  14 +++
 .../asm/sc/StaticCompileConstructorsTest.groovy    | 126 +++++++++------------
 9 files changed, 183 insertions(+), 147 deletions(-)

[groovy] 04/04: GROOVY-5736: xform loader for annotations and class loader for libraries

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d0cbcfee18ddcef560ccf8f5c3b5ae390d1e3c1a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Dec 19 14:49:40 2021 -0600

    GROOVY-5736: xform loader for annotations and class loader for libraries
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
---
 .../groovy/transform/LogASTTransformation.java     | 24 ++++++++++------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
index ac9af0b..85c456e 100644
--- a/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java
@@ -66,8 +66,7 @@ public class LogASTTransformation extends AbstractASTTransformation implements C
         AnnotatedNode targetClass = (AnnotatedNode) nodes[1];
         AnnotationNode logAnnotation = (AnnotationNode) nodes[0];
 
-        final GroovyClassLoader classLoader = compilationUnit != null ? compilationUnit.getTransformLoader() : source.getClassLoader();
-        final LoggingStrategy loggingStrategy = createLoggingStrategy(logAnnotation, classLoader);
+        final LoggingStrategy loggingStrategy = createLoggingStrategy(logAnnotation, source.getClassLoader(), compilationUnit.getTransformLoader());
         if (loggingStrategy == null) return;
 
         final String logFieldName = lookupLogFieldName(logAnnotation);
@@ -189,28 +188,27 @@ public class LogASTTransformation extends AbstractASTTransformation implements C
         return DEFAULT_CATEGORY_NAME;
     }
 
-    private static LoggingStrategy createLoggingStrategy(AnnotationNode logAnnotation, GroovyClassLoader loader) {
-
+    private static LoggingStrategy createLoggingStrategy(AnnotationNode logAnnotation, ClassLoader classLoader, ClassLoader xformLoader) {
         String annotationName = logAnnotation.getClassNode().getName();
 
         Class annotationClass;
         try {
-            annotationClass = Class.forName(annotationName, false, loader);
-        } catch (Throwable e) {
+            annotationClass = Class.forName(annotationName, false, xformLoader);
+        } catch (Throwable t) {
             throw new RuntimeException("Could not resolve class named " + annotationName);
         }
 
         Method annotationMethod;
         try {
             annotationMethod = annotationClass.getDeclaredMethod("loggingStrategy", (Class[]) null);
-        } catch (Throwable e) {
+        } catch (Throwable t) {
             throw new RuntimeException("Could not find method named loggingStrategy on class named " + annotationName);
         }
 
         Object defaultValue;
         try {
             defaultValue = annotationMethod.getDefaultValue();
-        } catch (Throwable e) {
+        } catch (Throwable t) {
             throw new RuntimeException("Could not find default value of method named loggingStrategy on class named " + annotationName);
         }
 
@@ -221,7 +219,7 @@ public class LogASTTransformation extends AbstractASTTransformation implements C
         try {
             Class<? extends LoggingStrategy> strategyClass = (Class<? extends LoggingStrategy>) defaultValue;
             if (AbstractLoggingStrategy.class.isAssignableFrom(strategyClass)) {
-                return DefaultGroovyMethods.newInstance(strategyClass, new Object[]{loader});
+                return DefaultGroovyMethods.newInstance(strategyClass, new Object[]{classLoader});
             } else {
                 return strategyClass.getDeclaredConstructor().newInstance();
             }
@@ -275,17 +273,17 @@ public class LogASTTransformation extends AbstractASTTransformation implements C
         }
 
         protected ClassNode classNode(String name) {
-            ClassLoader cl = loader == null ? this.getClass().getClassLoader() : loader;
+            ClassLoader cl = loader != null ? loader : getClass().getClassLoader();
             try {
                 return ClassHelper.make(Class.forName(name, false, cl));
             } catch (ClassNotFoundException e) {
-                throw new GroovyRuntimeException("Unable to load logging class", e);
+                throw new GroovyRuntimeException("Unable to load class: " + name, e);
             }
         }
     }
 
     @Override
-    public void setCompilationUnit(final CompilationUnit unit) {
-        this.compilationUnit = unit;
+    public void setCompilationUnit(CompilationUnit compilationUnit) {
+        this.compilationUnit = compilationUnit;
     }
 }

[groovy] 02/04: GROOVY-10457: support `@CompileStatic` class with `@CompileDynamic` ctor

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit bb1789f8f35bc8199615e3238a413fa8cc2750c5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jan 21 13:45:48 2022 -0600

    GROOVY-10457: support `@CompileStatic` class with `@CompileDynamic` ctor
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
---
 .../transform/sc/StaticCompilationVisitor.java     |  58 +++++-----
 .../classgen/asm/sc/CompileDynamicTest.groovy      |  40 +++++--
 .../asm/sc/MixedModeStaticCompilationTest.groovy   |  14 +++
 .../asm/sc/StaticCompileConstructorsTest.groovy    | 126 +++++++++------------
 4 files changed, 131 insertions(+), 107 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index f78f1c3..2484e1c 100644
--- a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -192,38 +192,44 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         return false;
     }
 
-    /**
-     * 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 constructor, so it may fail if it encounters dynamic
-     * code here. Thus we make this kind of code fail
-     */
-    private void checkForConstructorWithCSButClassWithout(MethodNode node) {
-        if (!(node instanceof ConstructorNode)) return;
-        Object meta = node.getNodeMetaData(STATIC_COMPILE_NODE);
-        if (!Boolean.TRUE.equals(meta)) return;
-        ClassNode clz = typeCheckingContext.getEnclosingClassNode();
-        meta = clz.getNodeMetaData(STATIC_COMPILE_NODE);
-        if (Boolean.TRUE.equals(meta)) return;
-        if (    clz.getObjectInitializerStatements().isEmpty() &&
-                clz.getFields().isEmpty() &&
-                clz.getProperties().isEmpty())
-        {
-            return;
+    private void visitConstructorOrMethod(final MethodNode node) {
+        boolean isSkipped = isSkipMode(node); // @CompileDynamic
+        boolean isSC = !isSkipped && isStaticallyCompiled(node);
+        if (isSkipped) {
+            node.putNodeMetaData(STATIC_COMPILE_NODE, Boolean.FALSE);
         }
+        if (node instanceof ConstructorNode) {
+            super.visitConstructor((ConstructorNode) node);
+            ClassNode declaringClass = node.getDeclaringClass();
+            if (isSC && !isStaticallyCompiled(declaringClass)) {
+                // In a constructor that is statically compiled within 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 constructor, so it may fail if it encounters dynamic
+                // code here. Thus we make this kind of code fail.
+                if (!declaringClass.getFields().isEmpty()
+                        || !declaringClass.getProperties().isEmpty()
+                        || !declaringClass.getObjectInitializerStatements().isEmpty()) {
+                    addStaticTypeError("Cannot statically compile constructor implicitly including non-static elements from fields, properties or initializers", node);
+                }
+            }
+        } else {
+            super.visitMethod(node);
+        }
+        if (isSC) {
+            ClassNode declaringClass = node.getDeclaringClass();
+            addDynamicOuterClassAccessorsCallback(declaringClass);
+        }
+    }
 
-        addStaticTypeError("Cannot statically compile constructor implicitly including non static elements from object initializers, properties or fields.",node);
+    @Override
+    public void visitConstructor(final ConstructorNode node) {
+        visitConstructorOrMethod(node);
     }
 
     @Override
     public void visitMethod(final MethodNode node) {
-        if (isSkipMode(node)) {
-            node.putNodeMetaData(STATIC_COMPILE_NODE, false);
-        }
-        super.visitMethod(node);
-        checkForConstructorWithCSButClassWithout(node);
-        if (isStaticallyCompiled(node)) addDynamicOuterClassAccessorsCallback(node.getDeclaringClass());
+        visitConstructorOrMethod(node);
     }
 
     /**
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/CompileDynamicTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/CompileDynamicTest.groovy
index c6db3f6..22bdb30 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/CompileDynamicTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/CompileDynamicTest.groovy
@@ -19,21 +19,47 @@
 package org.codehaus.groovy.classgen.asm.sc
 
 import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
 
 /**
  * Test case for {@link groovy.transform.CompileDynamic}.
  */
-class CompileDynamicTest extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+final class CompileDynamicTest extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
 
-    void testCompileDynamic() {
-        assertScript '''import groovy.transform.CompileDynamic
-            class Foo {
+    @Override
+    protected void setUp() {
+        super.setUp()
+        def customizers = config.compilationCustomizers
+        // ASTTransformationCustomizer(CompileStatic) only uses visitMethod
+        customizers.removeAll { it instanceof ASTTransformationCustomizer }
+        customizers[0].addImports('groovy.transform.CompileDynamic', 'groovy.transform.CompileStatic')
+    }
+
+    void testCompileDynamicMethod() {
+        assertScript '''
+            @CompileStatic
+            class C {
+                @CompileDynamic
+                void skip() {
+                    int i = 'cannot assign string to int'
+                }
+            }
+            new C()
+        '''
+    }
+
+    // GROOVY-10457
+    void testCompileDynamicConstructor() {
+        assertScript '''
+            @CompileStatic
+            class C {
                 @CompileDynamic
-                void skipped() {
-                    int i = 'should not pass'
+                C() {
+                    String result = new StringReader('works').text
+                    assert result == 'works'
                 }
             }
-            new Foo()
+            new C()
         '''
     }
 }
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 395e682..36b9a9f 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/MixedModeStaticCompilationTest.groovy
@@ -292,6 +292,20 @@ class MixedModeStaticCompilationTest extends StaticTypeCheckingTestCase implemen
 
     }
 
+    void testDynamicClassWithStaticConstructorAndInitialization() {
+        shouldFailWithMessages '''
+            class A {
+            }
+            class B {
+                A a = new A() // may require dynamic support...
+                @groovy.transform.CompileStatic
+                B() {
+                }
+            }
+        ''',
+        'Cannot statically compile constructor implicitly including non-static elements from fields, properties or initializers'
+    }
+
     void testSCClosureCanAccessPrivateFieldsOfNonSCEnclosingClass() {
         assertScript '''
             class Test {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileConstructorsTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileConstructorsTest.groovy
index e44cec6..dce86d3 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileConstructorsTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileConstructorsTest.groovy
@@ -26,95 +26,73 @@ import groovy.transform.stc.ConstructorsSTCTest
 class StaticCompileConstructorsTest extends ConstructorsSTCTest implements StaticCompilationTestSupport {
 
     void testMapConstructorError() {
-        assertScript '''import groovy.transform.Canonical
-
-        class WTF {
-            public static void main(String[] args) {
-                new Person(name:"First")
-                first(new Person(name:"First"))
+        assertScript '''
+            class C {
+                static void test() {
+                    new Person(name:"First")
+                    first(new Person(name:"First"))
+                }
+                static Person first(Person p) {
+                    p
+                }
             }
-
-            static Person first(Person p) {
-                p
+            @groovy.transform.Canonical
+            class Person {
+                String name
             }
 
-        }
-
-        @Canonical
-        class Person {
-            String name
-        }
-        WTF.main()
+            C.test()
         '''
     }
-    
-    void testMixedDynamicStaticConstructor() {
-        shouldFailWithMessages("""
-            class A{}
-            class B {
-                A a = new A();
-                @groovy.transform.CompileStatic
-                B(){}
-            }
-        """, "Cannot statically compile constructor implicitly including non static elements from object initializers, properties or fields")
-    }
 
     void testPrivateConstructorFromClosure() {
-        try {
-            assertScript '''
-                class Foo {
-                    String s
-                    private Foo(String s) { this.s = s }
-                    static Foo makeFoo(String s) {
-                        def cl = { new Foo(s) }
-                        cl()
-                    }
+        assertScript '''
+            class C {
+                String s
+                private C(String s) {
+                    this.s = s
+                }
+                static C make(String s) {
+                    def cl = { new C(s) }
+                    cl()
                 }
-                assert Foo.makeFoo('pls').s == 'pls'
-            '''
-        } finally {
-            //println astTrees
-        }
+            }
+            assert C.make('pls').s == 'pls'
+        '''
     }
 
     void testPrivateConstructorFromNestedClass() {
-        try {
-            assertScript '''
-                class Foo {
-                    String s
-                    private Foo(String s) { this.s = s }
-                    static class Bar {
-                        static Foo makeFoo(String s) { new Foo(s) }
-                    }
-
+        assertScript '''
+            class Foo {
+                String s
+                private Foo(String s) {
+                    this.s = s
+                }
+                static class Bar {
+                    static Foo makeFoo(String s) { new Foo(s) }
                 }
-                assert Foo.Bar.makeFoo('pls').s == 'pls'
-            '''
-        } finally {
-            //println astTrees
-        }
+
+            }
+            assert Foo.Bar.makeFoo('pls').s == 'pls'
+        '''
     }
 
     void testPrivateConstructorFromAIC() {
-        try {
-            assertScript '''
-                class Foo {
-                    String s
-                    private Foo(String s) { this.s = s }
-                    static Foo makeFoo(String s) {
-                        return new Object() {
-                            Foo makeFoo(String x) {
-                                new Foo(x)
-                            }
-                        }.makeFoo(s)
-                    }
+        assertScript '''
+            class Foo {
+                String s
+                private Foo(String s) {
+                    this.s = s
                 }
-                assert Foo.makeFoo('pls').s == 'pls'
-            '''
-        } finally {
-            //println astTrees
-        }
+                static Foo makeFoo(String s) {
+                    new Object() {
+                        Foo makeFoo(String x) {
+                            new Foo(x)
+                        }
+                    }.makeFoo(s)
+                }
+            }
+            assert Foo.makeFoo('pls').s == 'pls'
+        '''
     }
-
 }
-

[groovy] 01/04: GROOVY-10352: class model: load anno enum value as property expression

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 40b49a8b100d730844d11471a0c5b2ec6c14d288
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Feb 3 12:59:42 2022 -0600

    GROOVY-10352: class model: load anno enum value as property expression
---
 src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java b/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java
index 70d487c..7ecd263 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java
@@ -301,14 +301,16 @@ public class Java5 implements VMPlugin {
             return new ConstantExpression(value);
 
         if (value instanceof Class)
-            return new ClassExpression(ClassHelper.makeWithoutCaching((Class)value));
+            return new ClassExpression(ClassHelper.makeWithoutCaching((Class<?>)value));
+
+        if (value instanceof Enum )
+            return new PropertyExpression(new ClassExpression(ClassHelper.makeWithoutCaching(value.getClass())), value.toString());
 
         if (value.getClass().isArray()) {
-            ListExpression elementExprs = new ListExpression();
-            int len = Array.getLength(value);
-            for (int i = 0; i != len; ++i)
-                elementExprs.addExpression(annotationValueToExpression(Array.get(value, i)));
-            return elementExprs;
+            ListExpression values = new ListExpression();
+            for (int i = 0, n = Array.getLength(value); i < n; i += 1)
+                values.addExpression(annotationValueToExpression(Array.get(value, i)));
+            return values;
         }
 
         return null;

[groovy] 03/04: GROOVY-7033: visit AIC's field, method, and parameter annotations

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit cb33448d7ccee91c80d24dd1e0489985a3c4c80f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jan 20 15:51:56 2022 -0600

    GROOVY-7033: visit AIC's field, method, and parameter annotations
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
---
 .../groovy/classgen/VariableScopeVisitor.java       | 21 +++++++++------------
 src/test/gls/annotations/AnnotationTest.groovy      | 17 +++++++++++++++++
 .../closures/AnnotationClosureTest.groovy           | 16 +++++++---------
 3 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index f6afa6a..0dea9d0 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -558,28 +558,25 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
         currentScope.setClassScope(innerClass);
         currentScope.setInStaticContext(false);
         for (MethodNode method : innerClass.getMethods()) {
+            visitAnnotations(method); // GROOVY-7033
             Parameter[] parameters = method.getParameters();
-            if (parameters.length == 0)
-                parameters = null; // null means no implicit "it"
+            for (Parameter p : parameters) visitAnnotations(p); // GROOVY-7033
+            if (parameters.length == 0) parameters = null; // disable implicit "it"
             ClosureExpression cl = new ClosureExpression(parameters, method.getCode());
             visitClosureExpression(cl);
         }
-
         for (FieldNode field : innerClass.getFields()) {
+            visitAnnotations(field); // GROOVY-7033
             Expression expression = field.getInitialExpression();
-            pushState(field.isStatic());
-            if (expression != null) {
-                if (expression.isSynthetic() && expression instanceof VariableExpression &&
-                        ((VariableExpression) expression).getAccessedVariable() instanceof Parameter) {
+            if (expression != null
                     // GROOVY-6834: accessing a parameter which is not yet seen in scope
-                    popState();
-                    continue;
-                }
+                    && !(expression.isSynthetic() && expression instanceof VariableExpression
+                        && ((VariableExpression) expression).getAccessedVariable() instanceof Parameter)) {
+                pushState(field.isStatic());
                 expression.visit(this);
+                popState();
             }
-            popState();
         }
-
         for (Statement statement : innerClass.getObjectInitializerStatements()) {
             statement.visit(this);
         }
diff --git a/src/test/gls/annotations/AnnotationTest.groovy b/src/test/gls/annotations/AnnotationTest.groovy
index 796e8f1..e692755 100644
--- a/src/test/gls/annotations/AnnotationTest.groovy
+++ b/src/test/gls/annotations/AnnotationTest.groovy
@@ -760,6 +760,23 @@ class AnnotationTest extends CompilableTestSupport {
         '''
     }
 
+    // GROOVY-7033
+    void testClassLiteralsRecognizedForAnonymousInnerClassAnnotationUsage() {
+        shouldCompile '''
+            @interface A {
+                Class value()
+            }
+
+            def obj = new Object() {
+                @A(String) def field
+                @A(String) @Override
+                boolean equals(@A(String) param) {
+                    def type = String
+                }
+            }
+        '''
+    }
+
     void testVariableExpressionsReferencingConstantsSeenForAnnotationAttributes() {
         shouldCompile '''
             class C {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureTest.groovy b/src/test/gls/annotations/closures/AnnotationClosureTest.groovy
index 08a36dc..6672762 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureTest.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureTest.groovy
@@ -19,17 +19,16 @@
 package gls.annotations.closures
 
 import gls.CompilableTestSupport
-import groovy.transform.NotYetImplemented
 
-import java.lang.annotation.RetentionPolicy
 import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
 import java.lang.reflect.Modifier
 
 class AnnotationClosureTest extends CompilableTestSupport {
     def answer = new Object() {
         def answer() { 42 }
     }
-    
+
     void testGep3InClosure() {
         shouldCompile """
             @interface Bar{Class value();}
@@ -146,10 +145,9 @@ import java.lang.annotation.*
 class Foo {}
         """
     }
-    
-    @NotYetImplemented
+
     void testAnnotationOnAnonymousMethod() {
-        shouldCompile """        
+        shouldCompile '''
             import java.lang.annotation.*
 
             @Retention(RetentionPolicy.RUNTIME)
@@ -157,10 +155,10 @@ class Foo {}
             @interface Bar{Class value();}
 
             return new Object() {
-              @Bar({})
-              String toString() {}
+                @Bar({})
+                String toString() {}
             }
-"""
+        '''
     }
 }