Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions lib/ex_doc/retriever.ex
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,7 @@ defmodule ExDoc.Retriever do
function = actual_def(name, arity, type)
line = find_actual_line(module_info.abst_code, function, :function) || doc_line

behaviour = Map.get(module_info.impls, {name, arity})

doc =
if is_nil(doc) && behaviour do
"Callback implementation for `c:#{inspect behaviour}.#{name}/#{arity}`."
else
doc
end
doc = docstring(doc, name, arity, Map.fetch(module_info.impls, {name, arity}))

specs = module_info.specs
|> Map.get(function, [])
Expand Down Expand Up @@ -272,6 +265,25 @@ defmodule ExDoc.Retriever do
end
end

defp docstring(nil, name, arity, {:ok, behaviour}) do
callback_docs = Code.get_docs(behaviour, :callback_docs) || []
case List.keyfind(callback_docs, {name, arity}, 0) do
{{^name, ^arity}, _, :callback, callback_docs} when is_binary(callback_docs) ->
[header, body] = String.split(callback_docs, "\n", parts: 2)
info = "Documentation for callback `c:#{inspect behaviour}.#{name}/#{arity}`."
"#{header}\n\n#{info}\n\n#{trim_leading_newlines(body)}"
_ ->
"Callback implementation for `c:#{inspect behaviour}.#{name}/#{arity}`."
end
end

defp docstring(doc, _name, _arity, _behaviour) do
doc
end

defp trim_leading_newlines("\n" <> rest), do: trim_leading_newlines(rest)
defp trim_leading_newlines(rest), do: rest

defp get_callbacks(%{type: :behaviour, name: name, abst_code: abst_code}, source) do
optional_callbacks = get_optional_callbacks(abst_code)
(Code.get_docs(name, :callback_docs) || [])
Expand Down
4 changes: 4 additions & 0 deletions test/ex_doc/retriever_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ defmodule ExDoc.RetrieverTest do
"A doc for this so it doesn't use 'Callback implementation for'"
assert Enum.at(docs, 1).doc ==
"Callback implementation for `c:CustomBehaviourOne.greet/1`."
assert Enum.at(docs, 2).doc ==
"This is a sample callback.\n\n" <>
"Documentation for callback `c:CustomBehaviourOne.hello/1`.\n\n" <>
"With description\n"
end

## PROTOCOLS
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/behaviour.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule CustomBehaviourOne do

@doc """
This is a sample callback.

With description
"""
@callback hello(integer) :: integer
@callback greet(integer | String.t) :: integer
Expand Down