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)