Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(completions): correctly accumulate variables in <- expressions #424

Merged
merged 1 commit into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/next_ls/helpers/ast_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ defmodule NextLS.ASTHelpers do
|> Zipper.zip()
|> Zipper.find(fn
{:@, _, [{:__cursor__, _, []}]} -> true
{:__cursor__, _, []} -> true
{:__cursor__, _, _} -> true
{{:., _, [_, :__cursor__]}, _, _} -> true
_ -> false
end) do
Expand Down
20 changes: 14 additions & 6 deletions lib/next_ls/helpers/ast_helpers/env.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ defmodule NextLS.ASTHelpers.Env do
alias Sourceror.Zipper

defp inside?(range, position) do
Sourceror.compare_positions(range.start, position) == :lt && Sourceror.compare_positions(range.end, position) == :gt
Sourceror.compare_positions(range.start, position) in [:lt, :eq] &&
Sourceror.compare_positions(range.end, position) in [:gt, :eq]
end

def build(nil) do
Expand Down Expand Up @@ -40,21 +41,28 @@ defmodule NextLS.ASTHelpers.Env do

Map.update!(acc, :variables, &(vars ++ &1))

{match_op, _, [pm | _]} when match_op in [:<-] ->
{match_op, _, [pm | rhs]} when match_op in [:<-] ->
up_node = zipper |> Zipper.up() |> Zipper.node()

# in_match operator comes with for and with normally, so we need to
# check if we are inside the parent node, which is the for/with
is_inside =
with {_, _, _} <- up_node,
range when not is_nil(range) <- Sourceror.get_range(up_node) do
is_inside_p =
with {_, _, _} <- up_node, range when not is_nil(range) <- Sourceror.get_range(up_node) do
inside?(range, position)
else
_ ->
false
end

if is_inside do
is_inside_rhs =
with range when not is_nil(range) <- Sourceror.get_range(rhs) do
inside?(range, position)
else
_ ->
false
end

if is_inside_p and not is_inside_rhs do
{_, vars} =
Macro.prewalk(pm, [], fn node, acc ->
case node do
Expand Down
69 changes: 69 additions & 0 deletions test/next_ls/completions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ defmodule NextLS.CompletionsTest do
end
end

defmacrop assert_match({:not, _, [{:in, _, [left, right]}]}) do
quote do
refute Enum.any?(unquote(right), fn x ->
match?(unquote(left), x)
end),
"""
found a match inside of list, expected none

left: #{unquote(Macro.to_string(left))}
right: #{inspect(unquote(right), pretty: true)}
"""
end
end

@moduletag tmp_dir: true, root_paths: ["my_proj"]

setup %{tmp_dir: tmp_dir} do
Expand Down Expand Up @@ -482,4 +496,59 @@ defmodule NextLS.CompletionsTest do
%{"data" => _, "documentation" => _, "insertText" => "capture_log", "kind" => 3, "label" => "capture_log/2"} in results
)
end

test "completions inside generator rhs", %{client: client, foo: foo} do
uri = uri(foo)

did_open(client, foo, """
defmodule Foo do
def run() do
var = "hi"

for thing <- v do
end

end
end
""")

request client, %{
method: "textDocument/completion",
id: 2,
jsonrpc: "2.0",
params: %{
textDocument: %{
uri: uri
},
position: %{
line: 4,
character: 18
}
}
}

assert_result 2, [
%{
"data" => nil,
"documentation" => "",
"insertText" => "var",
"kind" => 6,
"label" => "var"
},
%{
"data" => nil,
"documentation" => _,
"insertText" => "var!",
"kind" => 3,
"label" => "var!/1"
},
%{
"data" => nil,
"documentation" => _,
"insertText" => "var!",
"kind" => 3,
"label" => "var!/2"
}
]
end
end
44 changes: 44 additions & 0 deletions test/next_ls/helpers/ast_helpers/env_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,50 @@ defmodule NextLS.ASTHelpers.EnvTest do

assert actual.variables == ["entries"]
end

test "comprehension lhs of generator do not leak into rhs " do
code = """
defmodule Foo do
def one(entries) do
for entry <- entries,
not_me <- __cursor__() do
:ok
end
end

def two do
baz = :bar
end
end
"""

actual = run(code)

assert actual.variables == ["entries", "entry"]
end

test "multiple generators and filters in comprehension" do
code = """
defmodule Foo do
def one(entries) do
for entry <- entries,
foo = do_something(),
bar <- foo do
__cursor__()
:ok
end
end

def two do
baz = :bar
end
end
"""

actual = run(code)

assert actual.variables == ["entries", "entry", "foo", "bar"]
end
end

defp run(code) do
Expand Down