Skip to content

Commit a3ed380

Browse files
authored
Add support for extend self to handle_module_operation (#2855)
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
1 parent 4770fdb commit a3ed380

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -751,16 +751,22 @@ def handle_module_operation(node, operation)
751751
return unless arguments
752752

753753
arguments.each do |node|
754-
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
755-
756-
case operation
757-
when :include
758-
owner.mixin_operations << Entry::Include.new(node.full_name)
759-
when :prepend
760-
owner.mixin_operations << Entry::Prepend.new(node.full_name)
761-
when :extend
754+
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode) ||
755+
(node.is_a?(Prism::SelfNode) && operation == :extend)
756+
757+
if node.is_a?(Prism::SelfNode)
762758
singleton = @index.existing_or_new_singleton_class(owner.name)
763-
singleton.mixin_operations << Entry::Include.new(node.full_name)
759+
singleton.mixin_operations << Entry::Include.new(owner.name)
760+
else
761+
case operation
762+
when :include
763+
owner.mixin_operations << Entry::Include.new(node.full_name)
764+
when :prepend
765+
owner.mixin_operations << Entry::Prepend.new(node.full_name)
766+
when :extend
767+
singleton = @index.existing_or_new_singleton_class(owner.name)
768+
singleton.mixin_operations << Entry::Include.new(node.full_name)
769+
end
764770
end
765771
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
766772
Prism::ConstantPathNode::MissingNodesInConstantPathError

lib/ruby_indexer/test/index_test.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,6 +1672,38 @@ def test_linearizing_singleton_object
16721672
)
16731673
end
16741674

1675+
def test_extend_self
1676+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1677+
module Foo
1678+
def bar
1679+
end
1680+
1681+
extend self
1682+
1683+
def baz
1684+
end
1685+
end
1686+
RUBY
1687+
1688+
["bar", "baz"].product(["Foo", "Foo::<Class:Foo>"]).each do |method, receiver|
1689+
entry = @index.resolve_method(method, receiver)&.first
1690+
refute_nil(entry)
1691+
assert_equal(method, T.must(entry).name)
1692+
end
1693+
1694+
assert_equal(
1695+
[
1696+
"Foo::<Class:Foo>",
1697+
"Foo",
1698+
"Module",
1699+
"Object",
1700+
"Kernel",
1701+
"BasicObject",
1702+
],
1703+
@index.linearized_ancestors_of("Foo::<Class:Foo>"),
1704+
)
1705+
end
1706+
16751707
def test_linearizing_singleton_ancestors
16761708
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
16771709
module First

0 commit comments

Comments
 (0)