Skip to content

Commit

Permalink
Merge pull request #8123 from garazdawi/lukas/otp/fix-warn_no_docs
Browse files Browse the repository at this point in the history
compiler: Add warn_missing_doc_functions et all and enable in all docs
  • Loading branch information
garazdawi authored Feb 20, 2024
2 parents ec65a6b + 3b16df8 commit 375ffcd
Show file tree
Hide file tree
Showing 45 changed files with 274 additions and 37 deletions.
Binary file modified bootstrap/lib/compiler/ebin/beam_doc.beam
Binary file not shown.
1 change: 1 addition & 0 deletions lib/common_test/proper_ext/ct_proper_ext.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
%% do not shrink.

-module(ct_proper_ext).
-moduledoc false.

-export([existing_atom/0]).
-export([safe_any/0]).
Expand Down
1 change: 1 addition & 0 deletions lib/common_test/src/cte_track.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
%%

-module(cte_track).
-moduledoc false.
%% module for tracking CT execution progress
%% test spec addition examples:
%% {event_handler, {cte_track, []}}.
Expand Down
51 changes: 42 additions & 9 deletions lib/compiler/src/beam_doc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@
}).

-type internal_docs() :: #docs{}.
-type opt() :: warn_missing_doc | nowarn_hidden_doc | {nowarn_hidden_doc, {atom(), arity()}}.
-type opt() :: warn_missing_doc | warn_missing_doc_functions | warn_missing_doc_callbacks | warn_missing_doc_types |
nowarn_missing_doc | nowarn_missing_doc_functions | nowarn_missing_doc_callbacks | nowarn_missing_doc_types |
nowarn_hidden_doc | {nowarn_hidden_doc, {atom(), arity()}}.
-type kfa() :: {Kind :: function | type | callback, Name :: atom(), Arity :: arity()}.
-type warnings() :: [{file:filename(),
[{erl_anno:location(), beam_doc, warning()}]}].
Expand Down Expand Up @@ -248,7 +250,32 @@ main(Dirname, Filename, AST, CmdLineOpts) ->

extract_opts(AST, CmdLineOpts) ->
CompileOpts = lists:flatten([C || {attribute,_,compile,C} <- AST]),
CompileOpts ++ CmdLineOpts.
normalize_warn_missing_doc(CmdLineOpts ++ CompileOpts).

normalize_warn_missing_doc(Opts) ->
normalize_warn_missing_doc(Opts, []).
normalize_warn_missing_doc([warn_missing_doc | Opts], _Warnings) ->
normalize_warn_missing_doc(Opts, [function,callback,type]);
normalize_warn_missing_doc([nowarn_missing_doc | Opts], _Warnings) ->
normalize_warn_missing_doc(Opts, []);
normalize_warn_missing_doc([warn_missing_doc_functions | Opts], Warnings) ->
normalize_warn_missing_doc(Opts, lists:uniq([function | Warnings]));
normalize_warn_missing_doc([nowarn_missing_doc_functions | Opts], Warnings) ->
normalize_warn_missing_doc(Opts, lists:uniq(Warnings -- [function]));
normalize_warn_missing_doc([warn_missing_doc_callbacks | Opts], Warnings) ->
normalize_warn_missing_doc(Opts, lists:uniq([callback | Warnings]));
normalize_warn_missing_doc([nowarn_missing_doc_callbacks | Opts], Warnings) ->
normalize_warn_missing_doc(Opts, lists:uniq(Warnings -- [callback]));
normalize_warn_missing_doc([warn_missing_doc_types | Opts], Warnings) ->
normalize_warn_missing_doc(Opts, lists:uniq([type | Warnings]));
normalize_warn_missing_doc([nowarn_missing_doc_types | Opts], Warnings) ->
normalize_warn_missing_doc(Opts, lists:uniq(Warnings -- [type]));
normalize_warn_missing_doc([Opt | Opts], Warnings) ->
[Opt | normalize_warn_missing_doc(Opts, Warnings)];
normalize_warn_missing_doc([], []) ->
[];
normalize_warn_missing_doc([], Warnings) ->
[{warn_missing_doc,Warnings}].

