Skip to content

Commit dbfab69

Browse files
ggcampinhojosevalim
authored andcommitted
Check deprecated calls on task xref warnings (#7128)
Check deprecated using `__info__` or `ExDp` chunk if the module is not loaded, it doesn't check local deprecations #7104
1 parent 47b5959 commit dbfab69

File tree

2 files changed

+315
-186
lines changed

2 files changed

+315
-186
lines changed

lib/mix/lib/mix/tasks/xref.ex

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,23 @@ defmodule Mix.Tasks.Xref do
165165
## Modes
166166

167167
defp warnings(opts) do
168-
warnings(&print_warnings/1, opts)
168+
warnings =
169+
source_warnings(excludes(), opts)
170+
|> merge_entries()
171+
|> sort_entries()
172+
|> print_warnings()
173+
174+
{:ok, warnings}
169175
end
170176

171177
defp unreachable(opts) do
172-
case warnings(&print_unreachables/1, opts) do
173-
{:ok, []} -> :ok
174-
_ -> :error
175-
end
178+
unreachable =
179+
source_unreachable(excludes(), opts)
180+
|> merge_entries()
181+
|> sort_entries()
182+
|> print_unreachables()
183+
184+
if unreachable == [], do: :ok, else: :error
176185
end
177186

178187
defp callers(callee, opts) do
@@ -256,24 +265,18 @@ defmodule Mix.Tasks.Xref do
256265

257266
## Warnings
258267

259-
defp warnings(print_warnings, opts) do
260-
case source_warnings(excludes(), opts) do
261-
[] ->
262-
{:ok, []}
268+
defp source_warnings(excludes, opts) do
269+
sources = sources(opts)
263270

264-
entries ->
265-
entries =
266-
entries
267-
|> merge_entries()
268-
|> sort_entries()
269-
|> print_warnings.()
271+
filter_unreachable(sources, excludes) ++ filter_deprecated(sources, excludes)
272+
end
270273

271-
{:ok, entries}
272-
end
274+
defp source_unreachable(excludes, opts) do
275+
sources(opts) |> filter_unreachable(excludes)
273276
end
274277

275-
defp source_warnings(excludes, opts) do
276-
Enum.flat_map(sources(opts), fn source ->
278+
defp filter_unreachable(sources, excludes) do
279+
Enum.flat_map(sources, fn source ->
277280
file = source(source, :source)
278281
runtime_dispatches = source(source, :runtime_dispatches)
279282

@@ -285,6 +288,23 @@ defmodule Mix.Tasks.Xref do
285288
end)
286289
end
287290

291+
defp filter_deprecated(sources, excludes) do
292+
callers = filter_callers(sources, fn _ -> true end)
293+
294+
called_modules = for {{module, function, arity}, location} <- callers, uniq: true, do: module
295+
296+
deprecated =
297+
for module <- called_modules,
298+
{{function, arity}, reason} <- load_deprecated(module),
299+
into: %{},
300+
do: {{module, function, arity}, reason}
301+
302+
for {mfa, locations} <- callers,
303+
reason = deprecated[mfa],
304+
{module, function, arity} = mfa,
305+
do: {{:deprecated, module, function, arity, reason}, locations}
306+
end
307+
288308
defp load_exports(module) do
289309
if :code.is_loaded(module) do
290310
# If the module is loaded, we will use the faster function_exported?/3 check
@@ -300,6 +320,26 @@ defmodule Mix.Tasks.Xref do
300320
end
301321
end
302322

323+
defp load_deprecated(module) do
324+
if :code.is_loaded(module) do
325+
# If the module is loaded, we will use __info__
326+
if function_exported?(module, :__info__, 1) do
327+
module.__info__(:deprecated)
328+
else
329+
[]
330+
end
331+
else
332+
# Otherwise we get the ExDp chunk using :beam_lib to avoid loading modules
333+
with [_ | _] = file <- :code.which(module),
334+
{:ok, {^module, [{'ExDp', deprecated_bin}]}} <- :beam_lib.chunks(file, ['ExDp']),
335+
{:elixir_deprecated_v1, deprecated} = :erlang.binary_to_term(deprecated_bin) do
336+
deprecated
337+
else
338+
_ -> []
339+
end
340+
end
341+
end
342+
303343
defp unreachable_mfa(exports, module, func, arity, excludes) do
304344
cond do
305345
excluded?(module, func, arity, excludes) ->
@@ -364,6 +404,16 @@ defmodule Mix.Tasks.Xref do
364404
]
365405
end
366406

407+
defp warning_message({:deprecated, module, function, arity, reason}) do
408+
[
409+
"function ",
410+
Exception.format_mfa(module, function, arity),
411+
" is deprecated. ",
412+
reason,
413+
"."
414+
]
415+
end
416+
367417
defp format_locations([location]) do
368418
format_location(location)
369419
end
@@ -414,7 +464,11 @@ defmodule Mix.Tasks.Xref do
414464
## Callers
415465

416466
defp source_callers(filter, opts) do
417-
Enum.flat_map(sources(opts), fn source ->
467+
sources(opts) |> filter_callers(filter)
468+
end
469+
470+
defp filter_callers(sources, filter) do
471+
Enum.flat_map(sources, fn source ->
418472
file = source(source, :source)
419473
runtime_dispatches = source(source, :runtime_dispatches)
420474
compile_dispatches = source(source, :compile_dispatches)

0 commit comments

Comments
 (0)