diff --git a/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb b/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb index c9a0f309d3..1fc6255687 100644 --- a/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +++ b/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb @@ -685,9 +685,12 @@ def list_params(parameters_node) keyword_rest = parameters_node.keyword_rest - if keyword_rest.is_a?(Prism::KeywordRestParameterNode) + case keyword_rest + when Prism::KeywordRestParameterNode keyword_rest_name = parameter_name(keyword_rest) || Entry::KeywordRestParameter::DEFAULT_NAME parameters << Entry::KeywordRestParameter.new(name: keyword_rest_name) + when Prism::ForwardingParameterNode + parameters << Entry::ForwardingParameter.new end parameters_node.posts.each do |post| diff --git a/lib/ruby_indexer/lib/ruby_indexer/entry.rb b/lib/ruby_indexer/lib/ruby_indexer/entry.rb index 5bbf9e2b05..4841a9f628 100644 --- a/lib/ruby_indexer/lib/ruby_indexer/entry.rb +++ b/lib/ruby_indexer/lib/ruby_indexer/entry.rb @@ -302,6 +302,17 @@ def decorated_name end end + # A forwarding method parameter, e.g. `def foo(...)` + class ForwardingParameter < Parameter + extend T::Sig + + sig { void } + def initialize + # You can't name a forwarding parameter, it's always called `...` + super(name: :"...") + end + end + class Member < Entry extend T::Sig extend T::Helpers diff --git a/lib/ruby_indexer/test/method_test.rb b/lib/ruby_indexer/test/method_test.rb index 82ef2c5ca7..266ceb35e1 100644 --- a/lib/ruby_indexer/test/method_test.rb +++ b/lib/ruby_indexer/test/method_test.rb @@ -330,6 +330,33 @@ def bar(**nil) assert_empty(parameters) end + def test_methods_with_argument_forwarding + index(<<~RUBY) + class Foo + def bar(...) + end + + def baz(a, ...) + end + end + RUBY + + entry = T.must(@index["bar"].first) + assert_instance_of(Entry::Method, entry, "Expected `bar` to be indexed") + + parameters = entry.signatures.first.parameters + assert_equal(1, parameters.length) + assert_instance_of(Entry::ForwardingParameter, parameters.first) + + entry = T.must(@index["baz"].first) + assert_instance_of(Entry::Method, entry, "Expected `baz` to be indexed") + + parameters = entry.signatures.first.parameters + assert_equal(2, parameters.length) + assert_instance_of(Entry::RequiredParameter, parameters[0]) + assert_instance_of(Entry::ForwardingParameter, parameters[1]) + end + def test_keeps_track_of_method_owner index(<<~RUBY) class Foo