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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4a8e0eec27 GROOVY-11237: additional interface modifier checks
4a8e0eec27 is described below

commit 4a8e0eec270fcc860a7df4650b261ebe092d9b88
Author: Eric Milles <[email protected]>
AuthorDate: Thu Dec 7 10:46:07 2023 -0600

    GROOVY-11237: additional interface modifier checks
---
 .../groovy/classgen/ClassCompletionVerifier.java   |  24 ++--
 src/spec/test/ClassTest.groovy                     |  23 +---
 .../groovy/AbstractClassAndInterfaceTest.groovy    | 141 ++++++++++-----------
 src/test/groovy/InterfaceTest.groovy               |  17 ++-
 .../classgen/ClassCompletionVerifierTest.java      | 131 ++++++++-----------
 .../codehaus/groovy/classgen/InterfaceTest.groovy  |   4 +-
 6 files changed, 150 insertions(+), 190 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java 
b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index edf355f2e6..870704af79 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -189,14 +189,11 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
         for (MethodNode method : node.getMethods()) {
             if (!method.isPublic()) {
                 if (method.isAbstract()) {
-                    addError("Method '" + method.getName() + "' from " + 
getDescription(node) +
-                        " must be public as it is declared as an abstract 
method.", method);
+                    addError("The method '" + method.getName() + "' must be 
public as it is declared abstract in " + getDescription(node) + ".", method);
                 } else if (!method.isPrivate() && 
!method.isStaticConstructor()) {
-                    // normal parsing won't get here since ASTBuilder only 
lets through default and private,
-                    // but we'll do a check in case any AST transforms have 
created dodgy method definitions
-                    addError("Method '" + method.getName() + "' is " +
-                        (method.isProtected() ? "protected" : 
"package-private") +
-                        " but should be public or private in " + 
getDescription(node) + ".", method);
+                    // normal parsing blocks non-static protected or 
@PackageScope
+                    addError("The method '" + method.getName() + "' is " + 
(method.isProtected() ? "protected" : "package-private") +
+                            " but must be " + (method.isStatic() ? "public" : 
"default") + " or private in " + getDescription(node) + ".", method);
                 }
             }
         }
@@ -207,8 +204,7 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
         if (!node.isAbstract() || node.isInterface()) return;
         for (MethodNode method : node.getAbstractMethods()) {
             if (method.isPrivate()) {
-                addError("Method '" + method.getName() + "' from " + 
getDescription(node) +
-                        " must not be private as it is declared as an abstract 
method.", method);
+                addError("The method '" + method.getName() + "' must not be 
private as it is declared abstract in " + getDescription(node) + ".", method);
             }
         }
     }
@@ -297,7 +293,8 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
     }
 
     private static String getDescription(final ClassNode node) {
-        return (node.isInterface() ? (Traits.isTrait(node) ? "trait" : 
"interface") : "class") + " '" + node.getName() + "'";
+        String kind = (node.isInterface() ? (Traits.isTrait(node) ? "trait" : 
"interface") : (node.isEnum() ? "enum" : "class"));
+        return kind + " '" + node.getName() + "'";
     }
 
     private static String getDescription(final MethodNode node) {
@@ -616,11 +613,8 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
     }
 
     private void checkInterfaceFieldModifiers(final FieldNode node) {
-        if (!currentClass.isInterface()) return;
-        if ((node.getModifiers() & (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) == 0 
||
-                (node.getModifiers() & (ACC_PRIVATE | ACC_PROTECTED)) != 0) {
-            addError("The " + getDescription(node) + " is not 'public static 
final' but is defined in " +
-                    getDescription(currentClass) + ".", node);
+        if (currentClass.isInterface() && !(node.isPublic() && node.isStatic() 
&& node.isFinal())) {
+            addError("The " + getDescription(node) + " is not 'public static 
final' but is defined in " + getDescription(currentClass) + ".", node);
         }
     }
 
diff --git a/src/spec/test/ClassTest.groovy b/src/spec/test/ClassTest.groovy
index 79c1541428..543025a928 100644
--- a/src/spec/test/ClassTest.groovy
+++ b/src/spec/test/ClassTest.groovy
@@ -1,5 +1,3 @@
-import groovy.test.GroovyTestCase
-
 /*
  *  Licensed to the Apache Software Foundation (ASF) under one
  *  or more contributor license agreements.  See the NOTICE file
@@ -18,7 +16,10 @@ import groovy.test.GroovyTestCase
  *  specific language governing permissions and limitations
  *  under the License.
  */
-class ClassTest extends GroovyTestCase {
+
+import groovy.test.GroovyTestCase
+
+final class ClassTest extends GroovyTestCase {
 
     void testClassDefinition() {
         assertScript '''
@@ -225,21 +226,11 @@ class ClassTest extends GroovyTestCase {
         def err = shouldFail '''
             // tag::protected_forbidden[]
             interface Greeter {
-                protected void greet(String name)           // <1>
+                protected void greet(String name)                       // <1>
             }
             // end::protected_forbidden[]
         '''
-        assert err.contains("Method 'greet' from interface 'Greeter' must be 
public as it is declared as an abstract method.")
-/*
-        err = shouldFail '''import groovy.transform.*
-            // tag::package_private_forbidden[]
-            interface Greeter {
-                @PackageScope void greet(String name)
-            }
-            // end::package_private_forbidden[]
-        '''
-        assert err.contains("Method 'greet' is package-private but should be 
public or private in interface 'Greeter'")
-*/
+        assert err.contains("The method 'greet' must be public as it is 
declared abstract in interface 'Greeter'")
     }
 
     void testFields() {
@@ -508,8 +499,6 @@ class ClassTest extends GroovyTestCase {
             }
             // end::annotation_value_set_option[]
         '''
-
-
     }
 
     void testAnnotationTarget() {
diff --git a/src/test/groovy/AbstractClassAndInterfaceTest.groovy 
b/src/test/groovy/AbstractClassAndInterfaceTest.groovy
index ad8ef85fc9..21b15a75e4 100644
--- a/src/test/groovy/AbstractClassAndInterfaceTest.groovy
+++ b/src/test/groovy/AbstractClassAndInterfaceTest.groovy
@@ -20,11 +20,11 @@ package groovy
 
 import gls.CompilableTestSupport
 
-class AbstractClassAndInterfaceTest extends CompilableTestSupport {
+final class AbstractClassAndInterfaceTest extends CompilableTestSupport {
 
     void testInterface() {
         def shell = new GroovyShell()
-        def text = """
+        def text = '''
             interface A {
                 void methodOne(Object o)
                 Object methodTwo()
@@ -41,13 +41,13 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
 
             def b = new B()
             return b.methodTwo()
-            """
+        '''
         def retVal = shell.evaluate(text)
         assert retVal.class == Object
     }
 
     void testClassImplementingAnInterfaceButMissesMethod() {
-        shouldNotCompile """
+        shouldNotCompile '''
             interface A {
                 void methodOne(Object o)
                 Object methodTwo()
@@ -57,11 +57,11 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
                 void methodOne(Object o){assert true}
             }
 
-            def b = new B();
+            def b = new B()
             return b.methodTwo()
-            """
+        '''
 
-        shouldNotCompile """
+        shouldNotCompile '''
             interface A {
                 Object methodTwo()
             }
@@ -73,25 +73,25 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
                 void methodOne(Object o){assert true}
             }
 
-            def b = new C();
+            def b = new C()
             return b.methodTwo()
-            """
+        '''
     }
 
     void 
testClassImplementingNestedInterfaceShouldContainMethodsFromSuperInterfaces() {
-        shouldNotCompile """
+        shouldNotCompile '''
             interface A { def a() }
             interface B extends A { def b() }
             class BImpl implements B {
                 def b(){ println 'foo' }
             }
             new BImpl().b()
-            """
+        '''
     }
 
     void testAbstractClass() {
         def shell = new GroovyShell()
-        def text = """
+        def text = '''
             abstract class A {
                 abstract void methodOne(Object o)
                 Object methodTwo(){
@@ -107,13 +107,13 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
 
             def b = new B()
             return b.methodTwo()
-            """
+        '''
         def retVal = shell.evaluate(text)
         assert retVal.class == Object
     }
 
     void testClassExtendingAnAbstractClassButMissesMethod() {
-        shouldNotCompile """
+        shouldNotCompile '''
             abstract class A {
                 abstract void methodOne(Object o)
                 Object methodTwo(){
@@ -130,11 +130,11 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
 
             class C extends B{}
 
-            def b = new C();
+            def b = new C()
             return b.methodTwo()
-            """
+        '''
 
-       shouldNotCompile """
+       shouldNotCompile '''
             abstract class A {
                 abstract void methodOne(Object o)
                 Object methodTwo(){
@@ -149,14 +149,14 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
                 void methodOne(Object o){assert true}
             }
 
-            def b = new B();
+            def b = new B()
             return b.methodTwo()
-            """
+        '''
     }
 
     void testInterfaceAbstractClassCombination() {
         def shell = new GroovyShell()
-        def text = """
+        def text = '''
             interface A {
                 void methodOne()
             }
@@ -173,10 +173,10 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
             }
             def c = new C()
             c.methodTwo()
-            """
+        '''
         shell.evaluate(text)
 
-        shouldNotCompile """
+        shouldNotCompile '''
             interface A {
                 void methodOne()
             }
@@ -188,12 +188,12 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
             class C extends B {}
             def c = new c()
             c.methodTwo()
-            """
+        '''
     }
 
     void testDefaultModifiersForInterfaces() {
         def shell = new GroovyShell()
-        def text = """
+        def text = '''
             import java.lang.reflect.Modifier
 
             interface A {
@@ -202,17 +202,17 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
 
             def fields = A.class.declaredFields
             assert fields.length==1
-            assert fields[0].name == "foo"
+            assert fields[0].name == 'foo'
             assert Modifier.isPublic (fields[0].modifiers)
             assert Modifier.isStatic (fields[0].modifiers)
             assert Modifier.isFinal  (fields[0].modifiers)
-            """
+        '''
         shell.evaluate(text)
     }
 
     void testAccessToInterfaceField() {
         def shell = new GroovyShell()
-        def text = """
+        def text = '''
             interface A {
                 def foo=1
             }
@@ -220,90 +220,87 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
               def foo(){foo}
             }
             assert new B().foo()==1
-       """
+       '''
        shell.evaluate(text)
     }
 
     void testImplementsDuplicateInterface() {
-        shouldCompile """
-        interface I {}
-        class C implements I {}
-        """
-        shouldNotCompile """
-        interface I {}
-        class C implements I, I {}
-        """
+        shouldCompile '''
+            interface I {}
+            class C implements I {}
+        '''
+        shouldNotCompile '''
+            interface I {}
+            class C implements I, I {}
+        '''
     }
 
     void testDefaultMethodParamsNotAllowedInInterface() {
-        shouldCompile """
-        interface Foo {
-           def doit( String param, int o )
-        }
-        """
-        shouldNotCompile """
-        interface Foo {
-           def doit( String param = "Groovy", int o )
-        }
-        """
+        shouldCompile '''
+            interface Foo {
+                def doit(String string, int i)
+            }
+        '''
+        shouldNotCompile '''
+            interface Foo {
+                def doit(String string = 'Groovy', int i)
+            }
+        '''
     }
 
     void testClassImplementsItselfCreatingACycle() {
-        def scriptStr = """
+        shouldNotCompile '''
             package p1
             class XXX implements XXX {}
-        """
-        shouldNotCompile scriptStr
-
-        scriptStr = """
+        '''
+        shouldNotCompile '''
             class YYY implements YYY {}
-        """
-        shouldNotCompile scriptStr
+        '''
     }
 
     void testAbstractClassWithPrivateAbstractMethod() {
-        def msg = shouldNotCompile """
+        def msg = shouldNotCompile '''
             abstract class X {
                 private abstract void y()
             }
-        """
-        assert msg.contains("Method 'y' from class 'X' must not be private as 
it is declared as an abstract method.")
+        '''
+        assert msg.contains("The method 'y' must not be private as it is 
declared abstract in class 'X'")
     }
 
     void testAbstractClassWithPrivateAbstractMethods() {
-        def msg = shouldNotCompile """
+        def msg = shouldNotCompile '''
             abstract class X {
                 private abstract void y()
                 private abstract void z()
             }
-        """
-        assert msg.contains("Method 'y' from class 'X' must not be private as 
it is declared as an abstract method.")
-        assert msg.contains("Method 'z' from class 'X' must not be private as 
it is declared as an abstract method.")
+        '''
+        assert msg.contains("The method 'y' must not be private as it is 
declared abstract in class 'X'")
+        assert msg.contains("The method 'z' must not be private as it is 
declared abstract in class 'X'")
     }
 
     void testAbstractNestedClassWithPrivateAbstractMethod() {
-        def msg = shouldNotCompile """
+        def msg = shouldNotCompile '''
             class Z {
                 abstract class X {
                     private abstract void y()
                 }
             }
-        """
-        assert msg.contains("Method 'y' from class 'Z\$X' must not be private 
as it is declared as an abstract method.")
+        '''
+        assert msg.contains("The method 'y' must not be private as it is 
declared abstract in class 'Z\$X'")
     }
 
     void testClassWithPrivateAbstractMethod() {
-        def msg = shouldNotCompile """
+        def msg = shouldNotCompile '''
             class X {
                 private abstract void y()
             }
-        """
-        assert !msg.contains("Method 'y' from class 'X' must not be private as 
it is declared as an abstract method.")
+        '''
+        assert !msg.contains("The method 'y' must not be private as it is 
declared abstract in class 'X'")
         assert msg.contains("Can't have an abstract method in a non-abstract 
class. The class 'X' must be declared abstract or the method 'void y()' must be 
implemented.")
     }
 
     void testEnumWithPrivateAbstractMethod() {
-        def msg = shouldNotCompile """
+        def msg = shouldNotCompile '''
             enum X {
                 CONST {
                     private void y() { }
@@ -311,16 +308,16 @@ class AbstractClassAndInterfaceTest extends 
CompilableTestSupport {
 
                 private abstract void y()
             }
-        """
-        assert msg.contains("Method 'y' from class 'X' must not be private as 
it is declared as an abstract method.")
+        '''
+        assert msg.contains("The method 'y' must not be private as it is 
declared abstract in enum 'X'")
     }
 
     void testInterfaceWithPrivateAbstractMethod() {
-        def msg = shouldNotCompile """
+        def msg = shouldNotCompile '''
             interface X {
                 private abstract void y()
             }
-        """
-        assert msg.contains("Method 'y' from interface 'X' must be public as 
it is declared as an abstract method.")
+        '''
+        assert msg.contains("The method 'y' must be public as it is declared 
abstract in interface 'X'")
     }
 }
diff --git a/src/test/groovy/InterfaceTest.groovy 
b/src/test/groovy/InterfaceTest.groovy
index 28620aafc7..b802a11370 100644
--- a/src/test/groovy/InterfaceTest.groovy
+++ b/src/test/groovy/InterfaceTest.groovy
@@ -61,9 +61,9 @@ final class InterfaceTest extends CompilableTestSupport {
     void testPrivateInterfaceMethod() {
         assertScript '''
             interface Foo {
-                default foo() { Foo.this.hello 'Foo#foo' }
+                default foo() { Foo.this.hello('Foo#foo') }
                 @groovy.transform.CompileStatic
-                default baz() { hello 'Foo#baz' }
+                default baz() { hello('Foo#baz') }
                 private hello(where) { "hello from $where"}
             }
 
@@ -93,24 +93,23 @@ final class InterfaceTest extends CompilableTestSupport {
     }
 
     // GROOVY-11237
-    void testStaticInterfaceMethod() {
-        assertScript '''
-            import static groovy.test.GroovyAssert.shouldFail
-
+    void testPublicStaticInterfaceMethod() {
+        assertScript '''import static groovy.test.GroovyAssert.shouldFail
             interface Foo {
                 static hello(where) { "hello $where" }
                 static String BAR = 'bar'
-                String BAA = 'baa' // implicit static
+                       String BAZ = 'baz' // implicit static
             }
 
             assert Foo.hello('world') == 'hello world'
             assert Foo.BAR == 'bar'
-            assert Foo.BAA == 'baa'
+            assert Foo.BAZ == 'baz'
+
             shouldFail(MissingMethodException) {
                 Foo.getBAR()
             }
             shouldFail(MissingMethodException) {
-                Foo.getBAA()
+                Foo.getBAZ()
             }
         '''
     }
diff --git 
a/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java 
b/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
index 758bb292ca..24be768e9d 100644
--- a/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
+++ b/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
@@ -28,70 +28,43 @@ import org.codehaus.groovy.control.SourceUnit;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
-public class ClassCompletionVerifierTest extends TestSupport {
+import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+
+public final class ClassCompletionVerifierTest extends TestSupport {
+
     private SourceUnit source;
     private ClassCompletionVerifier verifier;
-    private static final String ABSTRACT_FINAL_CLASS = "AbstractFinalClass";
-    private static final String FINAL_INTERFACE = "FinalInterface";
-    private static final String EXPECTED_CLASS_MODIFIER_ERROR_MESSAGE =
-            "The class '" + ABSTRACT_FINAL_CLASS + "' must not be both final 
and abstract.";
-    private static final String EXPECTED_INTERFACE_MODIFIER_ERROR_MESSAGE =
-            "The interface '" + FINAL_INTERFACE + "' must not be final. It is 
by definition abstract.";
-    private static final String EXPECTED_INTERFACE_FINAL_METHOD_ERROR_MESSAGE =
-            "The method 'java.lang.Object xxx()' from interface 'zzz' must not 
be final. It is by definition abstract.";
-    private static final String EXPECTED_TRANSIENT_CLASS_ERROR_MESSAGE =
-            "The class 'DodgyClass' has an incorrect modifier transient.";
-    /* can't check synchronized here as it doubles up with ACC_SUPER
-    private static final String EXPECTED_SYNCHRONIZED_CLASS_ERROR_MESSAGE =
-            "The class 'DodgyClass' has an incorrect modifier synchronized.";
-    */
-    private static final String EXPECTED_NATIVE_CLASS_ERROR_MESSAGE =
-            "The class 'DodgyClass' has an incorrect modifier native.";
-    private static final String EXPECTED_VOLATILE_CLASS_ERROR_MESSAGE =
-            "The class 'DodgyClass' has an incorrect modifier volatile.";
-    private static final String EXPECTED_DUPLICATE_METHOD_ERROR_CLASS_MESSAGE =
-            "Repetitive method name/signature for method 'java.lang.Object 
xxx()' in class 'zzz'.";
-    private static final String 
EXPECTED_DUPLICATE_METHOD_ERROR_INTERFACE_MESSAGE =
-            "Repetitive method name/signature for method 'java.lang.Object 
xxx(java.lang.String)' in interface 'zzz'.";
-    /* can't check volatile here as it doubles up with bridge
-    private static final String EXPECTED_VOLATILE_METHOD_ERROR_MESSAGE =
-            "The method 'java.lang.Object vo()' has an incorrect modifier 
volatile.";
-    */
-    private static final String EXPECTED_TRANSIENT_METHOD_ERROR_MESSAGE =
-            "The method 'java.lang.Object tr()' has an incorrect modifier 
transient.";
-    private static final String EXPECTED_ABSTRACT_PRIVATE_METHOD_ERROR_MESSAGE 
=
-            "Method 'y' from class 'X' must not be private as it is declared 
as an abstract method.";
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         source = SourceUnit.create("dummy.groovy", "");
         verifier = new ClassCompletionVerifier(source);
     }
 
-    public void testDetectsAbstractPrivateMethod() throws Exception {
+    public void testDetectsAbstractPrivateMethod() {
         ClassNode node = new ClassNode("X", ACC_ABSTRACT, 
ClassHelper.OBJECT_TYPE);
         node.addMethod(new MethodNode("y", ACC_PRIVATE | ACC_ABSTRACT, 
ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
         verifier.visitClass(node);
-        checkErrorMessage(EXPECTED_ABSTRACT_PRIVATE_METHOD_ERROR_MESSAGE);
+        checkErrorMessage("The method 'y' must not be private as it is 
declared abstract in class 'X'.");
     }
 
-    public void testDetectsFinalAbstractClass() throws Exception {
+    public void testDetectsFinalAbstractClass() {
         checkVisitErrors("FinalClass", ACC_FINAL, false);
         checkVisitErrors("AbstractClass", ACC_ABSTRACT, false);
-        checkVisitErrors(ABSTRACT_FINAL_CLASS, ACC_ABSTRACT | ACC_FINAL, true);
-        checkErrorMessage(EXPECTED_CLASS_MODIFIER_ERROR_MESSAGE);
+        checkVisitErrors("AbstractFinalClass", ACC_ABSTRACT | ACC_FINAL, true);
+        checkErrorMessage("The class 'AbstractFinalClass' must not be both 
final and abstract.");
     }
 
-    public void testDetectsDuplicateMethodsForClassNoParams() throws Exception 
{
-        checkDetectsDuplicateMethods(0, 
EXPECTED_DUPLICATE_METHOD_ERROR_CLASS_MESSAGE, Parameter.EMPTY_ARRAY);
+    public void testDetectsDuplicateMethodsForClassNoParams() {
+        checkDetectsDuplicateMethods(ACC_ABSTRACT, "Repetitive method 
name/signature for method 'java.lang.Object xxx()' in class 'zzz'.");
     }
 
-    public void testDetectsDuplicateMethodsForInterfaceOneParam() throws 
Exception {
-        Parameter[] stringParam = {new Parameter(ClassHelper.STRING_TYPE, 
"x")};
-        checkDetectsDuplicateMethods(ACC_INTERFACE, 
EXPECTED_DUPLICATE_METHOD_ERROR_INTERFACE_MESSAGE, stringParam);
+    public void testDetectsDuplicateMethodsForInterfaceOneParam() {
+        checkDetectsDuplicateMethods(ACC_INTERFACE, "Repetitive method 
name/signature for method 'java.lang.Object xxx(java.lang.String)' in interface 
'zzz'.", new Parameter(ClassHelper.STRING_TYPE, "x"));
     }
 
-    private void checkDetectsDuplicateMethods(int modifiers, String 
expectedErrorMessage, Parameter[] params) {
+    private void checkDetectsDuplicateMethods(int modifiers, String 
expectedErrorMessage, Parameter... params) {
         ClassNode node = new ClassNode("zzz", modifiers, 
ClassHelper.OBJECT_TYPE);
         node.addMethod(new MethodNode("xxx", ACC_PUBLIC, 
ClassHelper.OBJECT_TYPE, params, ClassNode.EMPTY_ARRAY, null));
         node.addMethod(new MethodNode("xxx", ACC_PUBLIC, 
ClassHelper.OBJECT_TYPE, params, ClassNode.EMPTY_ARRAY, null));
@@ -100,60 +73,68 @@ public class ClassCompletionVerifierTest extends 
TestSupport {
         checkErrorMessage(expectedErrorMessage);
     }
 
-    public void testDetectsIncorrectOtherModifier() throws Exception {
+    public void testDetectsIncorrectOtherModifier() {
         // can't check synchronized here as it doubles up with ACC_SUPER
         checkVisitErrors("DodgyClass", ACC_TRANSIENT | ACC_VOLATILE | 
ACC_NATIVE, true);
-        checkErrorMessage(EXPECTED_TRANSIENT_CLASS_ERROR_MESSAGE);
-        checkErrorMessage(EXPECTED_VOLATILE_CLASS_ERROR_MESSAGE);
-        checkErrorMessage(EXPECTED_NATIVE_CLASS_ERROR_MESSAGE);
+        checkErrorMessage("The class 'DodgyClass' has an incorrect modifier 
transient.");
+        checkErrorMessage("The class 'DodgyClass' has an incorrect modifier 
volatile.");
+        checkErrorMessage("The class 'DodgyClass' has an incorrect modifier 
native.");
     }
 
-    public void testDetectsFinalAbstractInterface() throws Exception {
-        checkVisitErrors(FINAL_INTERFACE, ACC_ABSTRACT | ACC_FINAL | 
ACC_INTERFACE, true);
-        checkErrorMessage(EXPECTED_INTERFACE_MODIFIER_ERROR_MESSAGE);
+    public void testDetectsFinalAbstractInterface() {
+        checkVisitErrors("FinalInterface", ACC_ABSTRACT | ACC_FINAL | 
ACC_INTERFACE, true);
+        checkErrorMessage("The interface 'FinalInterface' must not be final. 
It is by definition abstract.");
     }
 
-    public void testDetectsFinalMethodsInInterface() throws Exception {
+    public void testDetectsFinalMethodsInInterface() {
         ClassNode node = new ClassNode("zzz", ACC_ABSTRACT | ACC_INTERFACE, 
ClassHelper.OBJECT_TYPE);
         node.addMethod(new MethodNode("xxx", ACC_PUBLIC | ACC_FINAL, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
         addDummyConstructor(node);
         verifier.visitClass(node);
         checkErrorCount(1);
-        checkErrorMessage(EXPECTED_INTERFACE_FINAL_METHOD_ERROR_MESSAGE);
+        checkErrorMessage("The method 'java.lang.Object xxx()' from interface 
'zzz' must not be final. It is by definition abstract.");
     }
 
-    public void testDetectsIncorrectMethodModifiersInInterface() throws 
Exception {
-        // can't check volatile here as it doubles up with bridge
+    public void testDetectsIncorrectMethodModifiersInInterface() {
         ClassNode node = new ClassNode("zzz", ACC_ABSTRACT | ACC_INTERFACE, 
ClassHelper.OBJECT_TYPE);
-        node.addMethod(new MethodNode("st", ACC_PUBLIC | ACC_STRICT, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
-        node.addMethod(new MethodNode("na", ACC_PUBLIC | ACC_NATIVE, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
-        node.addMethod(new MethodNode("sy", ACC_PUBLIC | ACC_SYNCHRONIZED, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
-        node.addMethod(new MethodNode("tr", ACC_PUBLIC | ACC_TRANSIENT, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("st", ACC_PUBLIC | ACC_STRICT       , 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("na", ACC_PUBLIC | ACC_NATIVE       , 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("sy", ACC_PUBLIC | ACC_SYNCHRONIZED , 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("tr", ACC_PUBLIC | ACC_TRANSIENT    , 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        // can't check volatile here as it doubles up with bridge
         addDummyConstructor(node);
         verifier.visitClass(node);
         checkErrorCount(4);
         checkErrorMessage("The method 'java.lang.Object st()' has an incorrect 
modifier strictfp.");
         checkErrorMessage("The method 'java.lang.Object na()' has an incorrect 
modifier native.");
         checkErrorMessage("The method 'java.lang.Object sy()' has an incorrect 
modifier synchronized.");
-        checkErrorMessage(EXPECTED_TRANSIENT_METHOD_ERROR_MESSAGE);
+        checkErrorMessage("The method 'java.lang.Object tr()' has an incorrect 
modifier transient.");
     }
 
-    public void testDetectsIncorrectMemberVisibilityInInterface() throws 
Exception {
+    public void testDetectsIncorrectMemberVisibilityInInterface() {
         ClassNode node = new ClassNode("zzz", ACC_ABSTRACT | ACC_INTERFACE, 
ClassHelper.OBJECT_TYPE);
-        node.addMethod(new MethodNode("prom", ACC_PROTECTED, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
-        node.addMethod(new MethodNode("ppm", 0, ClassHelper.OBJECT_TYPE, 
Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
-        node.addField("prif", ACC_PRIVATE, ClassHelper.OBJECT_TYPE, null);
+        node.addMethod(new MethodNode("pro1", ACC_ABSTRACT | ACC_PROTECTED, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("pro2", ACC_STATIC   | ACC_PROTECTED, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("pro3",                ACC_PROTECTED, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, 
block()));
+        node.addMethod(new MethodNode("pp_1", ACC_ABSTRACT                , 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("pp_2", ACC_STATIC                  , 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
         node.addField("prof", ACC_PROTECTED, ClassHelper.OBJECT_TYPE, null);
+        node.addField("prif", ACC_PRIVATE  , ClassHelper.OBJECT_TYPE, null);
+        node.addField("pp_f", 0            , ClassHelper.OBJECT_TYPE, null);
         addDummyConstructor(node);
         verifier.visitClass(node);
-        checkErrorCount(4);
-        checkErrorMessage("The field 'prof' is not 'public static final' but 
is defined in interface 'zzz'.");
-        checkErrorMessage("The field 'prif' is not 'public static final' but 
is defined in interface 'zzz'.");
-        checkErrorMessage("Method 'prom' is protected but should be public or 
private in interface 'zzz'.");
-        checkErrorMessage("Method 'ppm' is package-private but should be 
public or private in interface 'zzz'.");
-    }
-
-    public void testDetectsCorrectMethodModifiersInClass() throws Exception {
+        checkErrorCount(8);
+        checkErrorMessage("The field 'prof' is not 'public static final' but 
is defined in interface 'zzz'");
+        checkErrorMessage("The field 'prif' is not 'public static final' but 
is defined in interface 'zzz'");
+        checkErrorMessage("The field 'pp_f' is not 'public static final' but 
is defined in interface 'zzz'");
+        checkErrorMessage("The method 'pro1' must be public as it is declared 
abstract in interface 'zzz'");
+        checkErrorMessage("The method 'pro2' is protected but must be public 
or private in interface 'zzz'");
+        checkErrorMessage("The method 'pro3' is protected but must be default 
or private in interface 'zzz'");
+        checkErrorMessage("The method 'pp_1' must be public as it is declared 
abstract in interface 'zzz'");
+        checkErrorMessage("The method 'pp_2' is package-private but must be 
public or private in interface 'zzz'");
+    }
+
+    public void testDetectsCorrectMethodModifiersInClass() {
         // can't check volatile here as it doubles up with bridge
         ClassNode node = new ClassNode("zzz", ACC_PUBLIC, 
ClassHelper.OBJECT_TYPE);
         node.addMethod(new MethodNode("st", ACC_STRICT, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
@@ -164,14 +145,14 @@ public class ClassCompletionVerifierTest extends 
TestSupport {
         checkErrorCount(0);
     }
 
-    public void testDetectsIncorrectMethodModifiersInClass() throws Exception {
+    public void testDetectsIncorrectMethodModifiersInClass() {
         // can't check volatile here as it doubles up with bridge
         ClassNode node = new ClassNode("zzz", ACC_PUBLIC, 
ClassHelper.OBJECT_TYPE);
         node.addMethod(new MethodNode("tr", ACC_TRANSIENT, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
         addDummyConstructor(node);
         verifier.visitClass(node);
         checkErrorCount(1);
-        checkErrorMessage(EXPECTED_TRANSIENT_METHOD_ERROR_MESSAGE);
+        checkErrorMessage("The method 'java.lang.Object tr()' has an incorrect 
modifier transient.");
     }
 
     public void testDetectsInvalidFieldModifiers() {
@@ -183,6 +164,8 @@ public class ClassCompletionVerifierTest extends 
TestSupport {
         checkErrorMessage("Illegal combination of modifiers, final and 
volatile, for field 'bar'");
     }
 
+    
//--------------------------------------------------------------------------
+
     private void addDummyConstructor(ClassNode node) {
         // constructors should not be treated as errors (they have no real 
meaning for interfaces anyway)
         node.addMethod(new MethodNode("<clinit>", ACC_PUBLIC | ACC_STATIC, 
ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
@@ -209,9 +192,7 @@ public class ClassCompletionVerifierTest extends 
TestSupport {
 
     private void checkErrorMessage(String expectedErrorMessage) {
         assertTrue("Expected an error message but none found.", 
source.getErrorCollector().hasErrors());
-        assertTrue("Expected message to contain <" + expectedErrorMessage +
-                "> but was <" + flattenErrorMessage() + ">.",
-                flattenErrorMessage().contains(expectedErrorMessage));
+        assertTrue("Expected message to contain <" + expectedErrorMessage + "> 
but was <" + flattenErrorMessage() + ">.", 
flattenErrorMessage().contains(expectedErrorMessage));
     }
 
     private String flattenErrorMessage() {
diff --git a/src/test/org/codehaus/groovy/classgen/InterfaceTest.groovy 
b/src/test/org/codehaus/groovy/classgen/InterfaceTest.groovy
index a1801c1776..853672d434 100644
--- a/src/test/org/codehaus/groovy/classgen/InterfaceTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/InterfaceTest.groovy
@@ -45,7 +45,7 @@ final class InterfaceTest {
                     GClass[] getGC()
                     default String foo() { 'foo' + GInterface.this.bar() }
                     private String bar() { 'bar' }
-//                    static  String baz() { 'baz' }
+                    static  String baz() { 'baz' }
                 }
             '''
             def c = new File(parentDir, 'test/JClass.java')
@@ -64,7 +64,7 @@ final class InterfaceTest {
                 def jc = new test.JClass()
                 assert jc.getGC().length == 0
                 assert jc.toString() == 'foobar'
-//                assert test.JClass.baz() == 'baz'
+                assert test.GInterface.baz() == 'baz'
             '''
 
             def loader = new GroovyClassLoader(this.class.classLoader)


Reply via email to