Skip to content

fix(cpp): correct args counting for operator() and constructors with initializer-lists - #2275

Merged
squid-protocol merged 3 commits into
mainfrom
fix/cpp-2012-args-counting
Aug 26, 2026
Merged

fix(cpp): correct args counting for operator() and constructors with initializer-lists#2275
squid-protocol merged 3 commits into
mainfrom
fix/cpp-2012-args-counting

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Summary

Fixes #2012. Two distinct, independently-diagnosed bugs in C++ args counting:

Pattern 1 (zero-undercount): operator() and out-of-class methods with non-whitelisted parameter types (e.g. mlir::ModuleOp) reported args=0. Root cause was two-fold: (a) the regex-based args extraction rejects operator() syntax and enforces a rigid parameter-type whitelist, silently defaulting to 0 on failure; (b) the structural fallback counter needed to skip operator()'s own empty name-parens to find the real parameter-list parens.

Pattern 2 (off-by-one overcount): a zero-arg constructor with a member-initializer-list (Ctor() : member(x) { }) reported args=1 -- the args-search text swept the initializer-list clause into the parameter-list search, misreading member(x) as a parameter.

Fix

  • Truncate the args-search text at the first top-level : (excluding ::) before the opening brace, cutting the initializer-list clause out of the search entirely (Pattern 2).
  • Fall back to the structural _count_top_level_args counter for c/cpp when the regex path fails, since func_start already validated it's a real function (Pattern 1a).
  • Skip operator()'s own empty name-parens in that structural counter to find the real parameter list (Pattern 1b).

Both fixes gated to lang_id/primary_lang_id in ("c", "cpp"). The common case (real params + initializer list) is unaffected.

Evidence

Case Before After
operator()(a, b) 0 2
Out-of-class BuildBuffer(mlir::ModuleOp module) 0 1
Zero-arg ctor with member-initializer-list 1 0
Ctor with real params + initializer-list (common case) 2 2 (unchanged)

Corpus-wide: args_exact_match improved from 1233 to 1295 (out of 1296/1297 comparable functions).

Known minor limitation

The operator() detection uses an 8-character trailing substring match (args_str[open_idx-8:open_idx] == "operator") without a word-boundary check. An identifier ending in ...operator( with no separator before it (e.g. a hypothetical custom_operator(...)) could theoretically false-positive and skip a real first parameter list. No such case was found in the ~80-repo corpus; flagging for awareness rather than blocking on it.

Verification

  • pytest tests/core_engine/test_detector.py tests/extraction/languages/test_cpp.py -q -- 195 passed (1 new regression test covering both patterns + the unaffected common case)
  • audit_check.py --ci -- clean
  • crucible_check.py --mode both -- drift confined to cpp (NVDA/godot/mlir Function Analysis changes, attributable) plus expected global mass/coordinate ripple in unrelated directory groups (confirmed no Function Analysis changes outside cpp), blessed
  • tree_sitter_accuracy_audit.py --all --ci -- clean
  • tri_comparison_chart.py --all --ci -- clean

This touches shared detector.py helpers (_calculate_block_metrics, _count_top_level_args), so the full --all --ci sweep was run per repo convention.

🤖 Generated with Gemini (via agy), orchestrated and independently verified by Claude Code.

squid-protocol and others added 3 commits August 26, 2026 11:21
…initializer-lists

Two distinct, independently-diagnosed bugs in C++ args counting:

Pattern 1 (zero-undercount): operator() and out-of-class methods with
non-whitelisted parameter types (e.g. mlir::ModuleOp) reported args=0.
Root cause was two-fold: (a) _calculate_block_metrics's regex-based
args extraction rejects operator() syntax and enforces a rigid
parameter-type whitelist, silently defaulting to 0 on failure -- now
falls back to the structural _count_top_level_args counter for c/cpp
when the regex path fails, since func_start already validated this is
a real function; (b) _count_top_level_args itself needed to skip
operator()'s own empty name-parens to find the real parameter-list
parens.

Pattern 2 (off-by-one overcount): a zero-arg constructor with a
member-initializer-list (`Ctor() : member(x) { }`) reported args=1 --
_slice_by_braces's args_search_text swept the initializer-list clause
into the parameter-list search, misreading `member(x)` as a
parameter. Fixed by truncating args_search_text at the first
top-level `:` (excluding `::`) before the opening brace.

Both fixes gated to lang_id/primary_lang_id in ("c", "cpp"); the
common case (real params + initializer list) is unaffected.

Confirmed via inline synthetic repro: operator()(a,b) 0->2,
out-of-class BuildBuffer(mlir::ModuleOp) 0->1, zero-arg ctor with
init-list 1->0, normal ctor with params+init-list unchanged at 2,
operator() call-site correctly still excluded.

Closes #2012

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@squid-protocol
squid-protocol merged commit 6a0ca7c into main Aug 26, 2026
@squid-protocol
squid-protocol deleted the fix/cpp-2012-args-counting branch August 26, 2026 15:30
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.

cpp args: Zero-undercount for operator() and method definitions, off-by-one overcount for constructors with initializer-lists

1 participant