Scott Murphy Heiberg created GROOVY-12697:
---------------------------------------------
Summary: RegexChecker fails inside the compiler on
Matcher.group(String) and non-constant group lookups
Key: GROOVY-12697
URL: https://issues.apache.org/jira/browse/GROOVY-12697
Project: Groovy
Issue Type: Bug
Affects Versions: 6.0.0
Reporter: Scott Murphy Heiberg
*Environment:* macOS 26.5, JDK 21.0.12 (BellSoft Liberica), Groovy 6.0.0,
6.0.1-SNAPSHOT (GROOVY_6_0_X at 7c0dcf17dd) and master (d86ea7eb85)
{{groovy.typecheckers.RegexChecker}} fails inside the compiler, with a "General
error during canonicalization" instead of a diagnostic, as soon as type-checked
code calls {{Matcher.group(String)}} on a matcher whose regex the checker has
tracked. The same happens for {{Matcher.group(int)}} with a non-constant index
and for {{matcher[0][i]}} with a non-constant index.
Reproducer ({{groovy named.groovy}}):
{code:groovy}
import java.util.regex.Matcher
@groovy.transform.TypeChecked(extensions = 'groovy.typecheckers.RegexChecker')
String level(String line) {
Matcher m = line =~ /(?<level>INFO|WARN|ERROR)/
m.find() ? m.group('level') : 'none'
}
println level('2026-11-04 WARN disk low')
{code}
Actual output (identical on 6.0.0, 6.0.1-SNAPSHOT and master; the line number
is from 6.0.0):
{noformat}
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during canonicalization: Cannot get property 'value' on null
object
java.lang.NullPointerException: Cannot get property 'value' on null object
at
org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:99)
at
groovy.typecheckers.RegexChecker$2.visitMethodCallExpression(RegexChecker.groovy:290)
at
org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:103)
...
at
groovy.typecheckers.RegexChecker$_run_closure4.doCall(RegexChecker.groovy:261)
...
at
org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.afterVisitMethod(GroovyTypeCheckingExtensionSupport.java:427)
at
org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.visitMethod(StaticTypeCheckingVisitor.java:3651)
1 error
{noformat}
Expected: the script compiles and prints {{WARN}}. Without the extension it
does.
Variants, all with the same {{@TypeChecked(extensions =
'groovy.typecheckers.RegexChecker')}}:
||variant||6.0.0 / 6.0.1-SNAPSHOT / master||
|{{m.group('level')}}, regex {{/(?<level>INFO\|WARN\|ERROR)/}} via
{{=~}}|compiler failure (above)|
|{{m.group('level')}}, regex {{/(?<lvl>INFO\|WARN\|ERROR)/}} (no group named
level)|compiler failure; a diagnostic would be expected|
|{{m.group('level')}}, regex {{/INFO\|WARN\|ERROR/}} (no groups at
all)|compiler failure; a diagnostic would be expected|
|{{m.group('level')}}, {{Pattern.compile(...).matcher(line)}}|compiler failure|
|{{m.group('level')}}, {{Pattern p = ~/.../; p.matcher(line)}}|compiler failure|
|{{m.group(idx)}} with {{int idx}} a parameter|compiler failure|
|{{m[0][idx]}} with {{int idx}} a parameter|compiler failure|
|{{m.group('level')}} with the regex in a {{String}} parameter (not
tracked)|compiles, prints WARN|
|{{m.group(1)}}|compiles, prints WARN|
|{{m.group(2)}}|diagnostic "Invalid group count 2 for regex with 1 group"
(correct)|
Cause: in the {{afterVisitMethod}} visitor, the {{group}} check does
{{findConstExp(call.arguments.getExpression(0), Integer).value}} and the
subscript check does {{findConstExp(expression.rightExpression,
Integer).value}}. {{findConstExp}} returns null when the argument is not an
{{Integer}} constant (a {{String}} group name, a variable, a parameter, an
expression), and the {{.value}} dereference raises the NullPointerException
that the compiler reports as a general error.
Expected behaviour: a non-constant index or name is left to the runtime (no
report); {{group(String)}} with a constant name that the tracked regex does not
define is reported as a static type error, in the same way an out-of-range
constant index already is ("Invalid group count 3 for regex with 2 groups");
{{group(String)}} with a name the regex defines compiles; and the compiler
never fails.
GROOVY-12688 (null-target and null-body guards in FormatStringChecker and
RegexChecker) does not cover this path; master at d86ea7eb85, which carries it,
still fails identically. A pull request with regression tests follows.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)