Skip to content

Commit

Permalink
handle local behaviours and protocols in returns reducer
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszsamson committed Feb 15, 2024
1 parent 63bfa55 commit d48611c
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 8 deletions.
33 changes: 27 additions & 6 deletions lib/elixir_sense/providers/suggestion/reducers/returns.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,38 @@ defmodule ElixirSense.Providers.Suggestion.Reducers.Returns do

callbacks =
for mod <- behaviours,
protocol == nil or mod != elem(protocol, 0),
return <- Introspection.get_returns_from_callback(mod, fun, arity) do
format_return(return)
protocol == nil or mod != elem(protocol, 0) do
case specs[{mod, fun, arity}] do
nil ->
for return <- Introspection.get_returns_from_callback(mod, fun, arity) do
format_return(return)
end

%State.SpecInfo{specs: info_specs} ->
for spec <- info_specs,
{:ok, {:@, _, [{_, _, [quoted]}]}} = Code.string_to_quoted(spec),
return <- Introspection.get_returns_from_spec_ast(quoted) do
format_return(return)
end
end
end
|> List.flatten()

# TODO metadata protocols and behaviours
protocol_functions =
case protocol do
{proto, _implementations} ->
for return <- Introspection.get_returns_from_callback(proto, fun, arity) do
format_return(return)
case specs[{proto, fun, arity}] do
nil ->
for return <- Introspection.get_returns_from_callback(proto, fun, arity) do
format_return(return)
end

%State.SpecInfo{specs: info_specs} ->
for spec <- info_specs,
{:ok, {:@, _, [{:callback, _, [quoted]}]}} <- [Code.string_to_quoted(spec)],
return <- Introspection.get_returns_from_spec_ast(quoted) do
format_return(return)
end
end

nil ->
Expand Down
63 changes: 61 additions & 2 deletions test/elixir_sense/suggestions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ defmodule ElixirSense.SuggestionsTest do
] = list
end

test "lists function return values" do
test "lists callback return values" do
buffer = """
defmodule MyServer do
use ElixirSenseExample.ExampleBehaviour
Expand Down Expand Up @@ -912,7 +912,7 @@ defmodule ElixirSense.SuggestionsTest do
] = list
end

test "lists macro return values" do
test "lists macrocallback return values" do
buffer = """
defmodule MyServer do
@behaviour ElixirSenseExample.BehaviourWithMacrocallback
Expand All @@ -937,6 +937,36 @@ defmodule ElixirSense.SuggestionsTest do
]
end

test "lists metadata callback return values" do
buffer = """
defmodule MyBehaviour do
@callback required(term()) :: {:ok, term()} | :error
end
defmodule MyServer do
@behaviour MyBehaviour
def required(arg) do
end
end
"""

list =
ElixirSense.suggestions(buffer, 9, 5)
|> Enum.filter(fn s -> s.type == :return end)

assert list == [
%{
description: "{:ok, term()}",
snippet: "{:ok, term()}",
spec: "{:ok, term()}",
type: :return
},
%{description: ":error", snippet: ":error", spec: ":error", type: :return}
]
end

test "lists protocol implementation return values" do
buffer = """
defimpl Enumerable, for: MyStruct do
Expand Down Expand Up @@ -966,6 +996,35 @@ defmodule ElixirSense.SuggestionsTest do
] == list
end

test "lists metadata protocol implementation return values" do
buffer = """
defprotocol MyProto do
@spec count(t()) :: {:ok, term()} | :error
def count(t)
end
defimpl MyProto, for: MyStruct do
def count(t) do
end
end
"""

list =
ElixirSense.suggestions(buffer, 8, 6)
|> Enum.filter(fn s -> s.type == :return end)

assert [
%{
description: "{:ok, term()}",
snippet: "{:ok, term()}",
spec: "{:ok, term()}",
type: :return
},
%{description: ":error", snippet: ":error", spec: ":error", type: :return}
] == list
end

test "lists function with spec return values" do
buffer = """
defmodule SomeModule do
Expand Down

0 comments on commit d48611c

Please sign in to comment.