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)