Skip to content

Commit

Permalink
Support the scenario where descendants and the target have the same n…
Browse files Browse the repository at this point in the history
…ame.

When their names are the same, we can only judge when adjusting the range, and using a `match?` to filter would be safer and more accurate.
  • Loading branch information
scottming committed Dec 9, 2023
1 parent fb9ce6f commit da6b905
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ defmodule Lexical.RemoteControl.CodeIntelligence.Rename do
defp search_related_candidates(document, position, entity, range) do
cursor_entity_string = cursor_entity_string(range)

entities =
exacts(entity, cursor_entity_string)
entities = exacts(entity, cursor_entity_string)

# Users won't always want to rename descendants of a module.
# For instance, when there are no more submodules after the cursor.
Expand Down Expand Up @@ -116,7 +115,9 @@ defmodule Lexical.RemoteControl.CodeIntelligence.Rename do
defp adjust_range(entries, entity) do
for entry <- entries,
uri = Document.Path.ensure_uri(entry.path),
{:ok, range} = resolve_entity_range(uri, entry.range.start, entity) do
range_result = resolve_entity_range(uri, entry.range.start, entity),
match?({:ok, _}, range_result) do
{_, range} = range_result
%{entry | range: range}
end
end
Expand All @@ -125,15 +126,21 @@ defmodule Lexical.RemoteControl.CodeIntelligence.Rename do
with {:ok, _} <- Document.Store.open_temporary(uri),
{:ok, document, analysis} <- Document.Store.fetch(uri, :analysis),
{:ok, result, range} <- resolve_module(analysis, position) do
if result == entity do
{:ok, range}
else
last_part_length = result |> last_part() |> String.length()
# Move the cursor to the next part:
# `|Parent.Next.Target.Child` -> 'Parent.|Next.Target.Child' -> 'Parent.Next.|Target.Child'
character = position.character + last_part_length + 1
position = Position.new(document, position.line, character)
resolve_entity_range(uri, position, entity)
cond do
result == entity ->
{:ok, range}

not has_dots_in_name?(entity) ->
# When the descendant entry name is the same as the target
:error

true ->
last_part_length = result |> last_part() |> String.length()
# Move the cursor to the next part:
# `|Parent.Next.Target.Child` -> 'Parent.|Next.Target.Child' -> 'Parent.Next.|Target.Child'
character = position.character + last_part_length + 1
position = Position.new(document, position.line, character)
resolve_entity_range(uri, position, entity)
end
else
_ ->
Expand All @@ -142,6 +149,10 @@ defmodule Lexical.RemoteControl.CodeIntelligence.Rename do
end
end

defp has_dots_in_name?(entity) do
entity |> inspect() |> String.contains?(".")
end

defp last_part(entity) when is_atom(entity) do
entity
|> inspect()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,25 @@ defmodule Lexical.RemoteControl.CodeIntelligence.RenameTest do
assert result =~ ~S[defmodule TopLevel.Foo.Renamed do]
assert result =~ ~S[alias TopLevel.Foo.Renamed]
end

test "succeeds even if there are descendants with the same name" do
{:ok, result} =
~q[
defmodule TopLevel.Foo do
defmodule Foo do # skip this
end
end
defmodule TopLevel.Bar do
alias TopLevel.|Foo.Foo
end
]
|> rename("Renamed")

assert result =~ ~S[defmodule TopLevel.Renamed do]
assert result =~ ~S[defmodule Foo do # skip this]
assert result =~ ~S[alias TopLevel.Renamed.Foo]
end
end

describe "rename struct" do
Expand Down

0 comments on commit da6b905

Please sign in to comment.