Paul King created GROOVY-12537:
----------------------------------

             Summary: STC: field access through a protected or doubly-nested 
private member type is wrongly rejected as inaccessible
                 Key: GROOVY-12537
                 URL: https://issues.apache.org/jira/browse/GROOVY-12537
             Project: Groovy
          Issue Type: Bug
          Components: Static Type Checker
    Affects Versions: 6.0.0
            Reporter: Paul King
            Assignee: Paul King


Description:

Since GROOVY-12314, the type checker rejects a field access when the type that 
qualifies it is not accessible from the calling class. The accessibility check 
gets member types wrong in two cases, so valid code that compiled before now 
fails under @CompileStatic and @TypeChecked:

1. A protected member type of a class compiled in an earlier step, used from a 
subclass in another package:

{code:groovy}
// p/Base.groovy, compiled first
package p
class Base {
    protected static class Prot { public static String F = 'f' }
}
{code}

{code:groovy}
// q/Sub.groovy, compiled with p.Base on the classpath
package q
@groovy.transform.CompileStatic
class Sub extends p.Base {
    static String run() { p.Base.Prot.F }
}
{code}

{noformat}
[Static type checking] - Cannot access field: F of class: p.Base$Prot from 
class: q.Sub
{noformat}

2. A private member type nested inside another member type, used from the 
top-level class:

{code:groovy}
package q
@groovy.transform.CompileStatic
class Outer {
    private static class A {
        private static class B { public static String F = 'f' }
    }
    static String run() { A.B.F }
}
{code}

{noformat}
[Static type checking] - Cannot access field: F of class: q.Outer$A$B from 
class: q.Outer
{noformat}

Java accepts both (JLS 6.6.1, 6.6.2), and both compiled and ran before 
GROOVY-12314.

Cause: StaticTypeCheckingVisitor#hasAccessToClass checks a member type's 
modifiers with the rule used for members, using the enclosing type as the 
receiver:
* For a type compiled in an earlier step, ClassNode#getOuterClass() is null, so 
the enclosing type is unknown. A protected member type is then checked against 
itself, and no subclass derives from it.
* Protected access is checked against the calling class alone. JLS 6.6.2 allows 
it anywhere in the body of the subclass, including its nested classes, closures 
and anonymous classes.
* Private access only allows the immediately enclosing type and classes nested 
inside the private type. It should allow anything in the same nest, as the 
existing inSameNest check does.

Proposed fix: when the enclosing type is unknown, enforce only package-private 
access, so the check rejects only what it can actually decide. Otherwise, check 
the enclosing type's accessibility first, then: public => accessible; private 
=> same nest; same package as the enclosing type => accessible; protected => 
the calling class or one of its enclosing classes derives from the enclosing 
type. Every change here makes the rule more permissive, so nothing the check 
accepts today will be rejected. The GROOVY-12310 case (a package-private nested 
enum in a Java class) is still rejected.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to