Skip to content

fix(extract): scan every attribute_list sibling, not just the first (#1692) - #1759

Open
Jumaga2015 wants to merge 2 commits into
DeusData:mainfrom
Jumaga2015:fix/1692-csharp-multi-attribute-decorates
Open

fix(extract): scan every attribute_list sibling, not just the first (#1692)#1759
Jumaga2015 wants to merge 2 commits into
DeusData:mainfrom
Jumaga2015:fix/1692-csharp-multi-attribute-decorates

Conversation

@Jumaga2015

Copy link
Copy Markdown

Summary

  • Addresses C#: log calls inside Kafka-consumer classes misclassified as Route nodes; ASP.NET Core [Route]/[HttpGet] attribute routes not extracted (cross-repo-intelligence returns 0 edges) #1692 (Repro 2 — the ASP.NET route-extraction half, not the Kafka
    misclassification half, which is a separate call-resolution defect left
    for its own atomic fix as requested in the issue thread): a C# method or
    class with 2+ stacked attributes only got a DECORATES edge for the
    first bracket group. find_jvm_modifiers() used
    ts_node_child_by_field_name(), which returns only the first matching
    child, so a route attribute stacked behind another one (e.g.
    [ServiceFilter(...)] then [Route("api/[controller]")]) was silently
    invisible to references/symbols and to route extraction.
  • find_jvm_modifiers() now returns every matching wrapper via a new
    cbm_find_children_by_kind() helper; both callers (extract_decorators,
    scan_route_annotations) iterate all of them.
  • C#-only: Java/Kotlin/Swift use the modifiers wrapper (never repeats);
    PHP already groups a stack under one attribute_list.

Test plan

  • repro_issue1692 (Makefile.cbm TEST_REPRO_SRCS) — indexes
    [Foo][Bar("x")][Baz] through the real production pipeline and
    asserts DECORATES == 3. Proven RED with the pre-fix lookup
    (decorates=1), GREEN with the fix.
  • scripts/test.sh CC=clang CXX=clang++ — full suite, no regressions
  • scripts/lint.sh CC=clang CXX=clang++ — clang-tidy (diff-scoped),
    clang-format, cppcheck all clean

Made with Claude Code

A C# attribute stack ([Foo][Bar][Baz]) compiles to separate sibling
attribute_list nodes, one per bracket group — not one attribute_list holding
several entries. find_jvm_modifiers() used ts_node_child_by_field_name(),
which only ever returns the first child registered under a given field, so
every attribute after the first bracket group was silently dropped and never
produced a DECORATES edge (DeusData#1692).

find_jvm_modifiers() now returns every matching wrapper (count + out array,
capped at MAX_ATTR_WRAPPERS) instead of a single TSNode, and its two callers
(extract_decorators, scan_route_annotations) iterate all of them. The
multi-match child scan lives in a new helper, cbm_find_children_by_kind()
(helpers.c/helpers.h), the multi-match sibling of the existing
cbm_find_child_by_kind() — keeps find_jvm_modifiers() a short per-language
dispatch that delegates the traversal, same shape it had before this fix.

Both callers size `wrappers` at MAX_ATTR_WRAPPERS. scan_route_annotations
appends the owner node after the wrappers, so its fill is capped one lower
(MAX_ATTR_WRAPPERS_MINUS_1) rather than the array being declared one larger
— the MAX_X / MAX_X_MINUS_1 pair this file already uses for MAX_BASES,
MAX_PARAMS and MAX_RETURN_TYPES.

No-op for the other languages on this switch: Java/Kotlin/Swift use the
`modifiers` wrapper, a single node that never repeats, and PHP groups a
`#[A] #[B] #[C]` stack under ONE attribute_list holding three
attribute_group children, which the previous lookup already returned whole.

Signed-off-by: Jumaga2015 <jumaga2015@gmail.com>
A C# method carrying three stacked attributes ([Foo][Bar("x")][Baz]) must
end up with three DECORATES edges, one per bracket group. The fixture is
indexed through the real production pipeline (rh_index) and asserts
rh_count_edges(..., "DECORATES") == 3, so it exercises the MCP path rather
than the extractor in isolation.

Verified to actually reproduce: with find_jvm_modifiers() reverted to its
first-child lookup the suite goes red (decorates=1, expected 3), and green
again with the fix in place.

C#-only by design. Parsing the equivalent fixtures with the vendored
grammars shows `[A] [B] [C]` yields three sibling `attribute_list` nodes in
C#, while PHP's `#[A] #[B] #[C]` yields ONE `attribute_list` holding three
`attribute_group` children — the pre-fix lookup already found all of them,
so PHP could not hit this bug and a stacked-PHP fixture would pass either
way. Java/Kotlin/Swift use the `modifiers` wrapper, a single node that never
repeats. PHP's DECORATES path stays covered by mkc_c3_php8_attribute
(tests/test_matrix_known_classes.c).

Registered in repro_main.c and Makefile.cbm's TEST_REPRO_SRCS.

Signed-off-by: Jumaga2015 <jumaga2015@gmail.com>
@Jumaga2015
Jumaga2015 requested a review from DeusData as a code owner August 20, 2026 09:35
@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

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.

1 participant