Eric Milles created GROOVY-8651:
-----------------------------------
Summary: Method override weaker access check does not fully
account for package-private visibility
Key: GROOVY-8651
URL: https://issues.apache.org/jira/browse/GROOVY-8651
Project: Groovy
Issue Type: Bug
Reporter: Eric Milles
If override method is package-private (via {{PackageScope}}) and super method
is public (or protected?), no error is produced. If protected is indeed more
visible than package-private, there may be some additional cases uncovered
below.
org.codehaus.groovy.classgen.ClassCompletionVerifier:
{code:java}
private void checkMethodForWeakerAccessPrivileges(MethodNode mn, ClassNode
cn) {
if (mn.isPublic()) return;
Parameter[] params = mn.getParameters();
for (MethodNode superMethod :
cn.getSuperClass().getMethods(mn.getName())) {
Parameter[] superParams = superMethod.getParameters();
if (!hasEqualParameterTypes(params, superParams)) continue;
if ((mn.isPrivate() && !superMethod.isPrivate()) ||
(mn.isProtected() && superMethod.isPublic())) {
addWeakerAccessError(cn, mn, params, superMethod);
return;
}
}
}
{code}
I think that this is the proper set of checks:
{code:java}
if ((mn.isPrivate() && !superMethod.isPrivate()) ||
(mn.isProtected() && !superMethod.isProtected() &&
!superMethod.isPrivate()) ||
(!mn.isPrivate() && !mn.isProtected() && !mn.isPublic() &&
(superMethod.isPublic() || superMethod.isProtected()))) {
addWeakerAccessError(cn, mn, params, superMethod);
...
// also the error message need some change to indicate default/package-private
private void addWeakerAccessError(ClassNode cn, MethodNode method,
Parameter[] parameters, MethodNode superMethod) {
StringBuilder msg = new StringBuilder();
msg.append(method.getName());
appendParamsDescription(parameters, msg);
msg.append(" in ");
msg.append(cn.getName());
msg.append(" cannot override ");
msg.append(superMethod.getName());
msg.append(" in ");
msg.append(superMethod.getDeclaringClass().getName());
msg.append("; attempting to assign weaker access privileges; was ");
// GRECLIPSE edit
//msg.append(superMethod.isPublic() ? "public" : "protected");
msg.append(superMethod.isPublic() ? "public" :
(superMethod.isProtected() ? "protected" : "package-private"));
// GRECLIPSE end
addError(msg.toString(), method);
}
{code}
For these tests, 1b and 2a are failing:
{code:java}
@Test
public void testOverriding_ReducedVisibility1() {
runNegativeTest(new String[] {
"Bar.groovy",
"class Bar { public def baz() {} }\n",
"Foo.groovy",
"class Foo extends Bar { private def baz() {}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { private def baz() {}\n" +
"\t ^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was public\n" +
"----------\n");
}
@Test
public void testOverriding_ReducedVisibility1a() {
runNegativeTest(new String[] {
"Bar.groovy",
"class Bar { public def baz() {} }\n",
"Foo.groovy",
"class Foo extends Bar { protected def baz() {}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { protected def baz() {}\n" +
"\t ^^^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was public\n" +
"----------\n");
}
@Test
public void testOverriding_ReducedVisibility1b() {
runNegativeTest(new String[] {
"Bar.groovy",
"class Bar { public def baz() {} }\n",
"Foo.groovy",
"class Foo extends Bar { @groovy.transform.PackageScope def baz()
{}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { @groovy.transform.PackageScope def baz()
{}\n" +
"\t
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was public\n" +
"----------\n");
}
@Test
public void testOverriding_ReducedVisibility2() {
runNegativeTest(new String[] {
"Bar.groovy",
"class Bar { protected def baz() {} }\n",
"Foo.groovy",
"class Foo extends Bar { private def baz() {}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { private def baz() {}\n" +
"\t ^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was protected\n" +
"----------\n");
}
@Test
public void testOverriding_ReducedVisibility2a() {
runNegativeTest(new String[] {
"Bar.groovy",
"class Bar { protected def baz() {} }\n",
"Foo.groovy",
"class Foo extends Bar { @groovy.transform.PackageScope def baz()
{}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { @groovy.transform.PackageScope def baz()
{}\n" +
"\t
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was protected\n" +
"----------\n");
}
@Test
public void testOverriding_ReducedVisibility3() {
runNegativeTest(new String[] {
"Bar.groovy",
"class Bar { @groovy.transform.PackageScope def baz() {} }\n",
"Foo.groovy",
"class Foo extends Bar { private def baz() {}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { private def baz() {}\n" +
"\t ^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was protected\n" +
"----------\n");
}
@Test
public void testOverriding_ReducedVisibility3a() {
runNegativeTest(new String[] {
"Bar.java",
"public class Bar { Object baz() { return null; } }\n",
"Foo.groovy",
"class Foo extends Bar { private def baz() {}\n }\n",
}, "----------\n" +
"1. ERROR in Foo.groovy (at line 1)\n" +
"\tclass Foo extends Bar { private def baz() {}\n" +
"\t ^^^^^^^^^^^^^^^^^^^^\n" +
"Groovy:baz() in Foo cannot override baz in Bar; attempting to
assign weaker access privileges; was package-private\n" +
"----------\n");
}
{code}
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)