fix(parser): extract Ruby method calls as CALLS edges#681
Open
beagleknight wants to merge 1 commit into
Open
Conversation
Ruby produced zero CALLS edges. Its grammar reuses the `call` node type for both `require`/`require_relative` and ordinary method invocation, and the dispatcher checked imports before calls and always `continue`d — so every Ruby `call` was consumed by the import branch and method calls were silently dropped. Even when reached, `_get_call_name` had no Ruby case, so member calls yielded no name. - `_extract_imports` now returns whether it emitted an import edge; the dispatcher only skips call extraction when an import was actually produced, so non-import `call` nodes fall through to call handling. - `_get_call_name` handles Ruby `call`/`method_call` via the node's `method` field, covering paren calls (`save(user)`), command calls (`puts ...`) and member calls (`User.new`, `@users.size`). Same-file/same-class calls now resolve to the defining method node, so callers_of/callees_of work within a file. Bare implicit-self calls with no parens parse as `identifier` (not `call`) and remain out of scope (future work: a Sorbet-backed resolver for typed cross-file resolution). Adds TestRubyParsing::test_finds_calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(parser): extract Ruby method calls as CALLS edges
Problem
Ruby produces zero
CALLSedges —callers_of,callees_of, impact radius,and caller-based dead-code are all blind on Ruby codebases. Definitions parse fine
(classes/methods/
CONTAINS), but the call graph is empty.Reproduce on any Ruby repo:
query callers_of helper→ 0 results.Root cause
Two issues in
parser.py:callnodetype for both
require/require_relativeand ordinary method invocation._extract_from_treechecks import node types before call node types andcontinues unconditionally, so every Rubycallis consumed by the importbranch (which only emits an edge when the text contains
require) and neverreaches call extraction.
_get_call_name. Even when acallnode is reached, therewas no Ruby handling, so member calls (
User.new,@users.size) produced nocall name and no edge.
Fix
_extract_importsnow returnsbool(whether it emitted an import edge). Thedispatcher only skips call extraction when an import was actually produced, so
non-import
callnodes fall through to call handling. This is a generalimprovement for any grammar that overloads a node type for imports and calls.
_get_call_namehandles Rubycall/method_callvia the node'smethodfield,covering paren calls (
save(user)), command calls (puts ...), and member calls(
User.new,@users.size).Result
Same-file / same-class calls resolve to the defining method node, so
callers_of/callees_ofwork within a file:Scope / limitations
Bar.new.run→run) remain bare, exactlylike the existing behavior for unresolved JS/TS calls. Precise typed resolution for
Ruby is best handled by a follow-up Sorbet-backed resolver (analogous to the
existing
jedi/Spring resolvers).helper) parse asidentifierrather than
call, so they are not captured here (also a Sorbet-resolver concern —it can disambiguate a send from a local variable).
Tests
tests/test_multilang.py::TestRubyParsing::test_finds_calls(fails onmainwith 0 CALLS; passes with this change).
ruff checkclean.