Skip to content

Commit

Permalink
Do not reveal opaque type details in signature provider
Browse files Browse the repository at this point in the history
Fixes #256
  • Loading branch information
lukaszsamson committed Aug 5, 2023
1 parent ed4e2df commit d159306
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 25 deletions.
38 changes: 21 additions & 17 deletions lib/elixir_sense/core/metadata.ex
Original file line number Diff line number Diff line change
Expand Up @@ -327,24 +327,28 @@ defmodule ElixirSense.Core.Metadata do
@spec get_type_signatures(__MODULE__.t(), module, atom) :: [signature_t]
def get_type_signatures(%__MODULE__{} = metadata, module, type)
when not is_nil(module) and not is_nil(type) do
case Map.get(metadata.types, {module, type, nil}) do
nil ->
[]

%State.TypeInfo{args: args_variants} ->
for args <- args_variants do
arity = length(args)

spec = metadata.types[{module, type, arity}].specs |> Enum.join("\n")

%{
name: Atom.to_string(type),
params: args,
documentation: "",
spec: spec
}
metadata.types
|> Enum.filter(fn
{{^module, ^type, arity}, _type_info} when not is_nil(arity) -> true
_ -> false
end)
|> Enum.map(fn {_, %State.TypeInfo{} = type_info} ->
args = type_info.args |> List.last() |> Enum.join(", ")

spec =
case type_info.kind do
:opaque -> "@opaque #{type}(#{args})"
_ -> List.last(type_info.specs)
end
end

%{
name: Atom.to_string(type),
params: type_info.args |> List.last(),
# TODO extract docs
documentation: "",
spec: spec
}
end)
end

def get_docs_specs_from_behaviours(env) do
Expand Down
5 changes: 3 additions & 2 deletions lib/elixir_sense/core/type_info.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ defmodule ElixirSense.Core.TypeInfo do
type_args = Enum.map(args, &(&1 |> elem(2) |> Atom.to_string()))
type_str = Atom.to_string(type)
doc = Introspection.extract_summary_from_docs(text)
spec = get_type_spec_as_string(mod, type, arity)
typedef = get_type_spec(mod, type, arity)
spec = format_type_spec(typedef, line_length: @param_option_spec_line_length)
%{name: type_str, params: type_args, documentation: doc, spec: spec}
end

Expand All @@ -81,7 +82,7 @@ defmodule ElixirSense.Core.TypeInfo do
name: Atom.to_string(name),
params: type_args,
documentation: "",
spec: type_spec_to_string(typedef)
spec: format_type_spec(typedef)
}
end
end
Expand Down
57 changes: 51 additions & 6 deletions test/elixir_sense/signature_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,56 @@ defmodule ElixirSense.SignatureTest do
documentation: "Remote type",
name: "remote_t",
params: [],
spec: "@type remote_t :: atom"
spec: "@type remote_t() :: atom()"
},
%{
documentation: "Remote type with params",
name: "remote_t",
params: ["a", "b"],
spec: "@type remote_t(a, b) :: {a, b}"
spec: "@type remote_t(a, b) ::\n {a, b}"
}
]
}
end

test "does not reveal opaque type details" do
code = """
defmodule MyModule do
@type a :: ElixirSenseExample.ModuleWithTypespecs.Remote.some_opaque_options_t(
end
"""

assert ElixirSense.signature(code, 2, 82) == %{
active_param: 0,
signatures: [
%{
documentation: "",
name: "some_opaque_options_t",
params: [],
spec: "@opaque some_opaque_options_t()"
}
]
}
end

test "does not reveal local opaque type details" do
code = """
defmodule Some do
@opaque my(a, b) :: {a, b}
end
defmodule MyModule do
@type a :: Some.my(
end
"""

assert ElixirSense.signature(code, 5, 22) == %{
active_param: 0,
signatures: [
%{
documentation: "",
name: "my",
params: ["a", "b"],
spec: "@opaque my(a, b)"
}
]
}
Expand All @@ -145,7 +188,7 @@ defmodule ElixirSense.SignatureTest do
documentation: "",
name: "some_type_doc_false",
params: ~c"",
spec: "@type some_type_doc_false :: integer"
spec: "@type some_type_doc_false() :: integer()"
}
]
}
Expand Down Expand Up @@ -175,7 +218,7 @@ defmodule ElixirSense.SignatureTest do
documentation: summary,
name: "time_unit",
params: [],
spec: "@type time_unit ::" <> _
spec: "@type time_unit() ::" <> _
}
]
} = ElixirSense.signature(code, 2, 32)
Expand Down Expand Up @@ -593,7 +636,8 @@ defmodule ElixirSense.SignatureTest do
end
"""

# TODO?
# TODO https://github.com/elixir-lsp/elixir_sense/issues/255
# Type system needs to handle function captures
assert ElixirSense.signature(code, 3, 20) == :none
end

Expand All @@ -605,7 +649,8 @@ defmodule ElixirSense.SignatureTest do
end
"""

# TODO?
# TODO https://github.com/elixir-lsp/elixir_sense/issues/255
# Type system needs to handle function captures
assert ElixirSense.signature(code, 3, 20) == :none
end

Expand Down

0 comments on commit d159306

Please sign in to comment.