Repository navigation
GROOVY-12568: SC: reach protected and package-private members of a class of another GroovyClassLoader compilation through the meta-class - #3097
Conversation
…ectly Under static compilation, a constructor reference such as Made::new is implemented by a synthetic method of the enclosing class, which the LambdaMetafactory call site targets. That method was generated with STATIC_COMPILE_NODE set to false, because its constructor call had no target constructor. So it created the object through the meta-class, an "init" invokedynamic call site followed by a "cast" call site, and the constructor was selected at run time on every call. In a GraalVM native image, the constructor also had to be registered for reflection although the code was statically compiled. StaticTypesMethodReferenceExpressionWriter now selects the constructor when it builds the synthetic method: chooseBestMethod matches the declared constructors of the type against the parameter types of the functional interface, as the arguments of a constructor call are matched. When a single constructor matches and the current class can call it, it becomes the DIRECT_METHOD_CALL_TARGET of the constructor call and the synthetic method is statically compiled, so StaticInvocationWriter emits NEW and INVOKESPECIAL, with any boxing, unboxing, widening or variadic array the arguments need. As for other method references, the constructor is then chosen by the parameter types of the functional interface, not by the run-time types of the arguments. The constructor is still selected at run time when no single constructor accepts the parameter types, for example Foo::new as a Function<Object,Foo> when Foo only declares Foo(String), and when the constructor is protected and declared in another package, which only a super(...) call can use. Array constructor references are unchanged: they already create the array directly.
… the visible ones The constructor of a statically compiled constructor reference was chosen from all the constructors the type declares. When the best match was a constructor the enclosing class cannot use, such as private Foo(String) next to a public Foo(Object), the reference fell back to run-time selection and the meta-class called the inaccessible constructor, while new Foo(s) in the same class calls Foo(Object). The constructors are now filtered by visibility before chooseBestMethod, as the type checker does for a constructor call, so the reference calls Foo(Object) directly, as new Foo(s) and Java do. Visibility is checked for the enclosing class of a closure or lambda, not for the generated class, so a private constructor of a nested class stays visible from a closure or lambda of the outer class, as it is for the type checker.
…y only within the compilation unit A constructor reference called a protected or package-private constructor of the same package directly. The JVM checks the run-time package, which is the package name and the class loader, so the call failed with IllegalAccessError when the class came from another class loader with the same package name: a class of an earlier GroovyShell parse, which GroovyClassLoader defines with another InnerLoader, or a precompiled class used from a script. Such a constructor is now called directly only when its class is compiled in the same compilation unit, which defines all its classes with one class loader. Otherwise the constructor is selected at run time, as before the constructor reference was compiled statically.
…final in an interface The synthetic method that implements a constructor reference, or adapts a variadic or extension method reference, is private, static and final. The JVM rejects a final private method in an interface, so a method reference that needs one, such as Foo::new or Arrays::asList as a Supplier<List>, in a static or default method of a statically compiled interface failed with ClassFormatError when the interface was loaded. The method is no longer final in an interface; it is private, so it cannot be overridden anyway.
…he meta-class A statically compiled constructor reference now calls the constructor directly, as new Foo(s) does under static compilation, so a constructor added to the meta-class, for example with ExpandoMetaClass, is no longer used by it. Pin this with a test, and mark the tests added for GROOVY-12488 with the issue key.
…cked code does new A(map), where map is a Map variable rather than a map literal and A declares only a no-argument constructor, is a map-style construction: Groovy calls the no-argument constructor and sets a property for each entry of the map. The type checker accepts it: as the property names are only known at run time, it does not select a constructor, and type-checked code constructs the object through the meta-class. Under static compilation nothing compiled such a call, and compilation stopped with the internal error "Target constructor for constructor call expression hasn't been set". A constructor reference such as Function<Map, A> f = A::new stopped with the same error, because the type checker checks it as new A(map). The type checker now marks such a call for dynamic resolution, and the static compiler creates the object through the meta-class, as type-checked and dynamic code do. A map literal is still compiled to the no-argument constructor and a setter call for each entry, and a constructor reference to such a class still selects the constructor at run time. (Test only: GROOVY-12454 on master already makes static compilation construct such an object through the meta-class, so only the test of the constructor reference, testFunctionCN25, is kept.)
…ugh the meta-class only for classes defined in memory The previous commits accessed a protected or package-private member of a class with the same package name through the meta-class whenever that class was compiled by another compilation unit. That also hit class files: a Java class of a joint compilation, a main class used by a test, a class left over from an incremental compilation. Such classes are loaded by one class loader at run time, as javac assumes, so the direct access worked; the meta-class path was slower, followed meta-class semantics, needed reflection metadata in a native image, and made an incremental build give other bytecode than a full one. The run-time package of such a class only differs when the classes are defined in memory by a GroovyClassLoader, which defines each compilation (a GroovyShell script, parseClass, JSR-223) with an InnerLoader of its own. GroovyClassLoader now records that on the compilation unit, and AsmClassGenerator.isInSameRuntimePackage treats a class of another compilation unit as another run-time package only then. Constructors, map-style construction, methods, getters and setters, method references, fields, dynamic super and this.@ access and super$ methods all use this check. Compiling to class files keeps direct access, as before these changes and as javac does. (Constructor part: the GroovyClassLoader marker, AsmClassGenerator.isInSameRuntimePackage and StaticInvocationWriter.isDirectlyAccessible, which constructor references use. The same rule for new, methods, fields, dynamic super, this.@ and super$ methods follows separately.)
…structor reference The synthetic method of an array constructor reference such as String[]::new was the one constructor-reference method still marked as not statically compiled. It is now compiled by the static writers, like the method of a class constructor reference that has a target constructor. Its bytecode does not change: the array was already created with NEWARRAY, ANEWARRAY or MULTIANEWARRAY, and the size unboxed the way a statically compiled new T[n] does (Integer.intValue, or DefaultTypeTransformation.intUnbox for a Short or Byte). The new tests pin that bytecode, compared with new String[s], and the behavior for each size type the type checker accepts (int, short, byte and their wrappers), multi-dimensional and primitive arrays, closures and lambdas, a negative size and null.
…rules of constructor references - isInSameRuntimePackage: isPrimaryClassNode() stands for "defined by the class loader of the accessing class", not for "compiled from source". - StaticInvocationWriter.isDirectlyAccessible: unlike isMemberDirectlyAccessible it has no subclass rule, since the verifier rejects NEW and INVOKESPECIAL of a protected constructor of another package in a subclass too. - findConstructorReferenceTarget: a selected constructor is called directly, so a meta-class constructor override is not used, as for a statically compiled new. The guard comment now says why enums are left to the meta-class: the type checker accepts an enum constructor reference whose arguments match the generated constructor, but Java code cannot instantiate an enum. - addSyntheticMethod: the ACC_FINAL rule of JVMS 4.6 applies to every helper method of a method reference in an interface. (Constructor part: the notes on statically compiled new follow separately.)
…nd abstract-class constructors Default arguments: the constructors that Verifier generates for default arguments keep the modifiers of the declared constructor and are not synthetic, and every class of a compilation is verified before any class is generated, so a constructor reference whose functional interface matches a generated constructor calls it directly, also when the class is declared after the reference, when the constructor is package-private, when every parameter has a default, and for a public constructor of a class compiled by an earlier parse. A package-private one of such a class is still selected at run time. Enums: the type checker accepts E::new inside the enum when the functional interface matches the constructor Groovy generates (name, ordinal, ...); the reference stays on the run-time path, while javac rejects it outright. Abstract classes: A::new is a type checking error also inside an anonymous subclass. A protected constructor of another package referenced from an anonymous subclass is selected at run time and works.
… interface All helper methods that a method reference adds to the current class are created by addSyntheticMethod, which leaves out ACC_FINAL in an interface. The interface tests covered the constructor-reference and variadic helpers; they now also cover the array constructor reference, the static extension method helper (Thread::startDaemon), the Class method helper (String::getName) and the helper that calls a package-private method of a class of another class loader (M::spm, M::pm), in static and default methods, and check that every helper is private and not final. With ACC_FINAL put back, both tests fail with ClassFormatError (illegal modifiers 0x101A). (Constructor-reference part: the case of a method of another run-time package follows separately.)
…AbstractBytecodeTestCase MethodReferenceTest and StaticCompileRuntimePackageTest each had a copy of the helper that compiles a script against the classes of an earlier parse of the same GroovyClassLoader, and of the code that keeps only the instructions of one method. AbstractBytecodeTestCase now provides them as compileAgainstLibrary, extractMethodSequence and selectMethod, and both tests use them. Test code only; the tests are unchanged. (Here MethodReferenceTest only; StaticCompileRuntimePackageTest, which comes separately, uses the same helpers.)
…ce helpers testMethodReferencesInStaticAndDefaultMethodsOfInterface listed every synthetic method of the interface. With coverage on, JaCoCo adds its own synthetic $jacocoInit, so the CI coverage job failed. The test now skips names starting with '$'.
…nstructor references COMPATIBILITY.md lists the changes for Groovy 7: the overload is chosen by the static parameter types of the functional interface, an Object[] is passed to a variadic constructor as one element, null for a primitive parameter throws NullPointerException, a constructor the enclosing class cannot call no longer wins over one it can, and a meta-class constructor is not used. The method reference section of the operators guide says how the constructor of a constructor reference is selected, when it is still selected at run time, and that those cases need reflection metadata in a native image.
…er subclass GroovyClassLoader marks every parseClass compilation as defined in memory, whatever its class collector does. A subclass whose collector defines the classes with the GroovyClassLoader itself therefore takes the meta-class path for non-public members of classes of its other compilations, where a direct access would also work. The javadoc of the mark now says so.
…h new directly only within the compilation unit Under static compilation, new A(...) of a protected or package-private constructor of a class with the same package name was compiled to NEW and INVOKESPECIAL. The JVM allows that call only within the same run-time package, which is the package name and the class loader, so it failed with IllegalAccessError when A came from another class loader: a class of an earlier parse of the same GroovyShell, which GroovyClassLoader defines with another InnerLoader, or a precompiled class used by a script. Dynamic and type-checked code create such an object through the meta-class and work. Such a constructor is now called directly only when its class is compiled in the same compilation unit, which defines all its classes with one class loader, as for a constructor reference. Otherwise the object is created through the meta-class, which selects the constructor at run time. This also applies to the no-argument constructor that a map-style construction such as new A(name: 'x') calls before it sets the properties. Public constructors, and constructors of classes of the same compilation unit, are still called directly. The constructor reference writer uses the same check.
… only within the compilation unit Under static compilation, a call to a protected or package-private method of a class with the same package name was compiled to a direct INVOKEVIRTUAL, INVOKESTATIC or INVOKESPECIAL. As for a constructor, the JVM allows that call only within the same run-time package, so it failed with IllegalAccessError when the class came from another class loader, for example a class of an earlier parse of the same GroovyShell. This also hit a protected or package-private getter or setter used as a property, such as a.name or a.name = value. Such a method is now called directly only when its class is compiled in the same compilation unit, or when the JVM allows the call from any package: a protected method called from a subclass on this, super or a receiver of the subclass type, or a protected static method called from a subclass. Otherwise the method is selected at run time through the meta-class, as dynamic code does. Public methods, and methods of classes of the same compilation unit, are still called directly.
…nother compilation unit through a synthetic method A statically compiled method reference such as m::pm, M::pm or M::spm gives LambdaMetafactory a method handle for the method. For a protected or package-private method of a class with the same package name, the JVM resolves that handle only within the same run-time package, so the reference failed with IllegalAccessError when the class came from another class loader, for example a class of an earlier parse of the same GroovyShell. For such a method of a class of another compilation unit, the reference now targets a synthetic static method of the current class that calls the method. The invocation writer compiles that call directly when the JVM allows it from any package (a protected method called through the subclass), or else selects the method at run time. Method references to methods of classes of the same compilation unit, and to public methods, still use a method handle for the method itself.
…ly within the compilation unit AsmClassGenerator.isFieldDirectlyAccessible decided by the package name if a protected or package-private field can be read or written with GETFIELD, PUTFIELD, GETSTATIC or PUTSTATIC. As for methods and constructors, the JVM allows that only within the same run-time package, so the access failed with IllegalAccessError when the class came from another class loader, for example a class of an earlier parse of the same GroovyShell. Under static compilation this hit a.field, a.@field, Type.field, an implicit field of a superclass, compound assignments and increments. Dynamic code hit it for super.field, super.@field and this.@field of a superclass. A protected field of a superclass with the same package name but of another compilation unit was also read through a receiver of the superclass type, which fails verification ("Bad access to protected data in getfield") when the classes are in different run-time packages. Such a field is now accessed directly only when its class is compiled in the same compilation unit, or through the subclass rule for a protected field (with a receiver of the current class). Otherwise it is read and written through the meta-class, as dynamic code does. Public fields, and fields of classes of the same compilation unit, are still accessed directly.
…ckage instead of failing verification
Outside its package, a protected constructor can only be called by
super(...) or by creating an anonymous inner class (JLS 6.6.2.2). The type
checker accepts new A(...) of such a constructor in a subclass of A, as it
accepts other protected members there, and type-checked code creates the
object through the meta-class. Under static compilation, the call was
compiled to NEW and INVOKESPECIAL, and the class failed verification when
it was loaded: "VerifyError: Bad access to protected <init> method". The
same happened for a map-style construction such as new A([:]), which calls
the protected no-argument constructor.
The static compiler now reports "Cannot call protected constructor for A
from class B", as it reports a protected method called on a receiver that
is not the subclass (GROOVY-7325). super(...), this(...) and
new A(...) {} still call the constructor directly. A constructor reference
A::new to such a constructor still selects it at run time.
… through a superclass receiver Outside its package, a protected instance method or field can be used only through a receiver of the subclass (JLS 6.6.2.1, JVMS 4.10.1.8). For a method, the static compiler meant to report such a call (GROOVY-7325), but its check compared the types the wrong way round: it tested whether the current class is a subtype of the receiver type instead of the reverse. So a.m() with a receiver of the superclass type, in a subclass in another package, was compiled to a direct call and the class failed verification: "VerifyError: Bad access to protected data in invokevirtual". This also hit a protected getter or setter used as a property (a.name, a.name = value). A method reference such as a::m or A::m to such a method failed with BootstrapMethodError, and an attribute assignment a.@field = value failed verification in putfield. The check now requires the receiver to be of the current class (or this, super or a static method), so such a call or method reference is reported as "Cannot access method", as GROOVY-7325 intended and as javac does. An attribute assignment through such a receiver is now made through the meta-class, as the attribute read a.@field already was. Calls through this, super or a receiver of the subclass type are still direct.
…amic cannot access the constructor A dynamic new of a protected constructor of another package, in a subclass, is accepted by Groovy and by the type checker. With invokedynamic, the constructor selector unreflected the selected constructor with the lookup of the calling class and turned an IllegalAccessException into GroovyBugError. For a constructor that the JVM refuses to the caller, such as the protected ObjectInputStream() of the encapsulated java.io package called by new in a subclass, the call failed with "BUG! UNCAUGHT EXCEPTION: member is protected". As the property selectors do since GROOVY-12314, the constructor selector now treats the refusal as an access-control outcome and leaves the call to the meta-class, which reports "could not access constructor", as the call does without invokedynamic. A constructor that reflection can reach, such as a protected constructor of a class of another package in the unnamed module, is still called.
…ethod of another run-time package For a dynamic super.m() call, the class gets a synthetic super$N$m method that calls the superclass method with INVOKESPECIAL. For a package-private method of a superclass with the same package name but of another compilation unit, the classes may be in different run-time packages, for example when the superclass comes from an earlier parse of the same GroovyShell, and the JVM refuses the call: super.m() failed with IllegalAccessError. Such a method, and a package-private method of a superclass of another package, no longer gets a super$ method, and the meta-class calls the superclass method reflectively, as it does for a statically compiled super.m() of such a method.
…ugh the meta-class only for classes defined in memory The previous commits accessed a protected or package-private member of a class with the same package name through the meta-class whenever that class was compiled by another compilation unit. That also hit class files: a Java class of a joint compilation, a main class used by a test, a class left over from an incremental compilation. Such classes are loaded by one class loader at run time, as javac assumes, so the direct access worked; the meta-class path was slower, followed meta-class semantics, needed reflection metadata in a native image, and made an incremental build give other bytecode than a full one. The run-time package of such a class only differs when the classes are defined in memory by a GroovyClassLoader, which defines each compilation (a GroovyShell script, parseClass, JSR-223) with an InnerLoader of its own. GroovyClassLoader now records that on the compilation unit, and AsmClassGenerator.isInSameRuntimePackage treats a class of another compilation unit as another run-time package only then. Constructors, map-style construction, methods, getters and setters, method references, fields, dynamic super and this.@ access and super$ methods all use this check. Compiling to class files keeps direct access, as before these changes and as javac does. (The rest of the change: new, map-style construction, methods, getters and setters, method references to methods, fields, dynamic super and this.@ access and super$ methods. The GroovyClassLoader marker, isInSameRuntimePackage and constructor references come first.)
The tests for protected and package-private members of a class of another compilation now compile it through a GroovyClassLoader, which defines it with another class loader; classes compiled to class files keep direct access. Name the tests accordingly.
…rules of constructor references - isInSameRuntimePackage: isPrimaryClassNode() stands for "defined by the class loader of the accessing class", not for "compiled from source". - StaticInvocationWriter.isDirectlyAccessible: unlike isMemberDirectlyAccessible it has no subclass rule, since the verifier rejects NEW and INVOKESPECIAL of a protected constructor of another package in a subclass too. - findConstructorReferenceTarget: a selected constructor is called directly, so a meta-class constructor override is not used, as for a statically compiled new. The guard comment now says why enums are left to the meta-class: the type checker accepts an enum constructor reference whose arguments match the generated constructor, but Java code cannot instantiate an enum. - addSyntheticMethod: the ACC_FINAL rule of JVMS 4.6 applies to every helper method of a method reference in an interface. (The part on statically compiled new; the rest comes with constructor references.)
… interface All helper methods that a method reference adds to the current class are created by addSyntheticMethod, which leaves out ACC_FINAL in an interface. The interface tests covered the constructor-reference and variadic helpers; they now also cover the array constructor reference, the static extension method helper (Thread::startDaemon), the Class method helper (String::getName) and the helper that calls a package-private method of a class of another class loader (M::spm, M::pm), in static and default methods, and check that every helper is private and not final. With ACC_FINAL put back, both tests fail with ClassFormatError (illegal modifiers 0x101A). (The case of a method of another run-time package; the other helper methods are tested with constructor references.)
…AbstractBytecodeTestCase MethodReferenceTest and StaticCompileRuntimePackageTest each had a copy of the helper that compiles a script against the classes of an earlier parse of the same GroovyClassLoader, and of the code that keeps only the instructions of one method. AbstractBytecodeTestCase now provides them as compileAgainstLibrary, extractMethodSequence and selectMethod, and both tests use them. Test code only; the tests are unchanged. (Here StaticCompileRuntimePackageTest; MethodReferenceTest was moved to the helpers with constructor references.)
…errors COMPATIBILITY.md describes how statically compiled code of a compilation that a GroovyClassLoader defines in memory reaches protected and package-private members of classes of other compilations, and the new compile errors for new of a protected constructor of another package and for a protected method of another package called through a superclass receiver. StaticInvocationWriter notes that the constructor error is reported during class generation, so @TypeChecked code is not checked for it and works dynamically.
…ass of another class loader Since GROOVY-12454, new A(map) with a Map variable, under static compilation, calls the no-argument constructor and then sets the properties of the map at run time. For a class of an earlier parse of the same GroovyShell whose no-argument constructor is package-private, the constructor is called through the meta-class, as for a map literal.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #3097 +/- ##
==================================================
+ Coverage 73.7763% 73.8134% +0.0371%
- Complexity 42753 42837 +84
==================================================
Files 1678 1678
Lines 147462 147579 +117
Branches 27899 27942 +43
==================================================
+ Hits 108792 108933 +141
+ Misses 28513 28472 -41
- Partials 10157 10174 +17
🚀 New features to boost your workflow:
|
daniellansun
left a comment
There was a problem hiding this comment.
LGTM for GROOVY-12568 (and the bundled GROOVY-12488 constructor-reference work this branch carries).
JVM run-time package = package name + ClassLoader. Marking each GroovyClassLoader in-memory compilation (InnerLoader metadata on the CompileUnit) and then refusing direct bytecode access to protected / package-private members across that boundary — falling back to meta-class / synthetic helpers, and emitting the new compile errors for illegal new of a protected ctor / protected method via a foreign receiver — matches JLS/JVMS and dynamic Groovy.
AsmClassGenerator.isInSameRuntimePackage / isFieldDirectlyAccessible, StaticInvocationWriter.isDirectlyAccessible + writeDynamicConstructorCall, MopWriter skipping impossible super$ bridges, and the indy ctor path are coherent. StaticCompileRuntimePackageTest + Groovy12568 cover GCL isolation, map-style construction, method/ctor refs, and fields. COMPATIBILITY.md / operator docs spell the Groovy 7 behavior change clearly.
CI fully green. Codecov ~84% patch with mostly branch partials (no large missing blocks) — acceptable for this surface.
Merge notes: branch is ~30 commits ahead / a few behind master; open #3022 (GROOVY-12488) overlaps — prefer one landing path. #3098 / #3099 are siblings on top of this tip; merge this first.
|
Friendly ping: this PR is approved. If there are no objections within 72 hours, this PR will be merged. Thanks! |
# Conflicts: # COMPATIBILITY.md
|
@daniellansun Thanks. #3097 is stacked on #3022 (GROOVY-12488), so merging it also lands #3022's commits. Either order works: merge #3022 first and #3097 then shows only its own commits, or merge #3097 and close #3022. #3098 and #3099 go after #3097. I merged master into all four to clear a COMPATIBILITY.md conflict (both sides added an entry; kept both). |
🔎 No tests executed 🔎🏷️ Commit: 7be59ca Learn more about TestLens at testlens.app/docs. |
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
GroovyClassLoaderdefines each compilation in memory with a class loader of its own (aGroovyShellscript,parseClass, a script run withgroovy, 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 withIllegalAccessError: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
newand map-style construction, instance and static methods, getters and setters used as properties, method references such asa::name(through a synthetic method), and field reads and writes including.@,+=and++. In dynamic code,super.f,super.@fandthis.@fof such a field andsuper.m()of such a method work too (nosuper$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 throughthis,superor 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 the same bytecode. The rule isAsmClassGenerator.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, onlysuper(...)andnew A(...) {}can call it. It used to compile and then fail verification. The error is raised while the class is generated, so@TypeCheckedcode is not checked for it and works through the meta-class.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 withVerifyError.a.@field = valuethrough such a receiver now goes through the meta-class, like the read.With invokedynamic, a dynamic
newof a constructor that the JVM refuses, such asnew ObjectInputStream()in a subclass, now fails with "could not access constructor", as it does without invokedynamic, instead ofGroovyBugError.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, theGroovyClassLoadermarker andStaticInvocationWriter.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 andMapvariable), 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: dynamicsuper.m()of a package-private method of another class loader, and invokedynamicnewof a protected constructor of another package or of the JDK;ConstructorsSTCTestandStaticCompileConstructorsTest:newof a protected constructor of another package, withsuper(...)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.classgenandorg.codehaus.groovy.transformpackages pass (13,458 tests), apart frombugs.Groovy12363, which also fails on master when it runs afterbugs.Groovy12142in the same JVM (GROOVY-12580, #3096, fixes it), andbugs.Groovy9815, whose@Grabdownload failed once and passes when rerun. The Checkstyle and CodeNarc gates pass.