@@ -287,7 +287,7 @@ defmodule IEx.Introspection do
287287 result =
288288 for { ^ function , arity } <- exports ,
289289 ( if docs do
290- find_doc ( docs , function , arity )
290+ find_doc_with_content ( docs , function , arity )
291291 else
292292 get_spec ( module , function , arity ) != [ ]
293293 end ) do
@@ -364,7 +364,7 @@ defmodule IEx.Introspection do
364364 spec = get_spec ( mod , fun , arity )
365365
366366 cond do
367- doc_tuple = find_doc ( docs , fun , arity ) ->
367+ doc_tuple = find_doc_with_content ( docs , fun , arity ) ->
368368 print_fun ( mod , doc_tuple , spec )
369369 :ok
370370
@@ -388,15 +388,17 @@ defmodule IEx.Introspection do
388388 end
389389
390390 defp has_callback? ( mod , fun ) do
391- mod
392- |> get_docs ( [ :callback , :macrocallback ] )
393- |> Enum . any? ( & match? ( { _ , ^ fun , _ } , elem ( & 1 , 0 ) ) )
391+ case get_callback_docs ( mod , & match? ( { _ , ^ fun , _ } , elem ( & 1 , 0 ) ) ) do
392+ { :ok , [ _ | _ ] } -> true
393+ _ -> false
394+ end
394395 end
395396
396397 defp has_callback? ( mod , fun , arity ) do
397- mod
398- |> get_docs ( [ :callback , :macrocallback ] )
399- |> Enum . any? ( & match? ( { _ , ^ fun , ^ arity } , elem ( & 1 , 0 ) ) )
398+ case get_callback_docs ( mod , & match? ( { _ , ^ fun , ^ arity } , elem ( & 1 , 0 ) ) ) do
399+ { :ok , [ _ | _ ] } -> true
400+ _ -> false
401+ end
400402 end
401403
402404 defp has_type? ( mod , fun ) do
@@ -423,16 +425,22 @@ defmodule IEx.Introspection do
423425
424426 defp extract_name_and_arity ( { { _ , name , arity } , _ , _ , _ , _ } ) , do: { name , arity }
425427
428+ defp find_doc_with_content ( docs , function , arity ) do
429+ doc = find_doc ( docs , function , arity )
430+ if doc != nil and has_content? ( doc ) , do: doc
431+ end
432+
433+ defp has_content? ( { _ , _ , _ , :hidden , _ } ) , do: false
434+ defp has_content? ( { { _ , name , _ } , _ , _ , :none , _ } ) , do: hd ( Atom . to_charlist ( name ) ) != ?_
435+ defp has_content? ( { _ , _ , _ , _ , _ } ) , do: true
436+
426437 defp find_doc ( nil , _fun , _arity ) do
427438 nil
428439 end
429440
430441 defp find_doc ( docs , fun , arity ) do
431- doc =
432- Enum . find ( docs , & match? ( { _ , ^ fun , ^ arity } , elem ( & 1 , 0 ) ) ) ||
433- find_doc_defaults ( docs , fun , arity )
434-
435- if doc != nil and has_content? ( doc ) , do: doc
442+ Enum . find ( docs , & match? ( { _ , ^ fun , ^ arity } , elem ( & 1 , 0 ) ) ) ||
443+ find_doc_defaults ( docs , fun , arity )
436444 end
437445
438446 defp find_doc_defaults ( docs , function , min ) do
@@ -445,10 +453,6 @@ defmodule IEx.Introspection do
445453 end )
446454 end
447455
448- defp has_content? ( { _ , _ , _ , :hidden , _ } ) , do: false
449- defp has_content? ( { { _ , name , _ } , _ , _ , :none , _ } ) , do: hd ( Atom . to_charlist ( name ) ) != ?_
450- defp has_content? ( { _ , _ , _ , _ , _ } ) , do: true
451-
452456 defp print_fun ( mod , { { kind , fun , arity } , _line , signature , doc , metadata } , spec ) do
453457 if callback_module = doc == :none and callback_module ( mod , fun , arity ) do
454458 filter = & match? ( { _ , ^ fun , ^ arity } , elem ( & 1 , 0 ) )
@@ -466,19 +470,10 @@ defmodule IEx.Introspection do
466470 defp kind_to_def ( :macro ) , do: :defmacro
467471
468472 defp callback_module ( mod , fun , arity ) do
469- predicate = & match? ( { { ^ fun , ^ arity } , _ } , & 1 )
470-
471473 mod . module_info ( :attributes )
472474 |> Keyword . get_values ( :behaviour )
473475 |> Stream . concat ( )
474- |> Enum . find ( & Enum . any? ( get_callbacks ( & 1 ) , predicate ) )
475- end
476-
477- defp get_callbacks ( module ) do
478- case Typespec . fetch_callbacks ( module ) do
479- { :ok , callbacks } -> callbacks
480- :error -> [ ]
481- end
476+ |> Enum . find ( & has_callback? ( & 1 , fun , arity ) )
482477 end
483478
484479 defp get_spec ( module , name , arity ) do
@@ -504,9 +499,6 @@ defmodule IEx.Introspection do
504499 :no_beam ->
505500 no_beam ( mod )
506501
507- :no_docs ->
508- no_docs ( mod )
509-
510502 { :ok , [ ] } ->
511503 puts_error ( "No callbacks for #{ inspect ( mod ) } were found" )
512504
@@ -524,7 +516,6 @@ defmodule IEx.Introspection do
524516
525517 case get_callback_docs ( mod , filter ) do
526518 :no_beam -> no_beam ( mod )
527- :no_docs -> no_docs ( mod )
528519 { :ok , [ ] } -> docs_not_found ( "#{ inspect ( mod ) } .#{ fun } " )
529520 { :ok , docs } -> Enum . each ( docs , & print_typespec / 1 )
530521 end
@@ -537,7 +528,6 @@ defmodule IEx.Introspection do
537528
538529 case get_callback_docs ( mod , filter ) do
539530 :no_beam -> no_beam ( mod )
540- :no_docs -> no_docs ( mod )
541531 { :ok , [ ] } -> docs_not_found ( "#{ inspect ( mod ) } .#{ fun } /#{ arity } " )
542532 { :ok , docs } -> Enum . each ( docs , & print_typespec / 1 )
543533 end
@@ -557,26 +547,54 @@ defmodule IEx.Introspection do
557547 :error ->
558548 :no_beam
559549
560- _ when is_nil ( docs ) ->
561- :no_docs
562-
563550 { :ok , callbacks } ->
564551 docs =
565- docs
552+ callbacks
553+ |> Enum . map ( & translate_callback / 1 )
566554 |> Enum . filter ( filter )
567- |> Enum . map ( fn
568- { { :macrocallback , fun , arity } , _ , _ , doc , metadata } ->
569- macro = { :"MACRO- #{ fun } " , arity + 1 }
570- { format_callback ( :macrocallback , fun , macro , callbacks ) , doc , metadata }
571-
572- { { kind , fun , arity } , _ , _ , doc , metadata } ->
573- { format_callback ( kind , fun , { fun , arity } , callbacks ) , doc , metadata }
555+ |> Enum . sort ( )
556+ |> Enum . flat_map ( fn { { _ , function , arity } , _specs } = callback ->
557+ case find_doc ( docs , function , arity ) do
558+ nil -> [ { format_callback ( callback ) , :none , % { } } ]
559+ { _ , _ , _ , :hidden , _ } -> [ ]
560+ { _ , _ , _ , doc , metadata } -> [ { format_callback ( callback ) , doc , metadata } ]
561+ end
574562 end )
575563
576564 { :ok , docs }
577565 end
578566 end
579567
568+ defp translate_callback ( { { name , arity } , specs } ) do
569+ case Atom . to_string ( name ) do
570+ "MACRO-" <> macro_name ->
571+ # The typespec of a macrocallback differs from the one expressed
572+ # via @macrocallback:
573+ #
574+ # * The function name is prefixed with "MACRO-"
575+ # * The arguments contain an additional first argument: the caller
576+ # * The arity is increased by 1
577+ #
578+ specs =
579+ Enum . map ( specs , fn { :type , line1 , :fun , [ { :type , line2 , :product , [ _ | args ] } , spec ] } ->
580+ { :type , line1 , :fun , [ { :type , line2 , :product , args } , spec ] }
581+ end )
582+
583+ { { :macrocallback , String . to_atom ( macro_name ) , arity - 1 } , specs }
584+
585+ _ ->
586+ { { :callback , name , arity } , specs }
587+ end
588+ end
589+
590+ defp format_callback ( { { kind , name , _arity } , specs } ) do
591+ Enum . map ( specs , fn spec ->
592+ Typespec . spec_to_quoted ( name , spec )
593+ |> Macro . prewalk ( & drop_macro_env / 1 )
594+ |> format_typespec ( kind , 0 )
595+ end )
596+ end
597+
580598 defp add_optional_callback_docs ( docs , mod ) do
581599 optional_callbacks =
582600 if Code . ensure_loaded? ( mod ) and function_exported? ( mod , :behaviour_info , 1 ) do
@@ -596,16 +614,6 @@ defmodule IEx.Introspection do
596614 format_typespec ( callbacks , :optional_callbacks , 0 )
597615 end
598616
599- defp format_callback ( kind , name , key , callbacks ) do
600- { _ , specs } = List . keyfind ( callbacks , key , 0 )
601-
602- Enum . map ( specs , fn spec ->
603- Typespec . spec_to_quoted ( name , spec )
604- |> Macro . prewalk ( & drop_macro_env / 1 )
605- |> format_typespec ( kind , 0 )
606- end )
607- end
608-
609617 defp drop_macro_env ( { name , meta , [ { ::: , _ , [ _ , { { :. , _ , [ Macro.Env , :t ] } , _ , _ } ] } | args ] } ) ,
610618 do: { name , meta , args }
611619
0 commit comments