Commit Graph
1 Commits
Author SHA1 Message Date
rajatnagda45 7340b82812 fix(ruby): capture paren-less self-send calls
A receiver-less Ruby method call written without parentheses — the most
common call form in idiomatic Ruby — was dropped from the call graph:

    def run
      build      # a method call on self
    end

Tree-sitter parses that `build` as a bare `identifier`, structurally
identical to a local-variable read (`x`). The call-walk only inspected
`call` nodes, so `build(1)`, `self.build` and `build arg` all produced a
`calls` edge while the bare `build` produced nothing. A whole module of
mutually-calling helpers could end up with no internal edges at all.

The Ruby resolver already had a dedicated bare-call promotion path, but it
had nothing to promote because extraction never produced the call.

Fix: mirror Ruby's own disambiguation rule — a bare identifier is a send on
`self` unless a local or parameter of that name is in scope. `_ruby_local_names`
collects the bound names of a method body (parameters, assignments, block
params, `for` variables, `rescue` captures); a bare identifier not among them
is routed through the normal callee path as a non-member call, resolving
in-file (EXTRACTED) or becoming a raw_call the resolver can prove.

The collector is deliberately over-inclusive, so a missed binding only
suppresses a candidate call (fail-closed) rather than inventing a wrong edge.
A receiver-position send (`logger.info` where `logger` is itself a send) is
left for a follow-up and stays unresolved rather than guessed.

Added tests/test_ruby_bare_self_send_calls.py covering the self-send, the
cross-module and mixed-in cases, and the negatives (a local, a parameter and
a block parameter that shadow a method name must NOT become calls).

(cherry picked from commit c95b11c8e6)
2026-10-02 17:10:07 +01:00