Skip to content

args counts call-site arguments in groovy (+46%): the return-type run is {0,3}, so the method arm degenerates to ^IDENT(...) #2782

Closed

Description

@squid-protocol

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

args matches 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:

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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugUnintended behavior or logic failure in the enginecore-engineModifications to the central physics and parsing enginemetricsHeuristics, risk exposures, and topological math updates

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions