codeconsole opened a new pull request, #3097:
URL: https://github.com/apache/groovy/pull/3097
The JVM allows access to a protected or package-private member only within
the same run-time package, which is the package name and the class loader. A
`GroovyClassLoader` defines each compilation in memory with a class loader of
its own (a `GroovyShell` script, `parseClass`, a script run with `groovy`,
JSR-223), so a class from an earlier parse, or a precompiled class used by such
a script, is in another run-time package even with the same package name.
Statically compiled code accessed such members directly and failed with
`IllegalAccessError`:
```groovy
// first parse
package p
class A { @PackageScope A(String s) {}; @PackageScope String name() { 'a' };
@PackageScope String tag = 't' }
// second parse with the same GroovyShell
package p
@CompileStatic List make() { def a = new A('x'); [a.name(), a.tag] }
```
For a compilation defined in memory, statically compiled code now reaches
such a constructor, method or field through the meta-class, as dynamic code
does. This covers `new` and map-style construction, instance and static
methods, getters and setters used as properties, method references such as
`a::name` (through a synthetic method), and field reads and writes including
`.@`, `+=` and `++`. In dynamic code, `super.f`, `super.@f` and `this.@f` of
such a field and `super.m()` of such a method work too (no `super$` method is
generated for a package-private method of another run-time package). Public
members, classes of the same compilation, and protected members used from a
subclass through `this`, `super` or a receiver of the subclass type are still
accessed directly. Code compiled to class files (groovyc, Gradle, Maven, Ant,
joint compilation with Java) keeps direct access to the members of the other
classes of its package, as javac does, and a full and an incremental build give
t
he same bytecode. The rule is `AsmClassGenerator.isInSameRuntimePackage`,
which #3022 introduces for constructor references; this applies it to the rest.
Protected members of another package, in a subclass, under static
compilation:
- `new A(...)` of a protected constructor of another package is reported:
"Cannot call protected constructor for p.A from class q.B". As in Java, only
`super(...)` and `new A(...) {}` can call it. It used to compile and then fail
verification. The error is raised while the class is generated, so
`@TypeChecked` code is not checked for it and works through the meta-class.
- A protected method of another package called through a receiver of the
superclass type (`a.m()`, `a.name`, `a::m`, `A::m`) is reported as "Cannot
access method", as GROOVY-7325 intended: its check compared the types the wrong
way round. These used to compile and then fail with `VerifyError`. `a.@field =
value` through such a receiver now goes through the meta-class, like the read.
With invokedynamic, a dynamic `new` of a constructor that the JVM refuses,
such as `new ObjectInputStream()` in a subclass, now fails with "could not
access constructor", as it does without invokedynamic, instead of
`GroovyBugError`.
COMPATIBILITY.md has an entry for the meta-class semantics of these accesses
and the two new compile errors.
This builds on #3022 (constructor references), which adds
`isInSameRuntimePackage`, the `GroovyClassLoader` marker and
`StaticInvocationWriter.isDirectlyAccessible`; its commits are included here
until it is merged.
## Tests
All marked `// GROOVY-12568`, each failing without the change it covers:
- `StaticCompileRuntimePackageTest`: constructors, map-style construction
(literal and `Map` variable), methods, properties, method references (also in
static and default methods of an interface) and fields of a class of another
class loader, with and without invokedynamic, compared with the same code
compiled dynamically; bytecode tests pin that classes of the same compilation,
public members, class files, incremental builds and joint compilation keep
direct access;
- `bugs.Groovy12568`: dynamic `super.m()` of a package-private method of
another class loader, and invokedynamic `new` of a protected constructor of
another package or of the JDK;
- `ConstructorsSTCTest` and `StaticCompileConstructorsTest`: `new` of a
protected constructor of another package, with `super(...)` and anonymous
classes still direct;
- `Groovy7325Bug`: protected methods of another package through a receiver
of the superclass and of the subclass.
The `groovy.*`, `gls.*`, `bugs.*`, `org.codehaus.groovy.classgen` and
`org.codehaus.groovy.transform` packages pass (13,458 tests), apart from
`bugs.Groovy12363`, which also fails on master when it runs after
`bugs.Groovy12142` in the same JVM (GROOVY-12580, #3096, fixes it), and
`bugs.Groovy9815`, whose `@Grab` download failed once and passes when rerun.
The Checkstyle and CodeNarc gates pass.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]