@@ -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