From 876f1663c046aec88d3c389fa6e2e1be57b2e5f5 Mon Sep 17 00:00:00 2001 From: sarah kate Date: Mon, 27 Nov 2023 13:43:52 -0500 Subject: [PATCH] Fix suggestions when using typespecs returning a remote type (#282) As shown in the following code: ``` defmodule Mod do @spec fun() :: NaiveDateTime.t() def fun(), do: NaiveDateTime.new(1, 2) def some do var = fun() var.h # ^ suggestion here end end ``` It should be able to suggest from NaiveDateTime. This wasn't working before because the `__aliases__` weren't being handled: ``` iex(1)> Code.string_to_quoted("@spec fun() :: NaiveDateTime.t()") {:ok, {:@, [line: 1], [ {:spec, [line: 1], [ {:"::", [line: 1], [ {:fun, [line: 1], []}, {{:., [line: 1], [{:__aliases__, [line: 1], [:NaiveDateTime]}, :t]}, [line: 1], []} ]} ]} ]}} ``` --- lib/elixir_sense/core/binding.ex | 7 +++++++ test/elixir_sense/suggestions_test.exs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/elixir_sense/core/binding.ex b/lib/elixir_sense/core/binding.ex index e57a3dad..b3c750ee 100644 --- a/lib/elixir_sense/core/binding.ex +++ b/lib/elixir_sense/core/binding.ex @@ -1191,6 +1191,13 @@ defmodule ElixirSense.Core.Binding do expand_type(env, mod, atom, args, false) end + # remote user type + defp parse_type(env, {{:., _, [{:__aliases__, _, aliases}, atom]}, _, args}, _mod, _include_private) + when is_atom(atom) do + # do not propagate include_private when expanding remote types + expand_type(env, Module.concat(aliases), atom, args, false) + end + # no_return defp parse_type(_env, {:no_return, _, _}, _, _include_private), do: :none diff --git a/test/elixir_sense/suggestions_test.exs b/test/elixir_sense/suggestions_test.exs index 475f8fba..58ac56a0 100644 --- a/test/elixir_sense/suggestions_test.exs +++ b/test/elixir_sense/suggestions_test.exs @@ -3173,6 +3173,24 @@ defmodule ElixirSense.SuggestionsTest do ] = list end + test "suggest struct fields when metadata function evaluates to remote type" do + buffer = """ + defmodule Mod do + @spec fun() :: NaiveDateTime.t() + def fun(), do: NaiveDateTime.new(1, 2) + + def some do + var = fun() + var.h + end + end + """ + + list = ElixirSense.suggestions(buffer, 7, 10) + + assert [%{name: "hour", origin: "NaiveDateTime"}] = list + end + test "suggest struct fields when variable is struct" do buffer = """ defmodule Abc do