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

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

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

   JIRA: [GROOVY-12692](https://issues.apache.org/jira/browse/GROOVY-12692)
   
   ### The bug
   
   With `groovy.typecheckers.FormatStringChecker` enabled, a format call whose 
arguments are not all constants is checked as if `%%` and `%n` each took an 
argument. A valid call is rejected:
   
   ```groovy
   import groovy.transform.TypeChecked
   
   @TypeChecked(extensions = 'groovy.typecheckers.FormatStringChecker')
   String show(String s) {
       String.format('100%% %s', s)
   }
   ```
   
   ```text
   [Static type checking] - MissingFormatArgument: Format specifier '%s'
   ```
   
   `java.util.Formatter` gives `%%` and `%n` no argument, so the call returns 
`100% done` for `s = 'done'`. With a constant argument the checker accepts the 
same format string. On the same path:
   
   | call | `java.util.Formatter` | checker before |
   | -

> FormatStringChecker counts %% and %n as taking an argument when the arguments 
> are not constants
> -----------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12692
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12692
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> With {{groovy.typecheckers.FormatStringChecker}} enabled, a format call whose 
> arguments are not all constants is checked as if {{%%}} and {{%n}} each took 
> an argument. A valid call is rejected.
> {{Percent.groovy}}:
> {code:groovy}
> import groovy.transform.TypeChecked
> @TypeChecked(extensions = 'groovy.typecheckers.FormatStringChecker')
> String show(String s) {
>     String.format('100%% %s', s)
> }
> assert show('done') == '100% done'
> {code}
> {code:sh}
> groovyc Percent.groovy
> {code}
> Actual: exit 1 and
> {code:text}
> org.codehaus.groovy.control.MultipleCompilationErrorsException: startup 
> failed:
> Percent.groovy: 5: [Static type checking] - MissingFormatArgument: Format 
> specifier '%s'
>  @ line 5, column 5.
>        String.format('100%% %s', s)
>        ^
> 1 error
> {code}
> Expected: the source compiles. {{java.util.Formatter}} gives {{%%}} and 
> {{%n}} no argument, so the call returns {{100% done}}. The checker accepts 
> the same format string when the argument is a constant 
> ({{String.format('100%% %s', 'done')}}).
> More calls, each in a method with a {{String s}} parameter, with {{s = 
> 'done'}} at run time:
> ||call||java.util.Formatter||FormatStringChecker||
> |{{String.format('%s%n', s)}}|returns {{done}} and a line 
> separator|MissingFormatArgument: Format specifier '%n'|
> |{{String.format('%n%s', s)}}|returns a line separator and 
> {{done}}|MissingFormatArgument: Format specifier '%s'|
> |{{String.format('%s %%', s)}}|returns {{done %}}|MissingFormatArgument: 
> Format specifier '%%'|
> |{{String.format('%s %% %s', s, s)}}|returns {{done % 
> done}}|MissingFormatArgument: Format specifier '%s'|
> |{{String.format('%s %% %<s', s)}}|returns {{done % 
> done}}|MissingFormatArgument: Format specifier '%%'|
> |{{String.format('100%% %d', s)}}|IllegalFormatConversionException: d != 
> java.lang.String|MissingFormatArgument: Format specifier '%d'|
> |{{String.format('%% %<s', s)}}|MissingFormatArgumentException: Format 
> specifier '%<s'|no error|
> |{{sprintf('%s%n', s)}}|returns {{done}} and a line 
> separator|MissingFormatArgument: Format specifier '%n'|
> The rows for {{'100%% %d'}} and {{'%% %<s'}} show the other side of the same 
> mistake: because the {{%%}} is given an argument, a real error is reported as 
> a different error, or not at all.
> Affected versions: 6.0.0, 6.0.0-beta-1, 5.0.8 and 5.0.0 reject 
> {{Percent.groovy}} the same way, and so does current master (7.0.0-SNAPSHOT 
> at 5e9212ce1e).
> Cause: when not all arguments are constants, {{checkFormatStringTypes}} 
> handles every specifier the format pattern matches as one that takes an 
> argument: it checks the index against the number of arguments, reads that 
> argument's type, and advances both the next index and the previous argument 
> that {{%<}} refers to. The {{switch}} that follows skips {{%}} and {{n}}, but 
> only after this bookkeeping. With constant arguments the checker runs 
> {{java.util.Formatter}} itself, which is why that path is right.
> Fix outline: handle {{%%}} and {{%n}} before the argument bookkeeping, 
> keeping the duplicate-flag check they already get.
> A pull request with regression tests follows.
> Environment: Groovy 6.0.0 on BellSoft JDK 21.0.12, macOS 26.5 (arm64); 
> reproduced on master at 5e9212ce1e with the same JDK.



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

Reply via email to