diff options
author | Eric Meadows-Jönsson <eric.meadows.jonsson@gmail.com> | 2019-07-01 22:21:25 +0200 |
---|---|---|
committer | Eric Meadows-Jönsson <eric.meadows.jonsson@gmail.com> | 2019-07-01 22:28:17 +0200 |
commit | 0b59ac33bc6ce0becb2f13483e95d4c0f4d639cc (patch) | |
tree | c02da574d79b8598c8b6264e9a3c22ef1bdbbf7d | |
parent | 6482484d1207afabd5b4402ad8423ed52dc4c657 (diff) | |
download | elixir-0b59ac33bc6ce0becb2f13483e95d4c0f4d639cc.tar.gz |
Add struct deprecation check
-rw-r--r-- | lib/elixir/lib/code.ex | 6 | ||||
-rw-r--r-- | lib/elixir/lib/module/checker.ex | 46 | ||||
-rw-r--r-- | lib/elixir/src/elixir.erl | 3 | ||||
-rw-r--r-- | lib/elixir/src/elixir_expand.erl | 4 | ||||
-rw-r--r-- | lib/elixir/test/elixir/module/checker_test.exs | 68 | ||||
-rw-r--r-- | lib/mix/lib/mix/tasks/compile.elixir.ex | 4 |
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 |