diff --git a/lib/sourceror/range.ex b/lib/sourceror/range.ex index 8cf6b3a..f8874c3 100644 --- a/lib/sourceror/range.ex +++ b/lib/sourceror/range.ex @@ -342,6 +342,11 @@ defmodule Sourceror.Range do get_range_for_qualified_call_with_arguments(quoted) end + # Qualified double call eg. Mod.unquote(foo)(bar) + defp do_get_range({{{:., _, _}, _, _}, _, _} = quoted) do + get_range_for_qualified_call_with_arguments(quoted) + end + # Anonymous function call with arguments defp do_get_range({{:., _, [_left]}, _meta, _args} = quoted) do get_range_for_qualified_call_with_arguments(quoted) @@ -502,6 +507,16 @@ defmodule Sourceror.Range do end end + defp get_range_for_qualified_call_with_arguments( + {{{:., _, [left | _]}, _, _}, _, args} = quoted + ) do + if Sourceror.has_closing_line?(quoted) do + get_range_for_node_with_closing_line(quoted) + else + get_range_for_pair(left, List.last(args)) + end + end + defp get_range_for_node_with_closing_line({:fn, _, _} = quoted) do start_position = Sourceror.get_start_position(quoted) end_position = Sourceror.get_end_position(quoted) @@ -511,6 +526,15 @@ defmodule Sourceror.Range do new(start_position, end_position) end + defp get_range_for_node_with_closing_line({{{:., _, [left | _]}, _, _}, _, args}) do + start_position = get_range(left).start + end_position = get_range(List.last(args) || left).end + + end_position = Keyword.update!(end_position, :column, &(&1 + 1)) + + new(start_position, end_position) + end + defp get_range_for_node_with_closing_line({_, meta, _} = quoted) do start_position = Sourceror.get_start_position(quoted) end_position = Sourceror.get_end_position(quoted) diff --git a/test/range_test.exs b/test/range_test.exs index 62aab59..a2dd06b 100644 --- a/test/range_test.exs +++ b/test/range_test.exs @@ -877,6 +877,12 @@ defmodule SourcerorTest.RangeTest do assert decorate(code, to_range(code)) == "«foo.\"b-a-r\"(1)»" end + test "qualified double calls" do + code = ~S/Mod.unquote(foo)(bar)/ + + assert decorate(code, to_range(code)) == "«Mod.unquote(foo)(bar)»" + end + test "qualified calls without parens" do code = ~S/foo.bar baz/ assert decorate(code, to_range(code)) == "«foo.bar baz»" @@ -1187,4 +1193,24 @@ defmodule SourcerorTest.RangeTest do end) end end + + describe "regressions" do + test "call with keyword :do block" do + code = ~S""" + def rpc_call(pid, call = %Call{method: unquote(method_name)}), + do: GenServer.unquote(genserver_method)(pid, call) + """ + + call = code |> Sourceror.parse_string!() + + assert %Sourceror.Range{} = range = Sourceror.Range.get_range(call) + + assert decorate(code, range) == + ~S""" + «def rpc_call(pid, call = %Call{method: unquote(method_name)}), + do: GenServer.unquote(genserver_method)(pid, call)» + """ + |> String.trim_trailing() + end + end end