Skip to content

Commit

Permalink
Add support for extend self to handle_module_operation (#2855)
Browse files Browse the repository at this point in the history
By adding the instance methods as class methods through the
singleton mixin operations, we are able to get all instance
methods "copied" over into the class methods implicitly.

I don't think it's necessary to test whether this extend self
applies when the module is opened after being closed again,
or re-opened in another file.

Closes #2782
  • Loading branch information
tlemburg authored Nov 19, 2024
1 parent 4770fdb commit a3ed380
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 9 deletions.
24 changes: 15 additions & 9 deletions lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -751,16 +751,22 @@ def handle_module_operation(node, operation)
return unless arguments

arguments.each do |node|
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)

case operation
when :include
owner.mixin_operations << Entry::Include.new(node.full_name)
when :prepend
owner.mixin_operations << Entry::Prepend.new(node.full_name)
when :extend
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode) ||
(node.is_a?(Prism::SelfNode) && operation == :extend)

if node.is_a?(Prism::SelfNode)
singleton = @index.existing_or_new_singleton_class(owner.name)
singleton.mixin_operations << Entry::Include.new(node.full_name)
singleton.mixin_operations << Entry::Include.new(owner.name)
else
case operation
when :include
owner.mixin_operations << Entry::Include.new(node.full_name)
when :prepend
owner.mixin_operations << Entry::Prepend.new(node.full_name)
when :extend
singleton = @index.existing_or_new_singleton_class(owner.name)
singleton.mixin_operations << Entry::Include.new(node.full_name)
end
end
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
Prism::ConstantPathNode::MissingNodesInConstantPathError
Expand Down
32 changes: 32 additions & 0 deletions lib/ruby_indexer/test/index_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,38 @@ def test_linearizing_singleton_object
)
end

def test_extend_self
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
module Foo
def bar
end
extend self
def baz
end
end
RUBY

["bar", "baz"].product(["Foo", "Foo::<Class:Foo>"]).each do |method, receiver|
entry = @index.resolve_method(method, receiver)&.first
refute_nil(entry)
assert_equal(method, T.must(entry).name)
end

assert_equal(
[
"Foo::<Class:Foo>",
"Foo",
"Module",
"Object",
"Kernel",
"BasicObject",
],
@index.linearized_ancestors_of("Foo::<Class:Foo>"),
)
end

def test_linearizing_singleton_ancestors
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
module First
Expand Down

0 comments on commit a3ed380

Please sign in to comment.