aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/src')
-rw-r--r--lib/dialyzer/src/dialyzer.erl24
-rw-r--r--lib/dialyzer/src/dialyzer.hrl4
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl47
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl9
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl10
5 files changed, 66 insertions, 28 deletions
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index 487a12b252..3e3c12405f 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -442,18 +442,24 @@ message_to_string({opaque_type_test, [Fun, Opaque]}) ->
message_to_string({race_condition, [M, F, Args, Reason]}) ->
io_lib:format("The call ~w:~w~s ~s\n", [M, F, Args, Reason]);
%%----- Warnings for behaviour errors --------------------
-message_to_string({callback_type_mismatch, [B, F, A, T]}) ->
- io_lib:format("The inferred return type for ~w/~w is ~s which is not valid"
- " return for the callback of the ~w behaviour\n",
- [F, A, T, B]);
-message_to_string({callback_arg_type_mismatch, [B, F, A, N, T]}) ->
- io_lib:format("The inferred type for the ~s argument of ~w/~w is ~s which is"
- " not valid for the callback of the ~w behaviour"
- "\n", [ordinal(N), F, A, T, B]);
+message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}) ->
+ io_lib:format("The inferred return type of ~w/~w (~s) has nothing in common"
+ " with ~s, which is the expected return type for the callback of"
+ " ~w behaviour\n", [F, A, ST, CT, B]);
+message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
+ io_lib:format("The inferred type for the ~s argument of ~w/~w (~s) is"
+ " not a supertype of ~s, which is expected type for this"
+ " argument in the callback of the ~w behaviour\n",
+ [ordinal(N), F, A, ST, CT, B]);
message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}) ->
io_lib:format("The return type ~s in the specification of ~w/~w is not a"
" subtype of ~s, which is the expected return type for the"
- " callback of ~w behaviour.\n", [ST, F, A, CT, B]);
+ " callback of ~w behaviour\n", [ST, F, A, CT, B]);
+message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
+ io_lib:format("The specified type for the ~s argument of ~w/~w (~s) is"
+ " not a supertype of ~s, which is expected type for this"
+ " argument in the callback of the ~w behaviour\n",
+ [ordinal(N), F, A, ST, CT, B]);
message_to_string({callback_missing, [B, F, A]}) ->
io_lib:format("Undefined callback function ~w/~w (behaviour '~w')\n",
[F, A, B]);
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index 9d2e554981..5e089d1773 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -57,6 +57,7 @@
-define(WARN_UNMATCHED_RETURN, warn_umatched_return).
-define(WARN_RACE_CONDITION, warn_race_condition).
-define(WARN_BEHAVIOUR, warn_behaviour).
+-define(WARN_UNDEFINED_CALLBACK, warn_undefined_callbacks).
%%
%% The following type has double role:
@@ -71,7 +72,8 @@
| ?WARN_CONTRACT_NOT_EQUAL | ?WARN_CONTRACT_SUBTYPE
| ?WARN_CONTRACT_SUPERTYPE | ?WARN_CALLGRAPH
| ?WARN_UNMATCHED_RETURN | ?WARN_RACE_CONDITION
- | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE.
+ | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE
+ | ?WARN_UNDEFINED_CALLBACK.
%%
%% This is the representation of each warning as they will be returned
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl
index a30707c7c3..56eb46d78a 100644
--- a/lib/dialyzer/src/dialyzer_behaviours.erl
+++ b/lib/dialyzer/src/dialyzer_behaviours.erl
@@ -125,7 +125,8 @@ check_all_callbacks(Module, Behaviour, [Cb|Rest],
true ->
[{callback_type_mismatch,
[Behaviour, Function, Arity,
- erl_types:t_to_string(ReturnType, Records)]}|Acc00]
+ erl_types:t_to_string(ReturnType, Records),
+ erl_types:t_to_string(CbReturnType, Records)]}|Acc00]
end
end,
Acc02 =
@@ -133,7 +134,7 @@ check_all_callbacks(Module, Behaviour, [Cb|Rest],
erl_types:t_inf_lists(ArgTypes, CbArgTypes)) of
false -> Acc01;
true ->
- find_mismatching_args(ArgTypes, CbArgTypes, Behaviour,
+ find_mismatching_args(type, ArgTypes, CbArgTypes, Behaviour,
Function, Arity, Records, 1, Acc01)
end,
Acc02
@@ -153,24 +154,40 @@ check_all_callbacks(Module, Behaviour, [Cb|Rest],
erl_types:t_to_string(SpecReturnType, Records),
erl_types:t_to_string(CbReturnType, Records)]}|Acc10]
end,
- Acc11
+ Acc12 =
+ case erl_types:any_none(
+ erl_types:t_inf_lists(SpecArgTypes, CbArgTypes)) of
+ false -> Acc11;
+ true ->
+ find_mismatching_args({spec, File, Line}, SpecArgTypes,
+ CbArgTypes, Behaviour, Function,
+ Arity, Records, 1, Acc11)
+ end,
+ Acc12
end,
NewAcc = Acc2,
check_all_callbacks(Module, Behaviour, Rest, State, NewAcc).
-find_mismatching_args([], [], _Beh, _Function, _Arity, _Records, _N, Acc) ->
+find_mismatching_args(_, [], [], _Beh, _Function, _Arity, _Records, _N, Acc) ->
Acc;
-find_mismatching_args([Type|Rest], [CbType|CbRest], Behaviour,
+find_mismatching_args(Kind, [Type|Rest], [CbType|CbRest], Behaviour,
Function, Arity, Records, N, Acc) ->
case erl_types:t_is_none(erl_types:t_inf(Type, CbType)) of
false ->
- find_mismatching_args(Rest, CbRest, Behaviour, Function,
+ find_mismatching_args(Kind, Rest, CbRest, Behaviour, Function,
Arity, Records, N+1, Acc);
true ->
+ Info =
+ [Behaviour, Function, Arity, N,
+ erl_types:t_to_string(Type, Records),
+ erl_types:t_to_string(CbType, Records)],
NewAcc =
- [{callback_arg_type_mismatch,
- [Behaviour, Function, Arity, N, erl_types:t_to_string(Type, Records)]}|Acc],
- find_mismatching_args(Rest, CbRest, Behaviour, Function,
+ [case Kind of
+ type -> {callback_arg_type_mismatch, Info};
+ {spec, File, Line} ->
+ {callback_spec_arg_type_mismatch, [File, Line | Info]}
+ end | Acc],
+ find_mismatching_args(Kind, Rest, CbRest, Behaviour, Function,
Arity, Records, N+1, NewAcc)
end.
@@ -178,9 +195,15 @@ add_tag_file_line(_Module, {Tag, [B|_R]} = Warn, State)
when Tag =:= callback_missing;
Tag =:= callback_info_missing ->
{B, Line} = lists:keyfind(B, 1, State#state.behlines),
- {?WARN_BEHAVIOUR, {State#state.filename, Line}, Warn};
-add_tag_file_line(Module, {Tag, [File, Line|R]}, State)
- when Tag =:= callback_spec_type_mismatch ->
+ Category =
+ case Tag of
+ callback_missing -> ?WARN_BEHAVIOUR;
+ callback_info_missing -> ?WARN_UNDEFINED_CALLBACK
+ end,
+ {Category, {State#state.filename, Line}, Warn};
+add_tag_file_line(_Module, {Tag, [File, Line|R]}, _State)
+ when Tag =:= callback_spec_type_mismatch;
+ Tag =:= callback_spec_arg_type_mismatch ->
{?WARN_BEHAVIOUR, {File, Line}, {Tag, R}};
add_tag_file_line(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) ->
{_A, FunCode} =
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index f80eb81ac6..ff8fc39a5e 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -491,6 +491,12 @@ warning_options_msg() ->
Suppress warnings for patterns that are unused or cannot match.
-Wno_opaque
Suppress warnings for violations of opaqueness of data types.
+ -Wno_behaviours
+ Suppress warnings about behaviour callbacks which drift from the published
+ recommended interfaces.
+ -Wno_undefined_callbacks
+ Suppress warnings about behaviours that have no -callback attributes for
+ their callbacks.
-Wunmatched_returns ***
Include warnings for function calls which ignore a structured return
value or do not match against one of many possible return value(s).
@@ -498,9 +504,6 @@ warning_options_msg() ->
Include warnings for functions that only return by means of an exception.
-Wrace_conditions ***
Include warnings for possible race conditions.
- -Wbehaviours ***
- Include warnings about behaviour callbacks which drift from the published
- recommended interfaces.
-Wunderspecs ***
Warn about underspecified functions
(those whose -spec is strictly more allowing than the success typing).
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index b2a67de8bd..866650a0b2 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -49,7 +49,9 @@ build(Opts) ->
?WARN_CALLGRAPH,
?WARN_CONTRACT_RANGE,
?WARN_CONTRACT_TYPES,
- ?WARN_CONTRACT_SYNTAX],
+ ?WARN_CONTRACT_SYNTAX,
+ ?WARN_BEHAVIOUR,
+ ?WARN_UNDEFINED_CALLBACK],
DefaultWarns1 = ordsets:from_list(DefaultWarns),
InitPlt = dialyzer_plt:get_default_plt(),
DefaultOpts = #options{},
@@ -275,14 +277,16 @@ build_warnings([Opt|Opts], Warnings) ->
no_contracts ->
Warnings1 = ordsets:del_element(?WARN_CONTRACT_SYNTAX, Warnings),
ordsets:del_element(?WARN_CONTRACT_TYPES, Warnings1);
+ no_behaviours ->
+ ordsets:del_element(?WARN_BEHAVIOUR, Warnings);
+ no_undefined_callbacks ->
+ ordsets:del_element(?WARN_UNDEFINED_CALLBACK, Warnings);
unmatched_returns ->
ordsets:add_element(?WARN_UNMATCHED_RETURN, Warnings);
error_handling ->
ordsets:add_element(?WARN_RETURN_ONLY_EXIT, Warnings);
race_conditions ->
ordsets:add_element(?WARN_RACE_CONDITION, Warnings);
- behaviours ->
- ordsets:add_element(?WARN_BEHAVIOUR, Warnings);
specdiffs ->
S = ordsets:from_list([?WARN_CONTRACT_SUBTYPE,
?WARN_CONTRACT_SUPERTYPE,