Skip to content

fix: Symbol.parameters/return_type extraction for Kotlin and Dart - #41

Open
pradeepmouli wants to merge 2 commits into
intuit:mainfrom
pradeepmouli:fix/symbol-parameters-kotlin-dart
Open

fix: Symbol.parameters/return_type extraction for Kotlin and Dart#41
pradeepmouli wants to merge 2 commits into
intuit:mainfrom
pradeepmouli:fix/symbol-parameters-kotlin-dart

Conversation

@pradeepmouli

Copy link
Copy Markdown
Contributor

Summary

Symbol.parameters/return_type are populated at tree-sitter extraction time via extract_child_text(node, "parameters"/"return_type", source), which calls child_by_field_name. This works correctly for 11 of 14 languages this project's SCIP indexers cover, but is structurally broken for Kotlin and Dart — verified against each grammar's actual node-types.json, not assumed:

  • Kotlin: tree-sitter-kotlin-ng's function_declaration node has no parameters/return_type named fields at all — the parameter list (function_value_parameters) and return type (a bare type node) are both positional/unnamed children, structurally unreachable via child_by_field_name regardless of what field name is tried.
  • Dart: two distinct issues. Plain functions' parameters/return_type live one level down on a nested function_signature node (reached via function_declaration's signature: field), not on the captured node directly. Methods are worse — method_signature has zero named fields at all, so parameters is unreachable there for any method. Constructors already work correctly (constructor_signature has direct name+parameters fields) and are unaffected.

Fix

Extended extract_entities's existing capture-name-keyed extraction idiom (already used for docstring/decorator/route.* fields in crates/infigraph-core/src/extract/entities.rs) with two new optional capture names: @func.params/@method.params and @func.return_type/@method.return_type. When a language's .scm query provides these, they're preferred over the existing child_by_field_name fallback; when a language doesn't provide them (the other 11+ languages), the fallback is used exactly as before — zero behavior change for anything already working.

Wired up for Kotlin and Dart via their own .scm files (crates/infigraph-languages/languages/{kotlin,dart}/entities.scm) — no Rust code specific to either grammar, and no changes to any other language.

One non-obvious gotcha hit and fixed during Dart's implementation: tree-sitter's query matcher is field-order-sensitive across sibling field-qualified patterns in a single query — it matches in the same relative order the fields are written in the query text. Dart's actual grammar (function_signature) declares return_type before name/parameters syntactically; declaring the query in the more intuitive name → parameters → return_type order silently drops the return_type capture with zero error output. The landed .scm uses return_type → name → parameters, matching the grammar's real order, with an explicit comment explaining why — verified directly against tree-sitter-dart 0.2.0's grammar.js.

Test plan

  • cargo test -p infigraph-core --lib extract::entities — 44/44 pass (34 pre-existing + 2 new Kotlin + 3 new Dart, incl. a constructor regression guard)
  • cargo fmt --all -- --check — clean
  • cargo clippy -p infigraph-core --all-targets -- -D warnings — clean
  • Verified end-to-end against real indexed Kotlin and Dart samples via a locally-built CLI

🤖 Generated with Claude Code

Symbol.parameters/return_type were empty for all Kotlin functions.
Root cause, verified against tree-sitter-kotlin-ng's real
node-types.json: function_declaration has no "parameters" or
"return_type"/"result" named fields at all -- the parameter list
(function_value_parameters) and the return type (a bare `type` node)
are both positional children, structurally unreachable via
child_by_field_name regardless of what field-name string is tried.

Extended extract_entities's existing capture-name-keyed extraction
idiom (already used for docstring/decorator/route.* fields) with two
new optional captures, @func.params/@method.params and
@func.return_type/@method.return_type, preferred over the existing
field-name fallback when a language's query provides them. Wired up
for Kotlin only in this commit -- zero changes to any other grammar,
whose queries simply never provide these captures, so the fallback
preserves their exact current behavior (regression-covered by the
pre-existing Python parameters/return_type tests still passing
unchanged).
Symbol.parameters/return_type were empty for all Dart functions and
methods. Root cause, verified against tree-sitter-dart's real
node-types.json: function_signature genuinely has "parameters"/
"return_type" named fields, but they live one level below the
captured @func.def/@method.def node (through function_declaration's
"signature" field for plain functions), so extract_child_text's
direct child_by_field_name lookup on the outer node never sees them.
For methods specifically it's worse -- method_signature has zero
named fields at all, so there's no field-name path to the answer
regardless of nesting depth, not just a wrong-node problem.

Uses the @func.params/@method.params/@func.return_type/@method.return_type
capture mechanism added for Kotlin in the previous commit -- this
commit is .scm-only, no further Rust changes. Constructor signatures
already worked via their own direct name+parameters fields and are
unchanged, covered by a dedicated regression test.

Field order in both the .scm patterns and the unit tests' inline
queries is return_type/name/parameters, matching tree-sitter-dart's
actual child order (return_type: (type) appears before name: and
parameters: in the concrete tree) -- discovered empirically while
debugging: tree-sitter's query matcher is order-sensitive across
sibling field-qualified patterns even when each is field-name
qualified, so declaring them in a different order (as in the
original plan's tests) silently drops the return_type capture with
no error, just a None result.
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