-spec format_error(warning()) -> io_lib:chars().
format_error({hidden_type_used_in_exported_fun, {Type, Arity}}) ->
Expand Down Expand Up @@ -688,6 +715,8 @@ warnings(_AST, State) ->
],
foldl(fun (W, State0) -> W(State0) end, State, WarnFuns).

warn_missing_docs(State = #docs{ moduledoc = {_, hidden} }) ->
State;
warn_missing_docs(State) ->
DocNodes = process_docs(State),
foldl(fun warn_missing_docs/2, State, DocNodes).
Expand Down Expand Up @@ -747,19 +776,23 @@ create_warning(Anno, Warning, State) ->
Location = erl_anno:location(Anno),
{Filename, [{Location, ?MODULE, Warning}]}.

warn_missing_docs({KFA, Anno, _, Doc, _}, State) ->
case proplists:get_value(warn_missing_doc, State#docs.opts, false) of
true when Doc =:= none ->
warn_missing_docs({{Kind, _, _} = KFA, Anno, _, Doc, MD}, State)
when Doc =:= none, not is_map_key(equiv, MD) ->
case lists:member(Kind, proplists:get_value(warn_missing_doc, State#docs.opts, [])) of
true ->
Warning = {missing_doc, KFA},
State#docs{ warnings = [create_warning(Anno, Warning, State) | State#docs.warnings] };
_false ->
false ->
State
end.
end;
warn_missing_docs(_, State) ->
State.

warn_missing_moduledoc(State) ->
{_, ModuleDoc} = State#docs.moduledoc,
case proplists:get_value(warn_missing_doc, State#docs.opts, false) of
true when ModuleDoc =:= none ->
case proplists:get_value(warn_missing_doc, State#docs.opts, []) of
%% If any warn_missing_doc flags is enabled, we also warn for missing moduledoc.
[_|_] when ModuleDoc =:= none ->
Anno = erl_anno:new(?DEFAULT_MODULE_DOC_LOC),
Warning = missing_moduledoc,
State#docs{ warnings = [create_warning(Anno, Warning, State) | State#docs.warnings] };
Expand Down
1 change: 1 addition & 0 deletions lib/compiler/src/beam_ssa_ss.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
%%

-module(beam_ssa_ss).
-moduledoc false.

-compile({inline,[add_edge/4, add_vertex/3]}).

Expand Down
17 changes: 17 additions & 0 deletions lib/compiler/src/cerl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,7 @@ is_c_map(#c_literal{val = V}) when is_map(V) ->
is_c_map(_) ->
false.

-doc "".
-spec map_es(c_map() | c_literal()) -> [c_map_pair()].

map_es(#c_literal{anno=As,val=M}) when is_map(M) ->
Expand All @@ -2073,44 +2074,52 @@ map_es(#c_literal{anno=As,val=M}) when is_map(M) ->
map_es(#c_map{es = Es}) ->
Es.

-doc "".
-spec map_arg(c_map() | c_literal()) -> c_map() | c_literal().

map_arg(#c_literal{anno=As,val=M}) when is_map(M) ->
#c_literal{anno=As,val=#{}};
map_arg(#c_map{arg=M}) ->
M.

-doc "".
-spec c_map([c_map_pair()]) -> c_map().

c_map(Pairs) ->
ann_c_map([], Pairs).

-doc "".
-spec c_map_pattern([c_map_pair()]) -> c_map().

c_map_pattern(Pairs) ->
#c_map{es=Pairs, is_pat=true}.

-doc "".
-spec ann_c_map_pattern([term()], [c_map_pair()]) -> c_map().

ann_c_map_pattern(As, Pairs) ->
#c_map{anno=As, es=Pairs, is_pat=true}.

-doc "".
-spec is_c_map_empty(c_map() | c_literal()) -> boolean().

is_c_map_empty(#c_map{ es=[] }) -> true;
is_c_map_empty(#c_literal{val=M}) when is_map(M),map_size(M) =:= 0 -> true;
is_c_map_empty(_) -> false.

-doc "".
-spec is_c_map_pattern(c_map()) -> boolean().

is_c_map_pattern(#c_map{is_pat=IsPat}) ->
IsPat.

-doc "".
-spec ann_c_map([term()], [c_map_pair()]) -> c_map() | c_literal().

ann_c_map(As, Es) ->
ann_c_map(As, #c_literal{val=#{}}, Es).

-doc "".
-spec ann_c_map([term()], c_map() | c_literal(), [c_map_pair()]) -> c_map() | c_literal().

ann_c_map(As, #c_literal{val=M0}=Lit, Es) when is_map(M0) ->
Expand Down Expand Up @@ -2149,41 +2158,49 @@ update_map_literal([#c_map_pair{op=#c_literal{val=exact},key=Ck,val=Cv}|Es], M)
update_map_literal([], M) ->
M.

-doc "".
-spec update_c_map(c_map(), cerl(), [cerl()]) -> c_map() | c_literal().

update_c_map(#c_map{is_pat=true}=Old, M, Es) ->
Old#c_map{arg=M, es=Es};
update_c_map(#c_map{is_pat=false}=Old, M, Es) ->
ann_c_map(get_ann(Old), M, Es).

-doc "".
-spec map_pair_key(c_map_pair()) -> cerl().

map_pair_key(#c_map_pair{key=K}) -> K.

-doc "".
-spec map_pair_val(c_map_pair()) -> cerl().

map_pair_val(#c_map_pair{val=V}) -> V.

-doc "".
-spec map_pair_op(c_map_pair()) -> map_op().

map_pair_op(#c_map_pair{op=Op}) -> Op.

-doc "".
-spec c_map_pair(cerl(), cerl()) -> c_map_pair().

c_map_pair(Key,Val) ->
#c_map_pair{op=#c_literal{val=assoc},key=Key,val=Val}.

-doc "".
-spec c_map_pair_exact(cerl(), cerl()) -> c_map_pair().

c_map_pair_exact(Key,Val) ->
#c_map_pair{op=#c_literal{val=exact},key=Key,val=Val}.

-doc "".
-spec ann_c_map_pair([term()], cerl(), cerl(), cerl()) ->
c_map_pair().

ann_c_map_pair(As,Op,K,V) ->
#c_map_pair{op=Op, key = K, val=V, anno = As}.

-doc "".
-spec update_c_map_pair(c_map_pair(), map_op(), cerl(), cerl()) -> c_map_pair().

update_c_map_pair(Old,Op,K,V) ->
Expand Down
1 change: 1 addition & 0 deletions lib/compiler/src/cerl_trees.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,7 @@ filter_labels([A | As]) ->
filter_labels([]) ->
[].

-doc "".
-spec get_label(cerl()) -> 'top' | integer().

get_label(T) ->
Expand Down
18 changes: 13 additions & 5 deletions lib/compiler/src/compile.erl
Original file line number Diff line number Diff line change
Expand Up @@ -708,11 +708,19 @@ value are listed.
enabled in a module that may load NIFs, as the compiler may inline NIF
fallbacks by accident. Use this option to turn off this kind of warnings.
- **`warn_missing_doc`[](){: #warn_missing_doc } **
By default, warnings are not emitted when `-doc` attribute for an exported function
is not given. Use this option to turn on this kind of warning.
- **`nowarn_hidden_doc` | `{nowarn_hidden_doc,NAs}`[](){: #nowarn_hidden_doc } **
- **`warn_missing_doc` | `warn_missing_doc_functions` | `warn_missing_doc_types` | `warn_missing_doc_callbacks` **{: #warn_missing_doc }
By default, warnings are not emitted when `-doc` attribute for an exported function,
callback or type is not given. Use these option to turn on this kind of warning.
`warn_missing_doc` is equivalent to setting all of `warn_missing_doc_functions`,
`warn_missing_doc_types` and `warn_missing_doc_callbacks`.
- **`nowarn_missing_doc` | `nowarn_missing_doc_functions` | `nowarn_missing_doc_types` | `nowarn_missing_doc_callbacks` **
If warnings are enabled by [`warn_missing_doc`](#warn_missing_doc), then you can use
these options turn those warnings off again.
`nowarn_missing_doc` is equivalent to setting all of `nowarn_missing_doc_functions`,
`nowarn_missing_doc_types` and `nowarn_missing_doc_callbacks`.
- **`nowarn_hidden_doc` | `{nowarn_hidden_doc,NAs}`**{: #nowarn_hidden_doc }
By default, warnings are emitted when `-doc false` attribute is set on a
[callback or referenced type](`e:system:documentation.md#what-is-visible-versus-hidden`).
You can set `nowarn_hidden_doc` to suppress all those warnings, or `{nowarn_hidden_doc, NAs}`
Expand Down
1 change: 1 addition & 0 deletions lib/compiler/src/core_parse.yrl
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ Header
"".

Erlang code.
-moduledoc false.

-include("core_parse.hrl").

Expand Down
78 changes: 62 additions & 16 deletions lib/compiler/test/beam_doc_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,24 @@ deprecated(Conf) ->
ok.

warn_missing_doc(Conf) ->

warn_missing_doc(Conf, [function, type, callback], [warn_missing_doc]),
warn_missing_doc(Conf, [function], [warn_missing_doc_functions]),
warn_missing_doc(Conf, [function, type], [warn_missing_doc_functions, warn_missing_doc_types]),
warn_missing_doc(Conf, [type, callback], [warn_missing_doc_types, warn_missing_doc_callbacks]),
warn_missing_doc(Conf, [callback], [warn_missing_doc_callbacks]),

warn_missing_doc(Conf, [type, callback], [warn_missing_doc, nowarn_missing_doc_functions]),
warn_missing_doc(Conf, [function, callback], [warn_missing_doc, nowarn_missing_doc_types]),
warn_missing_doc(Conf, [type], [warn_missing_doc, nowarn_missing_doc_callbacks, nowarn_missing_doc_functions]),
warn_missing_doc(Conf, [], [warn_missing_doc_functions, nowarn_missing_doc]),

ok.

warn_missing_doc(Conf, ExpectedWarnings, Options) ->
ModuleName = ?get_name(),
{ok, ModName, [{File,Warnings}, {HrlFile, HrlWarnings}]} =
default_compile_file(Conf, ModuleName, [return_warnings, warn_missing_doc, report]),
{ok, ModName, Ws} =
default_compile_file(Conf, ModuleName, [return_warnings, report | Options]),

{ok, {docs_v1, _,_, _, none, _,
[{{type,test,1},_,[<<"test(N)">>],none,_},
Expand All @@ -431,20 +446,51 @@ warn_missing_doc(Conf) ->
{{function,test,2},_,[<<"test(N, M)">>],none,_}]}
} = code:get_doc(ModName),

?assertEqual("warn_missing_doc.erl", filename:basename(File)),
?assertEqual(6, length(Warnings)),
?assertMatch({1, beam_doc, missing_moduledoc}, lists:nth(1, Warnings)),
?assertMatch({{6,2}, beam_doc, {missing_doc, {type,test,0}}}, lists:nth(2, Warnings)),
?assertMatch({{7,2}, beam_doc, {missing_doc, {type,test,1}}}, lists:nth(3, Warnings)),
?assertMatch({{9,2}, beam_doc, {missing_doc, {callback,test,0}}}, lists:nth(4, Warnings)),
?assertMatch({{13,1}, beam_doc, {missing_doc, {function,test,0}}}, lists:nth(5, Warnings)),
?assertMatch({{14,1}, beam_doc, {missing_doc, {function,test,1}}}, lists:nth(6, Warnings)),

?assertEqual("warn_missing_doc.hrl", filename:basename(HrlFile)),
?assertEqual(1, length(HrlWarnings)),
?assertMatch({{2,1}, beam_doc, {missing_doc, {function,test,2}}}, lists:nth(1, HrlWarnings)),

ok.
case ExpectedWarnings of
[] ->
?assertEqual([],Ws);
_ ->
[{File,Warnings} | Hrl] = Ws,
ExpectedWarningCount = 1 + lists:sum(
lists:flatten(
[[2 || lists:member(type, ExpectedWarnings)],
[1 || lists:member(callback, ExpectedWarnings)],
[2 || lists:member(function, ExpectedWarnings)]])),

?assertEqual("warn_missing_doc.erl", filename:basename(File)),
?assertEqual(ExpectedWarningCount, length(Warnings)),
?assertMatch({1, beam_doc, missing_moduledoc}, lists:nth(1, Warnings)),
TypePos =
case lists:member(type, ExpectedWarnings) of
true ->
?assertMatch({{6,2}, beam_doc, {missing_doc, {type,test,0}}}, lists:nth(2, Warnings)),
?assertMatch({{7,2}, beam_doc, {missing_doc, {type,test,1}}}, lists:nth(3, Warnings)),
4;
false ->
2
end,

CBPos =
case lists:member(callback, ExpectedWarnings) of
true ->
?assertMatch({{9,2}, beam_doc, {missing_doc, {callback,test,0}}}, lists:nth(TypePos, Warnings)),
TypePos + 1;
false ->
TypePos
end,

case lists:member(function, ExpectedWarnings) of
true ->
?assertMatch({{13,1}, beam_doc, {missing_doc, {function,test,0}}}, lists:nth(CBPos, Warnings)),
?assertMatch({{14,1}, beam_doc, {missing_doc, {function,test,1}}}, lists:nth(CBPos+1, Warnings)),
[{HrlFile, HrlWarnings}] = Hrl,
?assertEqual("warn_missing_doc.hrl", filename:basename(HrlFile)),
?assertEqual(1, length(HrlWarnings)),
?assertMatch({{2,1}, beam_doc, {missing_doc, {function,test,2}}}, lists:nth(1, HrlWarnings));
false ->
ok
end
end.

doc_with_file(Conf) ->
ModuleName = ?get_name(),
Expand Down
1 change: 1 addition & 0 deletions lib/dialyzer/src/dialyzer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ run_report_modules_analyzed(Opts) ->
{Warnings, _ModulesChanged, ModulesAnalyzed} = run_report_modules_changed_and_analyzed(Opts),
{Warnings, ModulesAnalyzed}.

-doc false.
run_report_modules_changed_and_analyzed(Opts) ->
try dialyzer_options:build([{report_mode, quiet},
{erlang_mode, true}|Opts]) of
Expand Down
3 changes: 3 additions & 0 deletions lib/diameter/src/compiler/diameter_dict_parser.yrl
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,6 @@ avp_code -> number : '$1'.

avp_vendor -> '$empty' : false.
avp_vendor -> number : '$1'.

Erlang code.
-moduledoc false.
2 changes: 1 addition & 1 deletion lib/et/examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
ERL_COMPILE_FLAGS += -pa ../../et/ebin
ERL_COMPILE_FLAGS += -pa ../../et/ebin +nowarn_missing_doc
EBIN = .

# ----------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion lib/eunit/src/eunit_autoexport.erl
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ rewrite([], As, Module, Test) ->
[{function,L,test,0,
[{clause,L,[],[],
[{call,L,{remote,L,{atom,L,eunit},{atom,L,test}},
[{atom,L,Module}]}]}]}
[{atom,L,Module}]}]}]},
{attribute,L,doc,false}
| As];
true ->
As
Expand Down
Loading

0 comments on commit 375ffcd

Please sign in to comment.