[ 
https://issues.apache.org/jira/browse/GROOVY-12729?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul King updated GROOVY-12729:
-------------------------------
    Summary: groovy-contracts: loop @Invariant and @Decreases are silently 
disabled by {} or a qualified class literal; @Decreases({ [] }) can never pass; 
simple class names in loop annotations are never resolved  (was: 
groovy-contracts: @Decreases is silently disabled by {} or by a qualified class 
literal, rejects { [] } on every loop, and rejects a simple class name only 
because it is never resolved)

> groovy-contracts: loop @Invariant and @Decreases are silently disabled by {} 
> or a qualified class literal; @Decreases({ [] }) can never pass; simple class 
> names in loop annotations are never resolved
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12729
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12729
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-contracts
>            Reporter: Paul King
>            Priority: Major
>
> Probed on master (715553465f). Each loop runs 3 times. The results are the 
> same in a script and in a class method.
> h3. 1. An empty closure or a qualified class literal turns off the check
> ||Annotation on the loop||Result||
> |{{@Invariant(\{\})}}|runs; no check is made, and nothing reports that|
> |{{@Invariant(java.lang.Object)}}|runs; no check is made|
> |{{@Decreases(\{\})}}|runs; no check is made, even on a loop that does not 
> decrease|
> |{{@Decreases(java.lang.Object)}}|runs; no check is made|
> Controls: {{@Invariant(\{ i < 2 \})}} throws {{LoopInvariantViolation}}, and 
> {{@Decreases(\{ n \})}} on a loop that does not decrease throws 
> {{LoopVariantViolation: loop variant did not decrease: was 3, now 3}}.
> {{LoopInvariantASTTransformation}} and {{LoopVariantASTTransformation}} 
> return without reporting anything in either case: when the value is not a 
> closure, or when the closure has no expression.
> Class-level contracts already reject an empty closure. {{@Invariant(\{\})}} 
> on a class fails to compile with:
> {noformat}
> [groovy-contracts] Annotation does not contain any expressions (e.g. use 
> '@Requires({ argument1 })').
> {noformat}
> The loop forms should behave the same.
> h3. 2. {{@Decreases(\{ [] \})}} can never pass
> It throws {{LoopVariantViolation: loop variant did not decrease: was [], now 
> []}} on every loop that runs more than once, including one that does decrease 
> {{n}}. An empty tuple never decreases, so a compile error would be more 
> helpful.
> {{@Invariant(\{ [] \})}} also always fails, but that is correct, since an 
> empty list is false in Groovy, as with {{\{ false \}}}. Class-level 
> {{@Invariant(\{ [] \})}} behaves the same way.
> h3. 3. Simple class names in loop annotations are never resolved
> ||Annotation on the loop||Result||
> |{{@Invariant(Object)}}, {{@Decreases(Object)}}|{{Only classes, closures, and 
> method references can be used for attribute 'value' in 
> @groovy.contracts.Invariant}} (or {{Decreases}})|
> |{{@Invariant(java.lang.Object)}}, {{@Decreases(java.lang.Object)}}|compiles, 
> and is then silently ignored (see 1)|
> |{{@Invariant(Object.class)}}, {{@Decreases(Object.class)}}|{{unable to find 
> class 'Object.class' for annotation attribute constant}}|
> So the simple name is rejected only by accident. An AST probe at CONVERSION, 
> SEMANTIC_ANALYSIS and CANONICALIZATION shows the {{@Decreases(Object)}} 
> member staying a {{VariableExpression(Object)}} throughout. A qualified name 
> becomes a {{ClassExpression}} during SEMANTIC_ANALYSIS, and on a method 
> annotation, {{@Requires(Object)}} becomes a {{ClassExpression}} as expected. 
> This affects any annotation on a loop, not just contracts.
> A list value ({{@Invariant(['i < 2'])}}, {{@Decreases([1])}}) is correctly 
> rejected by the generic annotation check.
> h3. Suggested fix
> * Loop {{@Invariant}} and {{@Decreases}}: report an error for a value that is 
> not a closure, and for an empty closure, as class-level contracts do. Also 
> report one for {{@Decreases(\{ [] \})}}.
> * Resolve class names in loop-statement annotations the same way as in 
> declaration annotations (possibly a separate issue).
> Related: GROOVY-12128 (where loop contract checks fire), GROOVY-12723 
> (@Modifies), and the issue raised alongside this one (class literals on 
> @Requires, @Ensures and @Invariant).



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

Reply via email to