Repository navigation
args counts call-site arguments in groovy (+46%): the return-type run is {0,3}, so the method arm degenerates to ^IDENT(...) #2782
Description
Found by the 46-language audit in docs/args_rule_contract.md, written for #2773. Same defect
#2773 fixed in typescript, in the same rule, on the same corpus pass (2026-09-05).
The contract
argsmatches the parameters a callable declares. A call site consumes a parameter
surface; it does not publish one.
Measured
keyword-rosetta/data/groovy, args against func_start, over the code stream:
| file | func_start |
args |
the extra hits |
|---|---|---|---|
a.groovy |
3 | 4 | assertEquals(kit, kit) |
c.groovy |
3 | 5 | close(conn), dispose(conn) |
main.groovy |
4 | 7 | probeBranch(argv), probeIo(argv), probeRisk(argv) |
| total | 13 | 19 (+46%) | 6 call sites |
language-crucible/data/groovy: 2193 args against 883 func_start (a/f 2.48).
Every extra hit is a call, and each is a probe the SPEC planted for a different signal --
assertEquals is test, close/dispose are cleanup. So groovy's args total scales with
how many calls its shell happens to contain, not with its declared parameter surface.
The cause
"args": re.compile(
r"^[ \t]*(?:(?:public|private|protected|static|final|def|abstract|@[A-Za-z0-9_.]+(?:\([^)]*\))?)[ \t\n]+){0,10}"
r"(?:(?:(?:void|int|long|…|boolean)(?:\[\])?|[a-zA-Z_][a-zA-Z0-9_<>\[\]?,\.]*)[ \t]+){0,3}" # <-- {0,3}
r"(?!(?:if|for|while|switch|catch|synchronized)\b)([A-Za-z_$][\w_$]*|…)[ \t\n]*(\((?:[^()]|\([^()]*\))*\))|…"The return-type run is {0,3} and the modifier run is {0,10}, both able to match zero times, so
the whole first alternative degenerates to ^[ \t]*IDENT(...) -- which is equally the shape of a
bare call statement. Groovy makes this worse than Java's version of the same rule because def
means a method genuinely can have no return type at all.
Suggested shape
Two precedents already in the tree, either of which fits:
java/csharp(same C-family, same rule): the return type is mandatory in the method arm,
and the constructor arm is anchored to{/throwsinstead.javascript/typescript(args counts call-site arguments in objective-c (+62%) and typescript: a coupling signal that scales with how many calls a file makes #2773): anchor on what FOLLOWS the parameter list -- a Groovy method
body is always{, so a(?=[ \t\n]*\{)lookahead is available and is whatjavascript's own
class-member arm already uses.
The def-less, return-type-less form (probeBranch(flag) { … }) is reachable by the second but
not the first, so the lookahead is probably the right one here.
Corpus pairing
args is planted at 13 (one parameter per probe, SPEC.md). keyword-rosetta/data/groovy needs no
authoring change -- the fix should land it on 13 exactly, the mechanical check that the anchor is
right and not merely narrower.
Part of #2669 (rosetta[groovy] tracking issue).
Activity
fix(core-engine): args counts declared parameters, not call sites (ob…
fix(core-engine): args counts declared parameters, not call sites (ob…
fix(core-engine): args counts declared parameters, not call sites (ob…
docs(args-contract): correct two audit findings that keyword-rosetta …