[ 
https://issues.apache.org/jira/browse/GROOVY-12717?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18140036#comment-18140036
 ] 

ASF GitHub Bot commented on GROOVY-12717:
-----------------------------------------

codeconsole opened a new pull request, #3251:
URL: https://github.com/apache/groovy/pull/3251

   Under `@CompileStatic`, this compiles and then fails when the class is 
loaded:
   
   ```groovy
   // package p
   class A { protected A(String s) {}; protected String im() { 'im' }; 
protected String getQp() { 'qp' } }
   
   // package q
   @CompileStatic class B extends p.A {
       B() { super('b') }
       static test(p.A a) {
           new p.A('x')  // VerifyError: Bad access to protected <init> method
           a.im()        // VerifyError: Bad access to protected data in 
invokevirtual
           a.qp          // the same, through the getter
           java.util.function.Supplier<String> s = a::im  // 
BootstrapMethodError
       }
   }
   ```
   
   5.0.8 and 6.0.0 fail the same way. Neither has to do with class loaders: 
these are Java's rules for a protected member outside its package.
   
   - `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. That includes a map-style 
construction, which calls the protected no-argument constructor. 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.
   
   Calls through `this`, `super` or a receiver of the subclass type are still 
direct, and `A::new` still selects such a constructor at run time.
   
   An attribute assignment `a.@f = v` through a superclass receiver still fails 
verification in `putfield`. It is not changed here.
   
   This and #3097 (GROOVY-12568) touch the same lines of 
`StaticInvocationWriter`, `StaticTypesMethodReferenceExpressionWriter` and 
`ConstructorCallTransformer`; whichever lands second keeps both. Once this is 
in, a map-style construction reaches the check of #3097 through 
`writeInvokeConstructor`, so its own call in `ConstructorCallTransformer` is 
not needed.
   
   ## Compatibility
   
   No working code is affected: this code failed verification or at link time. 
It now fails at compile time, under `@CompileStatic` only.
   
   ## Tests
   
   
`Groovy7325Bug.testProtectedMethodOfAnotherPackageThroughReceiverOfSuperclass`, 
`StaticCompileConstructorsTest.testProtectedConstructorOfAnotherPackage` and 
`testMapStyleConstructionWithProtectedConstructorOfAnotherPackage` fail without 
the change. 
`Groovy7325Bug.testProtectedMembersOfAnotherPackageThroughReceiverOfSubclass` 
and the `ConstructorsSTCTest` additions pin what keeps working. 5,684 tests in 
`org.codehaus.groovy.classgen.asm.sc`, `groovy.transform.stc` and `gls` pass. 
The Checkstyle and CodeNarc gates pass.
   




> SC: new of a protected constructor of another package, or a protected method 
> through a superclass receiver, fails verification instead of being reported
> --------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12717
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12717
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static compilation
>    Affects Versions: 4.0.32, 5.0.8, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {code:groovy}
> // package p
> class A {
>     protected A(String s) { }
>     protected String im() { 'im' }
>     protected String getQp() { 'qp' }
> }
> // package q
> @groovy.transform.CompileStatic
> class B extends p.A {
>     B() { super('b') }
>     static test(p.A a) {
>         new p.A('x')  // or new p.A([:]) with a protected no-argument 
> constructor
>         a.im()
>         a.qp
>         java.util.function.Supplier<String> s = a::im
>         java.util.function.Function<p.A, String> f = p.A::im
>     }
> }
> {code}
> *Actual:* {{VerifyError: Bad access to protected <init> method}} and 
> {{VerifyError: Bad access to protected data in invokevirtual}} when {{B}} is 
> loaded, and {{BootstrapMethodError}} for the method references.
> *Expected:* a compile error, as javac gives. Outside its package, a protected 
> constructor can only be called by {{super(...)}} or an anonymous class (JLS 
> 6.6.2.2), and a protected instance method only through a receiver of the 
> subclass (JLS 6.6.2.1, JVMS 4.10.1.8).
> Cause: {{StaticInvocationWriter}} writes {{new}} of such a constructor 
> directly. Its GROOVY-7325 check for a method compares the types the wrong way 
> round: it tests whether the current class is a subtype of the receiver type, 
> not the reverse.
> Verified on 5.0.8, 6.0.0 and master. 4.0.32 fails the same way for the 
> constructors and method references, and rejects {{a.im()}} and {{a.qp}} at 
> compile time.



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

Reply via email to