Skip to content

Commit

Permalink
Add support for extend self to handle_module_operation
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 Shopify#2782
  • Loading branch information
tlemburg committed Nov 14, 2024
1 parent 0eaaee1 commit 23fc41b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
9 changes: 7 additions & 2 deletions lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,8 @@ 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)
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode) ||
(node.is_a?(Prism::SelfNode) && operation == :extend)

case operation
when :include
Expand All @@ -755,7 +756,11 @@ def handle_module_operation(node, operation)
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)
singleton.mixin_operations << if node.is_a?(Prism::SelfNode)
Entry::Include.new(owner.name)
else
Entry::Include.new(node.full_name)
end
end
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
Prism::ConstantPathNode::MissingNodesInConstantPathError
Expand Down
20 changes: 20 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,26 @@ 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
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 23fc41b

Please sign in to comment.