Skip to content

Commit b2afe05

Browse files
authored
Fix infinite recursion in constant alias resolution (Shopify#3783)
* Fix infinite recursion in constant alias resolution * Address comment * Address issue * Fix offences
1 parent aadbf01 commit b2afe05

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

lib/ruby_indexer/lib/ruby_indexer/index.rb

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,10 @@ def follow_aliased_namespace(name, seen_names = [])
424424
(parts.length - 1).downto(0) do |i|
425425
current_name = parts[0..i] #: as !nil
426426
.join("::")
427-
entry = @entries[current_name]&.first
427+
428+
entry = unless seen_names.include?(current_name)
429+
@entries[current_name]&.first
430+
end
428431

429432
case entry
430433
when Entry::ConstantAlias
@@ -1023,11 +1026,19 @@ def build_non_redundant_full_name(name, nesting)
10231026
name_parts.join("::")
10241027
end
10251028

1029+
# Tries to return direct entry from index then non seen canonicalized alias or nil
10261030
#: (String full_name, Array[String] seen_names) -> Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias]?
10271031
def direct_or_aliased_constant(full_name, seen_names)
1028-
entries = @entries[full_name] || @entries[follow_aliased_namespace(full_name)]
1032+
if (entries = @entries[full_name])
1033+
return entries.map do |e|
1034+
e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e
1035+
end #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias])?
1036+
end
1037+
1038+
aliased = follow_aliased_namespace(full_name, seen_names)
1039+
return if full_name == aliased || seen_names.include?(aliased)
10291040

1030-
entries&.map do |e|
1041+
@entries[aliased]&.map do |e|
10311042
e.is_a?(Entry::UnresolvedConstantAlias) ? resolve_alias(e, seen_names) : e
10321043
end #: as Array[Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias])?
10331044
end

lib/ruby_indexer/test/index_test.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,29 @@ class Foo
11521152
assert_equal(2, foo_entry.location.start_line)
11531153
end
11541154

1155+
def test_resolving_self_referential_constant_alias
1156+
index(<<~RUBY)
1157+
module A
1158+
module B
1159+
class C
1160+
end
1161+
end
1162+
end
1163+
1164+
module A
1165+
module D
1166+
B = B::C
1167+
end
1168+
end
1169+
RUBY
1170+
1171+
entry = @index.resolve("A::D::B", [])&.first #: as Entry::ConstantAlias
1172+
1173+
assert_kind_of(RubyIndexer::Entry::ConstantAlias, entry)
1174+
assert_equal(10, entry.location.start_line)
1175+
assert_equal("A::B::C", entry.target)
1176+
end
1177+
11551178
def test_resolving_qualified_references
11561179
index(<<~RUBY)
11571180
module Namespace

0 commit comments

Comments
 (0)