Skip to content

Commit

Permalink
Move optional callbacks to language
Browse files Browse the repository at this point in the history
  • Loading branch information
wojtekmach committed Jul 30, 2021
1 parent 38c672f commit b943950
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 31 deletions.
25 changes: 12 additions & 13 deletions lib/ex_doc/language.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,22 @@ defmodule ExDoc.Language do
The map has the following keys:
* `:doc_fallback` - if set, a 0-arity function that returns DocAST which
will be used as fallback to empty docs on the function node
* `:extra_annotations`
* `:line` - the line where the code is located
* `:specs` - a list of specs that will be later formatted by `c:typespec/2`
* `:doc_fallback` - if set, a 0-arity function that returns DocAST which
will be used as fallback to empty docs on the function node
* `:extra_annotations` - additional annotations
"""
@callback function_data(entry :: tuple(), module_data()) ::
%{
doc_fallback: (() -> ExDoc.DocAST.t()) | nil,
extra_annotations: [String.t()],
line: non_neg_integer() | nil,
specs: [spec_ast()]
specs: [spec_ast()],
doc_fallback: (() -> ExDoc.DocAST.t()) | nil,
extra_annotations: [String.t()]
}
| :skip

Expand All @@ -74,22 +74,21 @@ defmodule ExDoc.Language do
The map has the following keys:
* `:actual_def` - `{name, arity}` of how the callback is actually represented
in abstract code
* `:line` - the line where the code is located
* `:signature` - the signature
* `:specs` - a list of specs that will be later formatted by `c:typespec/2`
* `:extra_annotations` - additional annotations
"""
@callback callback_data(entry :: tuple(), module_data()) ::
%{
actual_def: {atom(), arity()},
line: non_neg_integer() | nil,
signature: [binary()],
specs: [spec_ast()]
specs: [spec_ast()],
extra_annotations: [String.t()]
}

@doc """
Expand Down
11 changes: 8 additions & 3 deletions lib/ex_doc/language/elixir.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule ExDoc.Language.Elixir do
title = module_title(module, type)
abst_code = Erlang.get_abstract_code(module)
line = Erlang.find_module_line(module, abst_code)
optional_callbacks = type == :behaviour && module.behaviour_info(:optional_callbacks)

%{
module: module,
Expand All @@ -34,7 +35,8 @@ defmodule ExDoc.Language.Elixir do
abst_code: abst_code,
specs: Erlang.get_specs(module),
callbacks: Erlang.get_callbacks(module),
impls: get_impls(module)
impls: get_impls(module),
optional_callbacks: optional_callbacks
}
}
end
Expand Down Expand Up @@ -106,6 +108,9 @@ defmodule ExDoc.Language.Elixir do
{{kind, name, arity}, anno, _signature, _doc, _metadata} = entry
actual_def = actual_def(name, arity, kind)

extra_annotations =
if actual_def in module_data.private.optional_callbacks, do: ["optional"], else: []

specs =
case Map.fetch(module_data.private.callbacks, actual_def) do
{:ok, specs} ->
Expand All @@ -127,10 +132,10 @@ defmodule ExDoc.Language.Elixir do
signature = [get_typespec_signature(hd(quoted), arity)]

%{
actual_def: actual_def,
line: line,
signature: signature,
specs: quoted
specs: quoted,
extra_annotations: extra_annotations
}
end

Expand Down
14 changes: 10 additions & 4 deletions lib/ex_doc/language/erlang.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,24 @@ defmodule ExDoc.Language.Erlang do
":" <> id = inspect(module)
abst_code = get_abstract_code(module)
line = find_module_line(module, abst_code)
type = module_type(module)
optional_callbacks = type == :behaviour && module.behaviour_info(:optional_callbacks)

%{
module: module,
docs: docs_chunk,
language: __MODULE__,
id: id,
title: id,
type: module_type(module),
type: type,
line: line,
callback_types: [:callback],
nesting_info: nil,
private: %{
abst_code: abst_code,
specs: get_specs(module),
callbacks: get_callbacks(module)
callbacks: get_callbacks(module),
optional_callbacks: optional_callbacks
}
}
end
Expand Down Expand Up @@ -72,6 +75,9 @@ defmodule ExDoc.Language.Erlang do
def callback_data(entry, module_data) do
{{_kind, name, arity}, anno, signature, _doc, _metadata} = entry

extra_annotations =
if {name, arity} in module_data.private.optional_callbacks, do: ["optional"], else: []

specs =
case Map.fetch(module_data.private.callbacks, {name, arity}) do
{:ok, specs} ->
Expand All @@ -82,10 +88,10 @@ defmodule ExDoc.Language.Erlang do
end

%{
actual_def: {name, arity},
line: anno_line(anno),
signature: signature,
specs: specs
specs: specs,
extra_annotations: extra_annotations
}
end

Expand Down
13 changes: 3 additions & 10 deletions lib/ex_doc/retriever.ex
Original file line number Diff line number Diff line change
Expand Up @@ -240,31 +240,24 @@ defmodule ExDoc.Retriever do

defp get_callbacks(%{type: :behaviour} = module_data, source, groups_for_functions) do
{:docs_v1, _, _, _, _, _, docs} = module_data.docs
optional_callbacks = module_data.module.behaviour_info(:optional_callbacks)

for {{kind, _, _}, _, _, _, _} = doc <- docs, kind in module_data.callback_types do
get_callback(doc, source, optional_callbacks, groups_for_functions, module_data)
get_callback(doc, source, groups_for_functions, module_data)
end
end

defp get_callbacks(_, _, _), do: []

defp get_callback(callback, source, optional_callbacks, groups_for_functions, module_data) do
defp get_callback(callback, source, groups_for_functions, module_data) do
callback_data = module_data.language.callback_data(callback, module_data)

{:docs_v1, _, _, content_type, _, _, _} = module_data.docs
{{kind, name, arity}, anno, _signature, doc, metadata} = callback
actual_def = callback_data.actual_def
doc_line = anno_line(anno)

signature = signature(callback_data.signature)
specs = callback_data.specs
annotations = annotations_from_metadata(metadata)

# actual_def is Elixir specific, but remember optional_callbacks are generic.
annotations =
if actual_def in optional_callbacks, do: ["optional" | annotations], else: annotations

annotations = callback_data.extra_annotations ++ annotations_from_metadata(metadata)
doc_ast = doc_ast(content_type, doc, file: source.path, line: doc_line + 1)

group =
Expand Down
12 changes: 11 additions & 1 deletion test/ex_doc/retriever/erlang_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,27 @@ defmodule ExDoc.Retriever.ErlangTest do
-callback callback1() -> atom().
%% callback1/0 docs.
-callback optional_callback1() -> atom().
%% optional_callback1/0 docs.
-optional_callbacks([optional_callback1/0]).
""")

config = %ExDoc.Config{source_url_pattern: "%{path}:%{line}"}
[mod] = Retriever.docs_from_modules([:mod], config)
[callback1] = mod.docs
[callback1, optional_callback1] = mod.docs

assert callback1.id == "c:callback1/0"
assert callback1.type == :callback
assert callback1.annotations == []
assert DocAST.to_string(callback1.doc) == "callback1/0 docs."
assert Path.basename(callback1.source_url) == "mod.erl:4"
assert Erlang.autolink_spec(hd(callback1.specs), []) == "callback1() -> atom()."

assert optional_callback1.id == "c:optional_callback1/0"
assert optional_callback1.type == :callback
assert optional_callback1.annotations == ["optional"]
end

@tag :otp24
Expand Down

0 comments on commit b943950

Please sign in to comment.