Skip to content

fix(dart): count named / optional-positional parameter groups in args (#2309) - #2335

Merged
squid-protocol merged 1 commit into
mainfrom
fix-dart-args-named-param-groups-2309
Aug 27, 2026
Merged

fix(dart): count named / optional-positional parameter groups in args (#2309)#2335
squid-protocol merged 1 commit into
mainfrom
fix-dart-args-named-param-groups-2309

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Fixes #2309.

Bug

_count_top_level_args unwraps a signature's outer (...) and counts depth-0 commas in the body. For a Dart parameter list where the params sit in a named group ({a, b, c}) or an optional-positional group ([a, b]), the group's own {/[ read as ordinary nesting — every comma inside was at depth 1, so none counted.

EditableText({super.key, required this.controller, ...}) — a 91-line named-parameter constructor — measured 1 argument. _Editable, _UpdateTextSelectionAction, and ~dozens of Flutter widget constructors were similarly flattened.

(This is the args half of #2309. The func_start existence half and the bodyless this./super.-forwarding-constructor case were handled by #2071 / #2311.)

Fix

In _count_top_level_args, for primary_lang_id == "dart": when the parameter-list body ends (ignoring trailing whitespace) in } or ], find that terminal group's matching opener at depth 0 and blank just those two delimiter chars, so the group's members land at the top level and their separating commas count.

A {...}/[...] that's a default-value literal ({int x = const [1, 2, 3]}, {Map m = const {'a': 1}}) is never flush against the body's end → stays nested → internal commas stay correctly ignored. Scoped to dart; no other language's count path is touched.

Result

Name-matched gather_language("dart") args diff vs tree-sitter — GitGalaxy under-counts by ≥2 (excluding tree-sitter's own same-name reconciliation inflation) drop ~40 → 2, and both survivors are tree-sitter/reconciler quirks (build@6253 is genuinely 1 param; copyWith@theme_data:140 is a bodyless abstract method, 0). EditableText (1→76), _Editable (1→39), _UpdateTextSelectionAction (4→6) now match tree-sitter exactly.

Regenerated artifacts

file change
both golden masters 328 diffs — all dart (arg counts + downstream structural-impact / spatial-coordinate ripple); 0 non-dart content change
tree_sitter_accuracy_baseline_dart.json args_exact_match 1519 → 1633 (+114); summary table Dart row 99.4% → 99.5%
tree_sitter_accuracy_baseline_javascript.json files_scanned 18 → 17 — a stale value from #2331 (GATE D relegating threejs/Nodes.js); that workflow doesn't trigger on statistical_auditor.py paths so it was never updated. Included so this PR's own tree-sitter-accuracy-audit run (detector.py does trigger it) is green.

Verification

  • test_detector.py (+ new _count_top_level_args dart case) + tests/extraction (6234) — green
  • ruff / mypy / dead-key / ast-accuracy — clean
  • crucible_check.py — PASS both modes
  • tree_sitter_accuracy_audit --all --ci + tri_comparison_chart --all --ci — both green

🤖 Generated with Claude Code

…#2309)

`_count_top_level_args` unwraps a signature's outer `(...)` and counts
depth-0 commas in the remaining body. For a Dart parameter list whose
parameters live in a named group `({a, b, c})` or an optional-positional
group `([a, b])`, the group's own `{`/`[` was read as ordinary nesting --
so every comma inside sat at depth 1 and none counted. A Flutter widget
constructor like `EditableText({super.key, required this.controller, ...})`
measured **1** argument instead of 76; `_Editable`, `_UpdateTextSelectionAction`
and ~dozens more were similarly flattened. This is the args half of #2309
(the `func_start` existence half, and the bodyless `this.`/`super.`-forwarding
constructor case, were handled by #2071 / #2311).

Fix: in `_count_top_level_args`, for `primary_lang_id == "dart"`, when the
parameter-list body ends (ignoring trailing whitespace) in `}` or `]`,
locate that terminal group's matching opener at depth 0 and blank just those
two delimiter characters, so the group's members land at the top level and
their separating commas are counted. A `{...}` / `[...]` that is a
default-VALUE literal (`{int x = const [1, 2, 3]}`, `{Map m = const {'a': 1}}`)
is never flush against the body's end, so it stays nested and its internal
commas stay correctly ignored. Scoped to dart -- no other language's count
path is touched.

Result (name-matched `gather_language("dart")` args diff vs tree-sitter):
GitGalaxy under-counts by >=2 (excluding tree-sitter's own same-name
reconciliation inflation) drop from ~40 to 2, and those 2 are tree-sitter /
reconciler quirks, not GitGalaxy defects (`build` at editable_text.dart:6253
is genuinely 1 param; `copyWith` at theme_data.dart:140 is a bodyless
abstract method with 0). `EditableText` (1->76), `_Editable` (1->39),
`_UpdateTextSelectionAction` (4->6) now match tree-sitter exactly.

Regenerated:
- Both golden masters -- 328 diffs, all dart (arg counts + downstream
  structural-impact / spatial-coordinate ripple); 0 non-dart content change.
- `tree_sitter_accuracy_baseline_dart.json` -- `args_exact_match` 1519 -> 1633
  (+114); summary table in `language_standards.py` Dart row 99.4% -> 99.5%.
- `tree_sitter_accuracy_baseline_javascript.json` -- `files_scanned` 18 -> 17,
  a stale value left by #2331 (GATE D relegating `threejs/Nodes.js`); the
  tree-sitter-accuracy workflow doesn't trigger on statistical_auditor.py
  paths so it was never updated. Included here so this PR's own
  tree-sitter-accuracy-audit run (which `detector.py` does trigger) is green.

Verification: test_detector.py (+ new `_count_top_level_args` dart case) and
tests/extraction (6234) green; ruff/mypy/dead-key/ast-accuracy clean;
crucible_check both modes PASS; tree_sitter_accuracy_audit --all --ci and
tri_comparison_chart --all --ci both green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol
squid-protocol merged commit b81adab into main Aug 27, 2026
30 checks passed
@squid-protocol
squid-protocol deleted the fix-dart-args-named-param-groups-2309 branch August 27, 2026 17:46
squid-protocol added a commit that referenced this pull request Aug 27, 2026
…al causes (#2309) (#2342)

Explored `dart/function/args/agree[none]_vs[gitgalaxy,tree_sitter]` (106
occurrences after #2335's named-parameter-group fix, was 205). Every one was
`gg=N ts=0` or `gg=1 ts=0` -- i.e. one tool reporting a real count and the
other 0. Three distinct causes, none of them a "real" arg-count disagreement:

1. **tree-sitter ground truth wrong for const/factory constructors**
   (`tree_sitter_accuracy_audit.py::_get_param_count`, reused by the
   tri-comparison gatherer). `constant_constructor_signature`
   (`const PointerEvent({...})`) and `factory_constructor_signature`
   (`factory ThemeData({...})`) don't expose a field-tagged "parameters"
   child -- unlike the plain `constructor_signature` -- so they fell through
   to `return 0`. Every `const`/`factory` constructor in the dart corpus (the
   dominant Flutter widget-constructor form) measured 0. Added both node types
   to the direct-`formal_parameter_list`-child branch that already handles
   `function_signature`/`setter_signature`. ~30 large mismatches.

2. **GitGalaxy over-counts a paren-less getter** (`detector.py`). A bodyless
   `Offset get pan;` reached `_count_top_level_args("Offset get pan")`, which
   has no `(` to unwrap and returns 1 (whole string as one segment). The
   bodyless-`;` branch now returns 0 when `not has_parens`. ~15 mismatches.

3. **GitGalaxy under-counts operator overloads** (`detector.py`). The `args`
   regex needs `NAME(...)`; `bool operator ==(Object other)` has `==` between
   the name token and the `(`, so `.search()` returns None and the count
   falls to 0. Added dart to the same "regex failed -> structural counter"
   fallback c/cpp already use (#2012), guarded on a literal `(` in the
   signature text so a paren-less getter body still reads 0. ~12 mismatches.

Result: the args shape drops 106 -> 6, dart args accuracy 93.9% -> 99.65%,
GitGalaxy and tree-sitter now agree on 1733/1739 comparable functions.

The 6 survivors are all one unrelated shape -- a multi-line
`@Deprecated('...' '...',)` annotation that dart's `func_start` wrongly
consumes as a return-type prefix, so the annotation's own parens get counted
instead of the real parameter list. Filed separately.

Regenerated: both golden masters (26 diffs, all dart -- arg counts +
downstream ripple, 0 non-dart content change); `tree_sitter_accuracy_baseline_
dart.json` (`args_exact_match` 1633 -> 1733). No summary-table or javascript-
baseline change needed (a post-#2335 companion already refreshed the latter).

Verification: test_dart.py (+ new getter/operator slicer case) + tests/
extraction (6235) green; ruff/mypy/dead-key/ast-accuracy clean; crucible_check
both modes PASS; tree_sitter_accuracy_audit --all --ci + tri_comparison_chart
--all --ci both green.

Co-authored-by: Joe Esquibel <squid-protocol@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
squid-protocol added a commit that referenced this pull request Aug 27, 2026
#2341) (#2347)

dart's `func_start` match spans any leading `@annotation(...)` prefix and the
return-type prefix, so `start_idx` (the block start / args-span start) can
land on an annotation. When that annotation's argument list is multi-line and
carries a top-level comma -- `@Deprecated('Use x. ' 'Deprecated after v3.3.',)`
is the corpus shape -- its own `(...)` is the first paren the args counter
finds, and the declaration's real parameter list is never measured
(`ToolbarOptions` const ctor read 0 args, several deprecated getters read 1).

Fix: for dart, every args-span computation anchors at `match.start(match.
lastindex)` -- the name capture -- instead of `start_idx`. Same
`match.lastindex` name-anchor the typescript/javascript branch of
`_slice_by_braces` already uses. `start_idx` still bounds the block itself
(line numbers, body slice); only the parameter-count slice moves.

This closes out the `dart/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`
shape entirely: **0 remaining args mismatches** across the 7-file Flutter
corpus (was 205 before #2309, 106 after #2335, 6 after #2342), dart args
accuracy 99.65% -> **100.0%** (`args_exact_match` 1733 -> 1739 / 1739).

Regenerated: both golden masters (16 diffs, all dart -- arg counts + downstream
ripple, 0 non-dart content change); `tree_sitter_accuracy_baseline_dart.json`.
No summary-table or javascript-baseline change.

Verification: test_dart.py (+ new annotation-prefix slicer case) + tests/
extraction (6236) green; ruff/mypy/dead-key/ast-accuracy clean; crucible_check
both modes PASS; tree_sitter_accuracy_audit --all --ci green.

Co-authored-by: Joe Esquibel <squid-protocol@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dart args: constructor/function parameter counts read wrong (often 0) under generic-bounded class headers

1 participant