Skip to content

Commit 1f3e440

Browse files
authored
Pick most specific parent class during linearization (#3572)
1 parent c7c36e2 commit 1f3e440

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

lib/ruby_indexer/lib/ruby_indexer/index.rb

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -818,11 +818,22 @@ def linearize_superclass( # rubocop:disable Metrics/ParameterLists
818818
)
819819
# Find the first class entry that has a parent class. Notice that if the developer makes a mistake and inherits
820820
# from two different classes in different files, we simply ignore it
821-
superclass = if singleton_levels > 0
822-
self[attached_class_name]&.find { |n| n.is_a?(Entry::Class) && n.parent_class }
823-
else
824-
namespace_entries.find { |n| n.is_a?(Entry::Class) && n.parent_class }
825-
end #: as Entry::Class?
821+
possible_parents = singleton_levels > 0 ? self[attached_class_name] : namespace_entries
822+
superclass = nil #: Entry::Class?
823+
824+
possible_parents&.each do |n|
825+
# Ignore non class entries
826+
next unless n.is_a?(Entry::Class)
827+
828+
parent_class = n.parent_class
829+
next unless parent_class
830+
831+
# Always set the superclass, but break early if we found one that isn't `::Object` (meaning we found an explicit
832+
# parent class and not the implicit default). Note that when setting different parents to the same class, which
833+
# is invalid, we pick whatever is the first one we find
834+
superclass = n
835+
break if parent_class != "::Object"
836+
end
826837

827838
if superclass
828839
# If the user makes a mistake and creates a class that inherits from itself, this method would throw a stack

lib/ruby_indexer/test/index_test.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,30 @@ module A
728728
assert_equal(["A", "ALIAS"], @index.linearized_ancestors_of("A"))
729729
end
730730

731+
def test_linearizing_ancestors_for_classes_with_overridden_parents
732+
index(<<~RUBY)
733+
# Find the re-open of a class first, without specifying a parent
734+
class Child
735+
end
736+
737+
# Now, find the actual definition of the class, which includes a parent
738+
class Parent; end
739+
class Child < Parent
740+
end
741+
RUBY
742+
743+
assert_equal(
744+
[
745+
"Child",
746+
"Parent",
747+
"Object",
748+
"Kernel",
749+
"BasicObject",
750+
],
751+
@index.linearized_ancestors_of("Child"),
752+
)
753+
end
754+
731755
def test_resolving_an_inherited_method
732756
index(<<~RUBY)
733757
module Foo

0 commit comments

Comments
 (0)