Scott Murphy Heiberg created GROOVY-12723:
---------------------------------------------
Summary: @Modifies with a value that is not a closure is silently
an empty frame, which ModifiesChecker then reports as violated
Key: GROOVY-12723
URL: https://issues.apache.org/jira/browse/GROOVY-12723
Project: Groovy
Issue Type: Bug
Affects Versions: 6.0.0
Reporter: Scott Murphy Heiberg
{{ModifiesASTTransformation}} rejects a bare {{@Modifies}} ("@Modifies requires
a closure listing the modifiable targets; use @Modifies({}) to declare that
nothing is modified") but accepts any other value that is not a closure in
silence: {{extractFromAnnotation}} returns when the member is not a
{{ClosureExpression}}, the frame stays empty, and {{visit}} then replaces the
member with a class reference, so the annotation verifier never sees the
original value either. With {{ModifiesChecker}} on, the method is checked
against that empty frame:
{code:groovy}
import groovy.contracts.Modifies
import groovy.transform.CompileStatic
@CompileStatic(extensions = 'groovy.typecheckers.ModifiesChecker')
class Inventory {
int stock = 0
List<String> log = []
@Modifies(['this.stock', 'this.log'])
void restock(int amount) {
stock += amount
log.add('restock ' + amount)
}
}
{code}
{noformat}
[Static type checking] - @Modifies violation: assignment to 'stock' but 'stock'
is not declared in @Modifies
{noformat}
The message says the opposite of what the source says, and without the checker
the class compiles with a frame that declares nothing. Expected: the error a
bare {{@Modifies}} gets, at the annotation, naming what was found.
A list of strings is the first thing a language model writes for this
annotation (three of three runs, with the contracts documentation summarised in
front of it, in the seventh live run of the groovyai eval). The fix is one
condition in {{visit}}: a value that is not a {{ClosureExpression}} gets the
existing message plus "; found ['this.stock', 'this.log']".
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)