summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2019-06-28 16:11:20 +0200
committerEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2019-06-28 16:11:20 +0200
commit05bf681a22bfd7f15978ec881b1a7b66bc854f5b (patch)
treed8d932266d344326a3da6dbee373acbacd373fce
parent8ab017ea1dd911c42e23c9dcfe6dbb7ba61d91c0 (diff)
downloadelixir-05bf681a22bfd7f15978ec881b1a7b66bc854f5b.tar.gz
Move deprecation check to group pass
-rw-r--r--lib/elixir/lib/code.ex6
-rw-r--r--lib/elixir/lib/module/checker.ex51
-rw-r--r--lib/elixir/src/elixir.erl3
-rw-r--r--lib/elixir/test/elixir/module/checker_test.exs689
-rw-r--r--lib/mix/lib/mix/tasks/compile.elixir.ex4
5 files changed, 438 insertions, 315 deletions
diff --git a/lib/elixir/lib/code.ex b/lib/elixir/lib/code.ex
index b71e73c0a..aaa793a99 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]
+ @list_compiler_options [:no_warn_undefined, :no_warn_deprecated]
@available_compiler_options @boolean_compiler_options ++ @list_compiler_options
@@ -914,6 +914,10 @@ 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 a9252c09a..dd9343b6a 100644
--- a/lib/elixir/lib/module/checker.ex
+++ b/lib/elixir/lib/module/checker.ex
@@ -42,9 +42,9 @@ defmodule Module.Checker do
end
# Mod.fun(...)
- defp check_body({{:., meta, [module, fun]}, _, args}, state)
+ defp check_body({{:., meta, [module, fun]}, call_meta, args}, state)
when is_atom(module) and is_atom(fun) do
- check_remote(module, fun, length(args), meta, state)
+ check_remote(module, fun, length(args), meta ++ call_meta, state)
end
# Function call
@@ -68,21 +68,21 @@ defmodule Module.Checker do
defp check_remote(module, fun, arity, meta, state) do
cond do
- not warn_if_undefined?(module, fun, arity, state) ->
- []
-
# TODO: In the future we may want to warn for modules defined
# in the local context
Keyword.get(meta, :context_module, false) and state.module != module ->
[]
- not Code.ensure_loaded?(module) ->
+ not Code.ensure_loaded?(module) and warn_undefined?(module, fun, arity, state) ->
warn(meta, state, {:undefined_module, module, fun, arity})
- not function_exported?(module, fun, arity) ->
+ not function_exported?(module, fun, arity) and warn_undefined?(module, fun, arity, state) ->
exports = exports_for(module)
warn(meta, state, {:undefined_function, module, fun, arity, exports})
+ (reason = deprecated(module, fun, arity)) && warn_deprecated?(module, fun, arity, state) ->
+ warn(meta, state, {:deprecated, module, fun, arity, reason})
+
true ->
[]
end
@@ -90,19 +90,38 @@ defmodule Module.Checker do
# TODO: Do not warn inside guards
# TODO: Properly handle protocols
- defp warn_if_undefined?(_module, :__impl__, 1, _state), do: false
- defp warn_if_undefined?(:erlang, :orelse, 2, _state), do: false
- defp warn_if_undefined?(:erlang, :andalso, 2, _state), do: false
+ defp warn_undefined?(_module, :__impl__, 1, _state), do: false
+ defp warn_undefined?(:erlang, :orelse, 2, _state), do: false
+ 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_if_undefined?(module, fun, arity, state) do
+ defp warn_compile_opts?(module, fun, arity, compile_opts, option) do
for(
- {:no_warn_undefined, values} <- state.compile_opts,
+ {^option, values} <- compile_opts,
value <- List.wrap(values),
value == module or value == {module, fun, arity},
do: :skip
) == []
end
+ defp deprecated(module, fun, arity) do
+ if function_exported?(module, :__info__, 1) do
+ case List.keyfind(module.__info__(:deprecated), {fun, arity}, 0) do
+ {_key, reason} -> reason
+ nil -> nil
+ end
+ else
+ nil
+ end
+ end
+
defp exports_for(module) do
try do
module.__info__(:macros) ++ module.__info__(:functions)
@@ -156,6 +175,14 @@ defmodule Module.Checker do
]
end
+ defp format_warning({:deprecated, module, function, arity, reason}) do
+ [
+ Exception.format_mfa(module, function, arity),
+ " is deprecated. ",
+ reason
+ ]
+ end
+
defp format_locations([location]) do
format_location(location)
end
diff --git a/lib/elixir/src/elixir.erl b/lib/elixir/src/elixir.erl
index 99bdb3445..b7237314a 100644
--- a/lib/elixir/src/elixir.erl
+++ b/lib/elixir/src/elixir.erl
@@ -57,7 +57,8 @@ start(_Type, _Args) ->
debug_info => true,
warnings_as_errors => false,
relative_paths => true,
- no_warn_undefined => []
+ no_warn_undefined => [],
+ no_warn_deprecated => []
},
{ok, [[Home] | _]} = init:get_argument(home),
diff --git a/lib/elixir/test/elixir/module/checker_test.exs b/lib/elixir/test/elixir/module/checker_test.exs
index 6a795444b..4bc2e76a4 100644
--- a/lib/elixir/test/elixir/module/checker_test.exs
+++ b/lib/elixir/test/elixir/module/checker_test.exs
@@ -11,409 +11,498 @@ defmodule Module.CheckerTest do
on_exit(fn -> Application.put_env(:elixir, :ansi_enabled, previous) end)
end
- test "handles Erlang modules" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: :not_a_module.no_module
- def b, do: :lists.no_func
- end
- """
- }
+ describe "undefined" do
+ test "handles Erlang modules" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: :not_a_module.no_module
+ def b, do: :lists.no_func
+ end
+ """
+ }
- warning = """
- warning: :not_a_module.no_module/0 is undefined (module :not_a_module is not available or is yet to be defined)
- a.ex:2: A.a/0
+ warning = """
+ warning: :not_a_module.no_module/0 is undefined (module :not_a_module is not available or is yet to be defined)
+ a.ex:2: A.a/0
- warning: :lists.no_func/0 is undefined or private
- a.ex:3: A.b/0
+ warning: :lists.no_func/0 is undefined or private
+ a.ex:3: A.b/0
- """
+ """
- assert_warnings(files, warning)
- end
+ assert_warnings(files, warning)
+ end
- test "handles module body conditionals" do
- files = %{
- "a.ex" => """
- defmodule A do
- if function_exported?(List, :flatten, 1) do
- List.flatten([1, 2, 3])
- else
- List.old_flatten([1, 2, 3])
+ test "handles module body conditionals" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ if function_exported?(List, :flatten, 1) do
+ List.flatten([1, 2, 3])
+ else
+ List.old_flatten([1, 2, 3])
+ end
+
+ if function_exported?(List, :flatten, 1) do
+ def flatten(arg), do: List.flatten(arg)
+ else
+ def flatten(arg), do: List.old_flatten(arg)
+ end
+
+ if function_exported?(List, :flatten, 1) do
+ def flatten2(arg), do: List.old_flatten(arg)
+ else
+ def flatten2(arg), do: List.flatten(arg)
+ end
end
+ """
+ }
- if function_exported?(List, :flatten, 1) do
- def flatten(arg), do: List.flatten(arg)
- else
- def flatten(arg), do: List.old_flatten(arg)
- end
+ warning = """
+ warning: List.old_flatten/1 is undefined or private. Did you mean one of:
+
+ * flatten/1
+ * flatten/2
+
+ a.ex:15: A.flatten2/1
- if function_exported?(List, :flatten, 1) do
- def flatten2(arg), do: List.old_flatten(arg)
- else
- def flatten2(arg), do: List.flatten(arg)
- end
- end
"""
- }
- warning = """
- warning: List.old_flatten/1 is undefined or private. Did you mean one of:
+ assert_warnings(files, warning)
+ end
- * flatten/1
- * flatten/2
+ test "aliases" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ alias Enum, as: E
- a.ex:15: A.flatten2/1
+ def a(a, b), do: E.map2(a, b)
+ def b, do: &E.map2/2
- """
+ @file "external_source.ex"
+ def c do
+ alias Enum, as: EE
+ &EE.map2/2
+ end
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
+ warning = """
+ warning: Enum.map2/2 is undefined or private. Did you mean one of:
- test "aliases" do
- files = %{
- "a.ex" => """
- defmodule A do
- alias Enum, as: E
+ * map/2
- def a(a, b), do: E.map2(a, b)
- def b, do: &E.map2/2
+ Found at 3 locations:
+ a.ex:4: A.a/2
+ a.ex:5: A.b/0
+ external_source.ex:10: A.c/0
- @file "external_source.ex"
- def c do
- alias Enum, as: EE
- &EE.map2/2
- end
- end
"""
- }
- warning = """
- warning: Enum.map2/2 is undefined or private. Did you mean one of:
-
- * map/2
+ assert_warnings(files, warning)
+ end
- Found at 3 locations:
- a.ex:4: A.a/2
- a.ex:5: A.b/0
- external_source.ex:10: A.c/0
+ test "reports missing functions" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: A.no_func
+ def b, do: A.a()
- """
+ @file "external_source.ex"
+ def c, do: &A.no_func/1
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
+ warning = """
+ warning: A.no_func/0 is undefined or private
+ a.ex:2: A.a/0
- test "reports missing functions" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: A.no_func
- def b, do: A.a()
+ warning: A.no_func/1 is undefined or private
+ external_source.ex:6: A.c/0
- @file "external_source.ex"
- def c, do: &A.no_func/1
- end
"""
- }
- warning = """
- warning: A.no_func/0 is undefined or private
- a.ex:2: A.a/0
+ assert_warnings(files, warning)
+ end
- warning: A.no_func/1 is undefined or private
- external_source.ex:6: A.c/0
+ test " reports missing functions respecting arity" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: :ok
+ def b, do: A.a(1)
- """
+ @file "external_source.ex"
+ def c, do: A.b(1)
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
+ warning = """
+ warning: A.a/1 is undefined or private. Did you mean one of:
- test " reports missing functions respecting arity" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: :ok
- def b, do: A.a(1)
+ * a/0
- @file "external_source.ex"
- def c, do: A.b(1)
- end
- """
- }
+ a.ex:3: A.b/0
- warning = """
- warning: A.a/1 is undefined or private. Did you mean one of:
+ warning: A.b/1 is undefined or private. Did you mean one of:
- * a/0
+ * b/0
- a.ex:3: A.b/0
+ external_source.ex:6: A.c/0
- warning: A.b/1 is undefined or private. Did you mean one of:
+ """
- * b/0
+ assert_warnings(files, warning)
+ end
- external_source.ex:6: A.c/0
+ test "reports missing modules" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: D.no_module
- """
+ @file "external_source.ex"
+ def c, do: E.no_module
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
+ warning = """
+ warning: D.no_module/0 is undefined (module D is not available or is yet to be defined)
+ a.ex:2: A.a/0
- test "reports missing modules" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: D.no_module
+ warning: E.no_module/0 is undefined (module E is not available or is yet to be defined)
+ external_source.ex:5: A.c/0
- @file "external_source.ex"
- def c, do: E.no_module
- end
"""
- }
- warning = """
- warning: D.no_module/0 is undefined (module D is not available or is yet to be defined)
- a.ex:2: A.a/0
+ assert_warnings(files, warning)
+ end
- warning: E.no_module/0 is undefined (module E is not available or is yet to be defined)
- external_source.ex:5: A.c/0
+ test "reports missing captures" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: &A.no_func/0
- """
+ @file "external_source.ex"
+ def c, do: &A.no_func/1
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
+ warning = """
+ warning: A.no_func/0 is undefined or private
+ a.ex:2: A.a/0
- test "reports missing captures" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: &A.no_func/0
+ warning: A.no_func/1 is undefined or private
+ external_source.ex:5: A.c/0
- @file "external_source.ex"
- def c, do: &A.no_func/1
- end
"""
- }
- warning = """
- warning: A.no_func/0 is undefined or private
- a.ex:2: A.a/0
+ assert_warnings(files, warning)
+ end
- warning: A.no_func/1 is undefined or private
- external_source.ex:5: A.c/0
+ test "doesn't report missing funcs at compile time" do
+ files = %{
+ "a.ex" => """
+ Enum.map([], fn _ -> BadReferencer.no_func4() end)
- """
+ if function_exported?(List, :flatten, 1) do
+ List.flatten([1, 2, 3])
+ else
+ List.old_flatten([1, 2, 3])
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
-
- test "doesn't report missing funcs at compile time" do
- files = %{
- "a.ex" => """
- Enum.map([], fn _ -> BadReferencer.no_func4() end)
+ assert_no_warnings(files)
+ end
- if function_exported?(List, :flatten, 1) do
- List.flatten([1, 2, 3])
- else
- List.old_flatten([1, 2, 3])
+ test "handles multiple modules in one file" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: B.no_func
+ def b, do: B.a
end
- """
- }
+ """,
+ "b.ex" => """
+ defmodule B do
+ def a, do: A.no_func
+ def b, do: A.b
+ end
+ """
+ }
- assert_no_warnings(files)
- end
+ warning = """
+ warning: B.no_func/0 is undefined or private
+ a.ex:2: A.a/0
+
+ warning: A.no_func/0 is undefined or private
+ b.ex:2: B.a/0
- test "handles multiple modules in one file" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: B.no_func
- def b, do: B.a
- end
- """,
- "b.ex" => """
- defmodule B do
- def a, do: A.no_func
- def b, do: A.b
- end
"""
- }
- warning = """
- warning: B.no_func/0 is undefined or private
- a.ex:2: A.a/0
+ assert_warnings(files, warning)
+ end
- warning: A.no_func/0 is undefined or private
- b.ex:2: B.a/0
+ test "groups multiple warnings in one file" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a, do: A.no_func
- """
+ @file "external_source.ex"
+ def b, do: A2.no_func
- assert_warnings(files, warning)
- end
+ def c, do: A.no_func
+ def d, do: A2.no_func
+ end
+ """
+ }
- test "groups multiple warnings in one file" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a, do: A.no_func
+ warning = """
+ warning: A2.no_func/0 is undefined (module A2 is not available or is yet to be defined)
+ Found at 2 locations:
+ a.ex:8: A.d/0
+ external_source.ex:5: A.b/0
- @file "external_source.ex"
- def b, do: A2.no_func
+ warning: A.no_func/0 is undefined or private
+ Found at 2 locations:
+ a.ex:2: A.a/0
+ a.ex:7: A.c/0
- def c, do: A.no_func
- def d, do: A2.no_func
- end
"""
- }
- warning = """
- warning: A2.no_func/0 is undefined (module A2 is not available or is yet to be defined)
- Found at 2 locations:
- a.ex:8: A.d/0
- external_source.ex:5: A.b/0
+ assert_warnings(files, warning)
+ end
- warning: A.no_func/0 is undefined or private
- Found at 2 locations:
- a.ex:2: A.a/0
- a.ex:7: A.c/0
+ test "protocols are checked, ignoring missing built-in impls" do
+ files = %{
+ "a.ex" => """
+ defprotocol AProtocol do
+ def func(arg)
+ end
- """
+ defmodule AImplementation do
+ defimpl AProtocol do
+ def func(_), do: B.no_func
+ end
+ end
+ """
+ }
- assert_warnings(files, warning)
- end
+ warning = """
+ warning: B.no_func/0 is undefined (module B is not available or is yet to be defined)
+ a.ex:7: AProtocol.AImplementation.func/1
+
+ """
- test "protocols are checked, ignoring missing built-in impls" do
- files = %{
- "a.ex" => """
- defprotocol AProtocol do
- def func(arg)
- end
+ assert_warnings(files, warning)
+ end
- defmodule AImplementation do
- defimpl AProtocol do
- def func(_), do: B.no_func
+ test "handles Erlang ops" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def a(a, b), do: a and b
+ def b(a, b), do: a or b
end
- end
- """
- }
+ """
+ }
- warning = """
- warning: B.no_func/0 is undefined (module B is not available or is yet to be defined)
- a.ex:7: AProtocol.AImplementation.func/1
+ assert_no_warnings(files)
+ end
- """
+ test "hints exclude deprecated functions" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ def to_charlist(a), do: a
- assert_warnings(files, warning)
- end
+ @deprecated "Use String.to_charlist/1 instead"
+ def to_char_list(a), do: a
- test "handles Erlang ops" do
- files = %{
- "a.ex" => """
- defmodule A do
- def a(a, b), do: a and b
- def b(a, b), do: a or b
- end
- """
- }
+ def c(a), do: A.to_list(a)
+ end
+ """
+ }
- assert_no_warnings(files)
- end
+ warning = """
+ warning: A.to_list/1 is undefined or private. Did you mean one of:
- test "hints exclude deprecated functions" do
- files = %{
- "a.ex" => """
- defmodule A do
- def to_charlist(a), do: a
+ * to_charlist/1
- @deprecated "Use String.to_charlist/1 instead"
- def to_char_list(a), do: a
+ a.ex:7: A.c/1
- def c(a), do: A.to_list(a)
- end
"""
- }
- warning = """
- warning: A.to_list/1 is undefined or private. Did you mean one of:
+ assert_warnings(files, warning)
+ end
- * to_charlist/1
+ test "imports" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ import Record
- a.ex:7: A.c/1
+ def a(a, b), do: extract(a, b)
+ def b(arg), do: is_record(arg)
+ end
+ """
+ }
- """
+ assert_no_warnings(files)
+ end
- assert_warnings(files, warning)
- end
+ test "requires" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ require Integer
- test "imports" do
- files = %{
- "a.ex" => """
- defmodule A do
- import Record
+ def a(a), do: Integer.is_even(a)
+ end
+ """
+ }
- def a(a, b), do: extract(a, b)
- def b(arg), do: is_record(arg)
- end
- """
- }
+ assert_no_warnings(files)
+ end
- assert_no_warnings(files)
- end
+ test "excludes no_warn_undefined" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ @compile {:no_warn_undefined, [MissingModule, {MissingModule2, :func, 2}]}
+ @compile {:no_warn_undefined, {B, :func, 2}}
+
+ def a, do: MissingModule.func(1)
+ def b, do: MissingModule2.func(1, 2)
+ def c, do: MissingModule2.func(1)
+ def d, do: MissingModule3.func(1, 2)
+ def e, do: B.func(1)
+ def f, do: B.func(1, 2)
+ def g, do: B.func(1, 2, 3)
+ end
+ """,
+ "b.ex" => """
+ defmodule B do
+ def func(_), do: :ok
+ end
+ """
+ }
+
+ warning = """
+ warning: MissingModule2.func/1 is undefined (module MissingModule2 is not available or is yet to be defined)
+ a.ex:7: A.c/0
+
+ warning: MissingModule3.func/2 is undefined (module MissingModule3 is not available or is yet to be defined)
+ a.ex:8: A.d/0
- test "requires" do
- files = %{
- "a.ex" => """
- defmodule A do
- require Integer
+ warning: B.func/3 is undefined or private. Did you mean one of:
+
+ * func/1
+
+ a.ex:11: A.g/0
- def a(a), do: Integer.is_even(a)
- end
"""
- }
- assert_no_warnings(files)
+ assert_warnings(files, warning)
+ end
end
- test "excludes no_warn_undefined" do
- files = %{
- "a.ex" => """
- defmodule A do
- @compile {:no_warn_undefined, [MissingModule, {MissingModule2, :func, 2}]}
- @compile {:no_warn_undefined, {B, :func, 2}}
-
- def a, do: MissingModule.func(1)
- def b, do: MissingModule2.func(1, 2)
- def c, do: MissingModule2.func(1)
- def d, do: MissingModule3.func(1, 2)
- def e, do: B.func(1)
- def f, do: B.func(1, 2)
- def g, do: B.func(1, 2, 3)
- end
- """,
- "b.ex" => """
- defmodule B do
- def func(_), do: :ok
- end
- """
- }
+ describe "deprecated" do
+ test "reports deprecated functions" do
+ files = %{
+ "a.ex" => """
+ defmodule A do
+ @deprecated "oops"
+ def a, do: A.a
+ end
+ """
+ }
- warning = """
- warning: MissingModule2.func/1 is undefined (module MissingModule2 is not available or is yet to be defined)
- a.ex:7: A.c/0
+ warning = """
+ warning: A.a/0 is deprecated. oops
+ a.ex:3: A.a/0
- warning: MissingModule3.func/2 is undefined (module MissingModule3 is not available or is yet to be defined)
- a.ex:8: A.d/0
+ """
- warning: B.func/3 is undefined or private. Did you mean one of:
+ assert_warnings(files, warning)
+ end
- * func/1
+ # 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
+ 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)
+ 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
+ end
+ """
+ }
+
+ warning = """
+ warning: DeprecatedModule2.func/1 is deprecated. message
+ a.ex:6: A.c/0
- a.ex:11: A.g/0
+ warning: DeprecatedModule3.func/2 is deprecated. message
+ a.ex:7: A.d/0
- """
+ """
- assert_warnings(files, warning)
+ assert_warnings(files, warning)
+ end
end
defp assert_warnings(files, expected) do
diff --git a/lib/mix/lib/mix/tasks/compile.elixir.ex b/lib/mix/lib/mix/tasks/compile.elixir.ex
index 08dc46b6c..56518c49d 100644
--- a/lib/mix/lib/mix/tasks/compile.elixir.ex
+++ b/lib/mix/lib/mix/tasks/compile.elixir.ex
@@ -90,7 +90,9 @@ defmodule Mix.Tasks.Compile.Elixir do
if exclude == [] do
opts
else
- Keyword.update(opts, :no_warn_undefined, exclude, &(List.wrap(&1) ++ exclude))
+ opts
+ |> Keyword.update(:no_warn_undefined, exclude, &(List.wrap(&1) ++ exclude))
+ |> Keyword.update(:no_warn_deprecated, exclude, &(List.wrap(&1) ++ exclude))
end
end
end