summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2019-07-01 22:21:25 +0200
committerEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2019-07-01 22:28:17 +0200
commit0b59ac33bc6ce0becb2f13483e95d4c0f4d639cc (patch)
treec02da574d79b8598c8b6264e9a3c22ef1bdbbf7d
parent6482484d1207afabd5b4402ad8423ed52dc4c657 (diff)
downloadelixir-0b59ac33bc6ce0becb2f13483e95d4c0f4d639cc.tar.gz
Add struct deprecation check
-rw-r--r--lib/elixir/lib/code.ex6
-rw-r--r--lib/elixir/lib/module/checker.ex46
-rw-r--r--lib/elixir/src/elixir.erl3
-rw-r--r--lib/elixir/src/elixir_expand.erl4
-rw-r--r--lib/elixir/test/elixir/module/checker_test.exs68
-rw-r--r--lib/mix/lib/mix/tasks/compile.elixir.ex4
6 files changed, 45 insertions, 86 deletions
diff --git a/lib/elixir/lib/code.ex b/lib/elixir/lib/code.ex
index aaa793a99..b71e73c0a 100644
--- a/lib/elixir/lib/code.ex
+++ b/lib/elixir/lib/code.ex
@@ -38,7 +38,7 @@ defmodule Code do
:warnings_as_errors
]
- @list_compiler_options [:no_warn_undefined, :no_warn_deprecated]
+ @list_compiler_options [:no_warn_undefined]
@available_compiler_options @boolean_compiler_options ++ @list_compiler_options
@@ -914,10 +914,6 @@ defmodule Code do
at compilation time. This can be useful when doing dynamic compilation.
Defaults to `[]`.
- * `:no_warn_deprecated` - list of modules and `{Mod, fun, arity}` tuples
- that will not emit warnings that a function within the module or the
- specific function is deprecated. Defaults to `[]`.
-
It returns the new map of compiler options.
## Examples
diff --git a/lib/elixir/lib/module/checker.ex b/lib/elixir/lib/module/checker.ex
index dd9343b6a..b8d4ca777 100644
--- a/lib/elixir/lib/module/checker.ex
+++ b/lib/elixir/lib/module/checker.ex
@@ -31,38 +31,44 @@ defmodule Module.Checker do
end
end
- defp check_clause({_meta, _args, _guards, body}, state) do
- check_body(body, state)
+ defp check_clause({_meta, args, _guards, body}, state) do
+ [check_expr(args, state), check_expr(body, state)]
end
# &Mod.fun/arity
- defp check_body({:&, meta, [{:/, _, [{{:., dot_meta, [module, fun]}, _, []}, arity]}]}, state)
+ defp check_expr({:&, meta, [{:/, _, [{{:., _, [module, fun]}, _, []}, arity]}]}, state)
when is_atom(module) and is_atom(fun) do
- check_remote(module, fun, arity, meta ++ dot_meta, state)
+ check_remote(module, fun, arity, meta, state)
end
# Mod.fun(...)
- defp check_body({{:., meta, [module, fun]}, call_meta, args}, state)
+ defp check_expr({{:., meta, [module, fun]}, _, args}, state)
when is_atom(module) and is_atom(fun) do
- check_remote(module, fun, length(args), meta ++ call_meta, state)
+ check_remote(module, fun, length(args), meta, state)
+ end
+
+ # %Module{...}
+ defp check_expr({:%, meta, [module, {:%{}, _meta, args}]}, state)
+ when is_atom(module) and is_list(args) do
+ [check_remote(module, :__struct__, 0, meta, state), check_expr(args, state)]
end
# Function call
- defp check_body({left, _meta, right}, state) when is_list(right) do
- [check_body(right, state), check_body(left, state)]
+ defp check_expr({left, _meta, right}, state) when is_list(right) do
+ [check_expr(right, state), check_expr(left, state)]
end
# {x, y}
- defp check_body({left, right}, state) do
- [check_body(right, state), check_body(left, state)]
+ defp check_expr({left, right}, state) do
+ [check_expr(right, state), check_expr(left, state)]
end
# [...]
- defp check_body(list, state) when is_list(list) do
- Enum.map(list, &check_body(&1, state))
+ defp check_expr(list, state) when is_list(list) do
+ Enum.map(list, &check_expr(&1, state))
end
- defp check_body(_other, _state) do
+ defp check_expr(_other, _state) do
[]
end
@@ -80,7 +86,7 @@ defmodule Module.Checker do
exports = exports_for(module)
warn(meta, state, {:undefined_function, module, fun, arity, exports})
- (reason = deprecated(module, fun, arity)) && warn_deprecated?(module, fun, arity, state) ->
+ reason = deprecated_reason(module, fun, arity) ->
warn(meta, state, {:deprecated, module, fun, arity, reason})
true ->
@@ -95,23 +101,15 @@ defmodule Module.Checker do
defp warn_undefined?(:erlang, :andalso, 2, _state), do: false
defp warn_undefined?(module, fun, arity, state) do
- warn_compile_opts?(module, fun, arity, state.compile_opts, :no_warn_undefined)
- end
-
- defp warn_deprecated?(module, fun, arity, state) do
- warn_compile_opts?(module, fun, arity, state.compile_opts, :no_warn_deprecated)
- end
-
- defp warn_compile_opts?(module, fun, arity, compile_opts, option) do
for(
- {^option, values} <- compile_opts,
+ {:no_warn_undefined, values} <- state.compile_opts,
value <- List.wrap(values),
value == module or value == {module, fun, arity},
do: :skip
) == []
end
- defp deprecated(module, fun, arity) do
+ defp deprecated_reason(module, fun, arity) do
if function_exported?(module, :__info__, 1) do
case List.keyfind(module.__info__(:deprecated), {fun, arity}, 0) do
{_key, reason} -> reason
diff --git a/lib/elixir/src/elixir.erl b/lib/elixir/src/elixir.erl
index b7237314a..99bdb3445 100644
--- a/lib/elixir/src/elixir.erl
+++ b/lib/elixir/src/elixir.erl
@@ -57,8 +57,7 @@ start(_Type, _Args) ->
debug_info => true,
warnings_as_errors => false,
relative_paths => true,
- no_warn_undefined => [],
- no_warn_deprecated => []
+ no_warn_undefined => []
},
{ok, [[Home] | _]} = init:get_argument(home),
diff --git a/lib/elixir/src/elixir_expand.erl b/lib/elixir/src/elixir_expand.erl
index 0b5700dd7..adea4a684 100644
--- a/lib/elixir/src/elixir_expand.erl
+++ b/lib/elixir/src/elixir_expand.erl
@@ -527,8 +527,8 @@ expand_fn_capture(Meta, Arg, E) ->
{{remote, Remote, Fun, Arity}, EE} ->
is_atom(Remote) andalso
elixir_lexical:record_remote(Remote, Fun, Arity, ?key(E, function), ?line(Meta), ?key(E, lexical_tracker)),
- DotMeta = attach_context_module(Remote, [], E),
- {{'&', Meta, [{'/', [], [{{'.', DotMeta, [Remote, Fun]}, [], []}, Arity]}]}, EE};
+ AttachedMeta = attach_context_module(Remote, Meta, E),
+ {{'&', AttachedMeta, [{'/', [], [{{'.', [], [Remote, Fun]}, [], []}, Arity]}]}, EE};
{{local, Fun, Arity}, #{function := nil}} ->
form_error(Meta, E, ?MODULE, {undefined_local_capture, Fun, Arity});
{{local, Fun, Arity}, EE} ->
diff --git a/lib/elixir/test/elixir/module/checker_test.exs b/lib/elixir/test/elixir/module/checker_test.exs
index 4bc2e76a4..68626f374 100644
--- a/lib/elixir/test/elixir/module/checker_test.exs
+++ b/lib/elixir/test/elixir/module/checker_test.exs
@@ -419,7 +419,7 @@ defmodule Module.CheckerTest do
end
describe "deprecated" do
- test "reports deprecated functions" do
+ test "reports functions" do
files = %{
"a.ex" => """
defmodule A do
@@ -438,66 +438,34 @@ defmodule Module.CheckerTest do
assert_warnings(files, warning)
end
- # test "reports deprecated structs" do
- # files = %{
- # "a.ex" => """
- # defmodule A do
- # @deprecated "oops"
- # defstruct [:x, :y]
- # def match(%A{}), do: :ok
- # def build(:ok), do: %A{}
- # end
- # """,
- # "b.ex" => """
- # defmodule B do
- # def match(%A{}), do: :ok
- # def build(:ok), do: %A{}
- # end
- # """
- # }
- #
- # warning = """
- # """
- #
- # assert_warnings(files, warning)
- # end
-
- test "excludes specified modules and MFAs" do
+ test "reports structs" do
files = %{
"a.ex" => """
defmodule A do
- @compile {:no_warn_deprecated, [DeprecatedModule, {DeprecatedModule2, :func, 2}]}
-
- def a, do: DeprecatedModule.func(1)
- def b, do: DeprecatedModule2.func(1, 2)
- def c, do: DeprecatedModule2.func(1)
- def d, do: DeprecatedModule3.func(1, 2)
+ @deprecated "oops"
+ defstruct [:x, :y]
+ def match(%A{}), do: :ok
+ def build(:ok), do: %A{}
end
""",
- "deprecated_modules.ex" => """
- defmodule DeprecatedModule do
- @deprecated "message"
- def func(_), do: :ok
- end
- defmodule DeprecatedModule2 do
- @deprecated "message"
- def func(_), do: :ok
- @deprecated "message"
- def func(_, _), do: :ok
- end
- defmodule DeprecatedModule3 do
- @deprecated "message"
- def func(_, _), do: :ok
+ "b.ex" => """
+ defmodule B do
+ def match(%A{}), do: :ok
+ def build(:ok), do: %A{}
end
"""
}
warning = """
- warning: DeprecatedModule2.func/1 is deprecated. message
- a.ex:6: A.c/0
+ warning: A.__struct__/0 is deprecated. oops
+ Found at 2 locations:
+ a.ex:4: A.match/1
+ a.ex:5: A.build/1
- warning: DeprecatedModule3.func/2 is deprecated. message
- a.ex:7: A.d/0
+ warning: A.__struct__/0 is deprecated. oops
+ Found at 2 locations:
+ b.ex:2: B.match/1
+ b.ex:3: B.build/1
"""
diff --git a/lib/mix/lib/mix/tasks/compile.elixir.ex b/lib/mix/lib/mix/tasks/compile.elixir.ex
index 56518c49d..08dc46b6c 100644
--- a/lib/mix/lib/mix/tasks/compile.elixir.ex
+++ b/lib/mix/lib/mix/tasks/compile.elixir.ex
@@ -90,9 +90,7 @@ defmodule Mix.Tasks.Compile.Elixir do
if exclude == [] do
opts
else
- opts
- |> Keyword.update(:no_warn_undefined, exclude, &(List.wrap(&1) ++ exclude))
- |> Keyword.update(:no_warn_deprecated, exclude, &(List.wrap(&1) ++ exclude))
+ Keyword.update(opts, :no_warn_undefined, exclude, &(List.wrap(&1) ++ exclude))
end
end
end