Skip to content

Commit e9f764d

Browse files
committed
provide definition when cursor is on spec or callback
1 parent 6dbb617 commit e9f764d

File tree

2 files changed

+117
-4
lines changed

2 files changed

+117
-4
lines changed

apps/language_server/lib/language_server/providers/definition/locator.ex

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ defmodule ElixirLS.LanguageServer.Providers.Definition.Locator do
1313
"""
1414

1515
alias ElixirSense.Core.Binding
16-
alias ElixirSense.Core.Introspection
16+
require ElixirSense.Core.Introspection, as: Introspection
1717
alias ElixirSense.Core.Metadata
1818
alias ElixirSense.Core.State
1919
alias ElixirSense.Core.State.ModFunInfo
2020
alias ElixirSense.Core.Source
2121
alias ElixirSense.Core.SurroundContext
2222
alias ElixirLS.LanguageServer.Location
2323
alias ElixirSense.Core.Parser
24-
alias ElixirSense.Core.State.{ModFunInfo, TypeInfo}
24+
alias ElixirSense.Core.State.{ModFunInfo, TypeInfo, SpecInfo}
2525

2626
alias ElixirLS.LanguageServer.Plugins.Phoenix.Scope
2727
alias ElixirSense.Core.Normalized.Code, as: NormalizedCode
@@ -240,8 +240,29 @@ defmodule ElixirLS.LanguageServer.Providers.Definition.Locator do
240240
context.begin,
241241
true
242242
) do
243-
{_, _, false, _} ->
244-
nil
243+
{_, f, false, _} ->
244+
module = env.module
245+
{line, column} = context.end
246+
call_arity = Metadata.get_call_arity(metadata, env.module, f, line, column) || :any
247+
248+
Enum.find_value(metadata.specs, fn
249+
{{^module, ^f, a}, spec_info = %SpecInfo{}} ->
250+
if Introspection.matches_arity?(a, call_arity) do
251+
{{line, column}, {end_line, end_column}} = Location.info_to_range(spec_info)
252+
253+
%Location{
254+
file: nil,
255+
type: :spec,
256+
line: line,
257+
column: column,
258+
end_line: end_line,
259+
end_column: end_column
260+
}
261+
end
262+
263+
_ ->
264+
nil
265+
end)
245266

246267
{mod, fun, true, :mod_fun} ->
247268
{line, column} = context.end

apps/language_server/test/providers/definition/locator_test.exs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,24 @@ defmodule ElixirLS.LanguageServer.Providers.Definition.LocatorTest do
13431343
}
13441344
end
13451345

1346+
test "find definition of local functions on definition" do
1347+
buffer = """
1348+
defmodule MyModule do
1349+
def my_fun(abc), do: Asd.ASd
1350+
# ^
1351+
end
1352+
"""
1353+
1354+
assert Locator.definition(buffer, 2, 8) == %Location{
1355+
type: :function,
1356+
file: nil,
1357+
line: 2,
1358+
column: 3,
1359+
end_line: 2,
1360+
end_column: 31
1361+
}
1362+
end
1363+
13461364
test "find definition of local functions with default args" do
13471365
buffer = """
13481366
defmodule MyModule do
@@ -1877,6 +1895,80 @@ defmodule ElixirLS.LanguageServer.Providers.Definition.LocatorTest do
18771895
Locator.definition(buffer, 5, 28)
18781896
end
18791897

1898+
test "find definition of local type on definition" do
1899+
buffer = """
1900+
defmodule MyModule do
1901+
@type my_fun(abc) :: :ok
1902+
# ^
1903+
end
1904+
"""
1905+
1906+
assert Locator.definition(buffer, 2, 10) == %Location{
1907+
type: :typespec,
1908+
file: nil,
1909+
line: 2,
1910+
column: 3,
1911+
end_line: 2,
1912+
end_column: 27
1913+
}
1914+
end
1915+
1916+
test "find definition of local spec on definition" do
1917+
buffer = """
1918+
defmodule MyModule do
1919+
@spec my_fun(abc()) :: :ok
1920+
# ^
1921+
def my_fun(abc), do: :ok
1922+
end
1923+
"""
1924+
1925+
assert Locator.definition(buffer, 2, 10) == %Location{
1926+
type: :spec,
1927+
file: nil,
1928+
line: 2,
1929+
column: 3,
1930+
end_line: 2,
1931+
end_column: 29
1932+
}
1933+
end
1934+
1935+
test "find definition of local spec with guard on definition" do
1936+
buffer = """
1937+
defmodule MyModule do
1938+
@spec my_fun(abc) :: :ok when abc: atom()
1939+
# ^
1940+
def my_fun(abc), do: :ok
1941+
end
1942+
"""
1943+
1944+
assert Locator.definition(buffer, 2, 10) == %Location{
1945+
type: :spec,
1946+
file: nil,
1947+
line: 2,
1948+
column: 3,
1949+
end_line: 2,
1950+
end_column: 44
1951+
}
1952+
end
1953+
1954+
test "find definition of local callback on definition" do
1955+
buffer = """
1956+
defmodule MyModule do
1957+
@callback my_fun(abc) :: :ok
1958+
# ^
1959+
end
1960+
"""
1961+
1962+
assert Locator.definition(buffer, 2, 14) == %Location{
1963+
type: :spec,
1964+
file: nil,
1965+
line: 2,
1966+
column: 3,
1967+
end_line: 2,
1968+
end_column: 31
1969+
}
1970+
end
1971+
18801972
test "find metadata type for the correct arity - on type definition" do
18811973
buffer = """
18821974
defmodule MyModule do

0 commit comments

Comments
 (0)