[
https://issues.apache.org/jira/browse/GROOVY-12742?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18140811#comment-18140811
]
ASF GitHub Bot commented on GROOVY-12742:
-----------------------------------------
codeconsole opened a new pull request, #3277:
URL: https://github.com/apache/groovy/pull/3277
Fixes [GROOVY-12742](https://issues.apache.org/jira/browse/GROOVY-12742).
A class-level `@Invariant` on a class that implements a trait made every
method the trait contributes return `null` (a primitive return failed with a
`GroovyCastException`), and trait property accessors with it.
`ClassInvariantGenerator.addInvariantAssertionStatement` wove the invariant
call before each `return` only when the method body was a block; the forwarders
and property accessors that `TraitComposer` generates have a bare expression or
return statement as body, so the generator fell back to appending the void
invariant call after it and the implicit return value was lost. The same
fallback left a `@Synchronized` body unwrapped, so an explicit `return` inside
it skipped the invariant.
The generator now normalises the body to a block first, with the
`ensureBlockBody` step the postcondition path has used since GROOVY-12084, so
the implicit return becomes explicit and the invariant is checked before each
return. The fallback remains only for a method without a body.
Tests: seven new tests in `SimpleClassInvariantTests` (forwarders returning
a primitive and an object, a void forwarder, a forwarder that violates the
invariant, the class's own method beside forwarders, trait property accessors,
and a `@Synchronized` method with an explicit return). Four of them fail on
master with the null returns; the `groovy-contracts` module passes with the fix
(403 tests).
> groovy-contracts: a class invariant makes the trait forwarders and trait
> property accessors of the class return null
> --------------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12742
> URL: https://issues.apache.org/jira/browse/GROOVY-12742
> Project: Groovy
> Issue Type: Bug
> Components: groovy-contracts
> Affects Versions: 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> h3. Problem
> A class-level {{@Invariant}} on a class that implements a trait makes every
> method the trait contributes return {{null}}; a primitive return fails with a
> cast exception:
> {code:groovy}
> import groovy.contracts.*
> trait Named {
> String name = 'x'
> String greet() { "hi $name" }
> int one() { 1 }
> }
> @Invariant({ count >= 0 })
> class Counter implements Named {
> int count
> }
> def c = new Counter()
> assert c.greet() == 'hi x' // greet() returns null
> c.one() // GroovyCastException: Cannot cast 'null' to
> class 'int'
> {code}
> Trait properties are affected too ({{getSize()}} of a trait property {{int
> size}} fails the same way). The interface equivalent, where the class writes
> the method bodies itself, is fine. Reproduced on Groovy 6.0.0 and on master
> (df1fe66ed1).
> h3. Cause
> {{ClassInvariantGenerator.addInvariantAssertionStatement}} weaves the
> invariant call before each {{return}} only when the method body is a block.
> The forwarders and property accessors that {{TraitComposer}} generates in the
> implementing class have a bare expression or return statement as body, so the
> generator fell back to appending the (void) invariant call after it, and the
> forwarder's implicit return value was lost. The same fallback left a
> {{@Synchronized}} body unwrapped, so an explicit {{return}} inside it skipped
> the invariant.
> h3. Fix
> Normalise the body to a block first (the {{ensureBlockBody}} step the
> postcondition path already performs since GROOVY-12084), so the implicit
> return is made explicit and the invariant is checked before each return.
> Trait forwarders and property accessors keep their values and are checked;
> the {{@Synchronized}} explicit-return case is checked as well. Pull request
> to follow.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)