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)

Reply via email to