Skip to content

Commit 81fe6a1

Browse files
committed
Enable line specifying for :callback attribute
1 parent dd48f95 commit 81fe6a1

File tree

4 files changed

+55
-6
lines changed

4 files changed

+55
-6
lines changed

lib/gradient/ast_specifier.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ defmodule Gradient.AstSpecifier do
131131
@spec mapper(form(), [token()], options()) :: {form(), [token()]}
132132
def mapper(form, tokens, opts)
133133

134-
def mapper({:attribute, anno, :spec, {name_arity, specs}}, tokens, opts) do
134+
def mapper({:attribute, anno, spec, {name_arity, specs}}, tokens, opts)
135+
when spec in [:spec, :callback] do
135136
new_specs = context_mapper_map(specs, [], opts, &spec_mapper/3)
136137

137-
{:attribute, anno, :spec, {name_arity, new_specs}}
138+
{:attribute, anno, spec, {name_arity, new_specs}}
138139
|> pass_tokens(tokens)
139140
end
140141

1.61 KB
Binary file not shown.

test/examples/typespec_beh.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
defmodule TypespecBeh do
2+
@callback vital_fun() :: %{atom() => any()}
3+
@callback non_vital_fun() :: a when a: {integer(), atom()}
4+
@macrocallback non_vital_macro(arg :: any) :: Macro.t()
5+
@optional_callbacks non_vital_fun: 0, non_vital_macro: 1
6+
end

test/gradient/ast_specifier_test.exs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ defmodule Gradient.AstSpecifierTest do
12991299

13001300
[spec | _] =
13011301
AstSpecifier.run_mappers(ast, tokens)
1302-
|> filter_specs()
1302+
|> filter_attributes(:spec)
13031303
|> Enum.reverse()
13041304

13051305
assert {:attribute, 2, :spec,
@@ -1324,12 +1324,54 @@ defmodule Gradient.AstSpecifierTest do
13241324
]}} = spec
13251325
end
13261326

1327+
test "typespec behavior" do
1328+
{tokens, ast} = load("/Elixir.TypespecBeh.beam", "/typespec_beh.ex")
1329+
1330+
[callback1, callback2 | _] =
1331+
AstSpecifier.run_mappers(ast, tokens)
1332+
|> filter_attributes(:callback)
1333+
|> Enum.reverse()
1334+
1335+
assert {:attribute, 4, :callback,
1336+
{{:"MACRO-non_vital_macro", 2},
1337+
[
1338+
{:type, 4, :fun,
1339+
[
1340+
{:type, 4, :product,
1341+
[
1342+
{:type, 4, :term, []},
1343+
{:ann_type, 4, [{:var, 4, :arg}, {:type, 4, :any, []}]}
1344+
]},
1345+
{:remote_type, 4, [{:atom, 4, Macro}, {:atom, 4, :t}, []]}
1346+
]}
1347+
]}} = callback1
1348+
1349+
assert {:attribute, 3, :callback,
1350+
{{:non_vital_fun, 0},
1351+
[
1352+
{:type, 3, :bounded_fun,
1353+
[
1354+
{:type, 3, :fun, [{:type, 3, :product, []}, {:var, 3, :a}]},
1355+
[
1356+
{:type, 3, :constraint,
1357+
[
1358+
{:atom, 3, :is_subtype},
1359+
[
1360+
{:var, 3, :a},
1361+
{:type, 3, :tuple, [{:type, 3, :integer, []}, {:type, 3, :atom, []}]}
1362+
]
1363+
]}
1364+
]
1365+
]}
1366+
]}} = callback2
1367+
end
1368+
13271369
test "typespec" do
13281370
{tokens, ast} = load("/Elixir.Typespec.beam", "/typespec.ex")
13291371

13301372
[atoms_type2, atoms_type, named_type, missing_type_arg, missing_type | _] =
13311373
AstSpecifier.run_mappers(ast, tokens)
1332-
|> filter_specs()
1374+
|> filter_attributes(:spec)
13331375
|> Enum.reverse()
13341376

13351377
assert {:attribute, 17, :spec,
@@ -1413,7 +1455,7 @@ defmodule Gradient.AstSpecifierTest do
14131455

14141456
# Helpers
14151457

1416-
def filter_specs(ast) do
1417-
Enum.filter(ast, &match?({:attribute, _, :spec, _}, &1))
1458+
def filter_attributes(ast, type) do
1459+
Enum.filter(ast, &match?({:attribute, _, ^type, _}, &1))
14181460
end
14191461
end

0 commit comments

Comments
 (0)