Skip to content

Commit 15a6772

Browse files
uesteibarjosevalim
authored andcommitted
Show better error when h/1 is used on callback (#6206)
Closes #6204
1 parent d5f3a0a commit 15a6772

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

lib/iex/lib/iex/introspection.ex

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ defmodule IEx.Introspection do
5555
case h_mod_fun(module, function) do
5656
:ok ->
5757
:ok
58+
:behaviour_found ->
59+
behaviour_found("#{inspect module}.#{function}")
5860
:no_docs ->
5961
puts_error("#{inspect module} was not compiled with docs")
6062
:not_found ->
@@ -70,7 +72,14 @@ defmodule IEx.Introspection do
7072
h(mod, fun, arity)
7173
end
7274

73-
if result != [], do: :ok, else: :not_found
75+
cond do
76+
result != [] ->
77+
:ok
78+
has_callback?(mod, fun) ->
79+
:behaviour_found
80+
true ->
81+
:not_found
82+
end
7483
else
7584
:no_docs
7685
end
@@ -95,6 +104,8 @@ defmodule IEx.Introspection do
95104
case h_mod_fun_arity(module, function, arity) do
96105
:ok ->
97106
:ok
107+
:behaviour_found ->
108+
behaviour_found("#{inspect module}.#{function}/#{arity}")
98109
:no_docs ->
99110
puts_error("#{inspect module} was not compiled with docs")
100111
:not_found ->
@@ -115,13 +126,37 @@ defmodule IEx.Introspection do
115126
end
116127
:ok
117128
else
118-
:not_found
129+
if has_callback?(mod, fun, arity) do
130+
:behaviour_found
131+
else
132+
:not_found
133+
end
119134
end
120135
else
121136
:no_docs
122137
end
123138
end
124139

140+
defp has_callback?(mod, fun) do
141+
mod
142+
|> Code.get_docs(:callback_docs)
143+
|> find_callback_doc(fun)
144+
end
145+
146+
defp has_callback?(mod, fun, arity) do
147+
mod
148+
|> Code.get_docs(:callback_docs)
149+
|> find_callback_doc(fun, arity)
150+
end
151+
152+
defp find_callback_doc(docs, fun) do
153+
Enum.any?(docs, &match?({{^fun, _}, _, _, _}, &1))
154+
end
155+
156+
defp find_callback_doc(docs, fun, arity) do
157+
Enum.any?(docs, &match?({{^fun, ^arity}, _, _, _}, &1))
158+
end
159+
125160
defp find_doc(docs, fun, arity) do
126161
doc = List.keyfind(docs, {fun, arity}, 0) || find_doc_defaults(docs, fun, arity)
127162
if doc != nil and has_content?(doc), do: doc
@@ -440,7 +475,14 @@ defmodule IEx.Introspection do
440475

441476
defp no_specs(for), do: no(for, "specification")
442477
defp no_types(for), do: no(for, "type information")
443-
defp no_docs(for), do: no(for, "documentation")
478+
defp no_docs(for), do: no(for, "documentation")
479+
480+
defp behaviour_found(for) do
481+
puts_error("""
482+
No documentation for function #{for} was found, but there is a callback with the same name.
483+
You can view callback documentations with the b/1 helper.
484+
""")
485+
end
444486

445487
defp no(for, type) do
446488
puts_error("No #{type} for #{for} was found")

lib/iex/test/iex/helpers_test.exs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ defmodule IEx.HelpersTest do
102102

103103
assert capture_io(fn -> h Impl.first end) == "* @callback first(integer()) :: integer()\n\nDocs for MyBehaviour.first\n"
104104
assert capture_io(fn -> h Impl.second end) == "* def second(int)\n\nDocs for Impl.second/1\n* def second(int1, int2)\n\nDocs for Impl.second/2\n"
105+
106+
assert capture_io(fn -> h MyBehaviour.first end) == """
107+
No documentation for function MyBehaviour.first was found, but there is a callback with the same name.
108+
You can view callback documentations with the b/1 helper.\n
109+
"""
110+
assert capture_io(fn -> h MyBehaviour.second/2 end) == """
111+
No documentation for function MyBehaviour.second/2 was found, but there is a callback with the same name.
112+
You can view callback documentations with the b/1 helper.\n
113+
"""
114+
assert capture_io(fn -> h MyBehaviour.second/3 end) == "No documentation for MyBehaviour.second/3 was found\n"
105115
end
106116
after
107117
cleanup_modules([Impl, MyBehaviour])

0 commit comments

Comments
 (0)