Skip to content

Commit

Permalink
Avoid removing redundant namespaces when not inside correct nesting (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock authored Oct 15, 2024
1 parent c47c0b6 commit e400005
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 16 deletions.
26 changes: 10 additions & 16 deletions lib/ruby_indexer/lib/ruby_indexer/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -980,29 +980,23 @@ def inherited_constant_completion_candidates(name, nesting)
# nesting
sig { params(name: String, nesting: T::Array[String]).returns(String) }
def build_non_redundant_full_name(name, nesting)
# If there's no nesting, then we can just return the name as is
return name if nesting.empty?

namespace = nesting.join("::")

# If the name is not qualified, we can just concatenate the nesting and the name
return "#{namespace}::#{name}" unless name.include?("::")
return "#{nesting.join("::")}::#{name}" unless name.include?("::")

name_parts = name.split("::")
first_redundant_part = nesting.index(name_parts[0])

# Find the first part of the name that is not in the nesting
index = name_parts.index { |part| !nesting.include?(part) }
# If there are no redundant parts between the name and the nesting, then the full name is both combined
return "#{nesting.join("::")}::#{name}" unless first_redundant_part

if index.nil?
# All parts of the nesting are redundant because they are already present in the name. We can return the name
# directly
name
elsif index == 0
# No parts of the nesting are in the name, we can concatenate the namespace and the name
"#{namespace}::#{name}"
else
# The name includes some parts of the nesting. We need to remove the redundant parts
"#{namespace}::#{T.must(name_parts[index..-1]).join("::")}"
end
# Otherwise, push all of the leading parts of the nesting that aren't redundant into the name. For example, if we
# have a reference to `Foo::Bar` inside the `[Namespace, Foo]` nesting, then only the `Foo` part is redundant, but
# we still need to include the `Namespace` part
T.unsafe(name_parts).unshift(*nesting[0...first_redundant_part])
name_parts.join("::")
end

sig do
Expand Down
89 changes: 89 additions & 0 deletions lib/ruby_indexer/test/index_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1934,5 +1934,94 @@ module Namespace
real_namespace = @index.follow_aliased_namespace("Namespace::Second")
assert_equal("First::Second", real_namespace)
end

def test_resolving_alias_to_non_existing_namespace
index(<<~RUBY)
module Namespace
class Foo
module InnerNamespace
Constants = Namespace::Foo::Constants
end
end
end
RUBY

entry = @index.resolve("Constants", ["Namespace", "Foo", "InnerNamespace"])&.first
assert_instance_of(Entry::UnresolvedConstantAlias, entry)

entry = @index.resolve("Namespace::Foo::Constants", ["Namespace", "Foo", "InnerNamespace"])&.first
assert_nil(entry)
end

def test_resolving_alias_to_existing_constant_from_inner_namespace
index(<<~RUBY)
module Parent
CONST = 123
end
module First
module Namespace
class Foo
include Parent
module InnerNamespace
Constants = Namespace::Foo::CONST
end
end
end
end
RUBY

entry = @index.resolve("Namespace::Foo::CONST", ["First", "Namespace", "Foo", "InnerNamespace"])&.first
assert_equal("Parent::CONST", entry.name)
assert_instance_of(Entry::Constant, entry)
end

def test_build_non_redundant_name
assert_equal(
"Namespace::Foo::Constants",
@index.send(
:build_non_redundant_full_name,
"Namespace::Foo::Constants",
["Namespace", "Foo", "InnerNamespace"],
),
)

assert_equal(
"Namespace::Foo::Constants",
@index.send(
:build_non_redundant_full_name,
"Namespace::Foo::Constants",
["Namespace", "Foo"],
),
)

assert_equal(
"Namespace::Foo::Constants",
@index.send(
:build_non_redundant_full_name,
"Foo::Constants",
["Namespace", "Foo"],
),
)

assert_equal(
"Bar::Namespace::Foo::Constants",
@index.send(
:build_non_redundant_full_name,
"Namespace::Foo::Constants",
["Bar"],
),
)

assert_equal(
"First::Namespace::Foo::Constants",
@index.send(
:build_non_redundant_full_name,
"Namespace::Foo::Constants",
["First", "Namespace", "Foo", "InnerNamespace"],
),
)
end
end
end

0 comments on commit e400005

Please sign in to comment.