aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorStavros Aronis <[email protected]>2012-01-22 17:43:48 +0100
committerStavros Aronis <[email protected]>2012-02-22 14:13:08 +0100
commit4ca72667f3e655d175c7587b8998aa7d22f50985 (patch)
tree307e4372295330fbc3db75fb772ef370bcc85ba9 /lib
parent7c3a98b560a80878c603fabe26ca4a572bfe9122 (diff)
downloadotp-4ca72667f3e655d175c7587b8998aa7d22f50985.tar.gz
otp-4ca72667f3e655d175c7587b8998aa7d22f50985.tar.bz2
otp-4ca72667f3e655d175c7587b8998aa7d22f50985.zip
Zero-arity unused functions Dialyzer patch
Dialyzer was not reporting unused functions with 0 arity. This was not a real issue, until we found out that there could be cases where this could lead to false warnings. This was the case in "no_local_return.erl".
Diffstat (limited to 'lib')
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl54
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/results/compiler1
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/inets1
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/inf_loop22
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/no_local_return3
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl12
7 files changed, 43 insertions, 32 deletions
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 8930054210..887b2dd049 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -316,27 +316,26 @@ analyze_module(Tree, Plt, Callgraph, Records, GetWarnings) ->
analyze_loop(#state{callgraph = Callgraph, races = Races} = State) ->
case state__get_work(State) of
- none -> state__clean_not_called(State);
- {Fun, NewState} ->
- ArgTypes = state__get_args(Fun, NewState),
- case any_none(ArgTypes) of
+ none -> State;
+ {Fun, NewState1} ->
+ {ArgTypes, IsCalled} = state__get_args_and_status(Fun, NewState1),
+ case not IsCalled of
true ->
- ?debug("Not handling1 ~w: ~s\n",
+ ?debug("Not handling (not called) ~w: ~s\n",
[state__lookup_name(get_label(Fun), State),
t_to_string(t_product(ArgTypes))]),
- analyze_loop(NewState);
+ analyze_loop(NewState1);
false ->
- case state__fun_env(Fun, NewState) of
+ case state__fun_env(Fun, NewState1) of
none ->
- ?debug("Not handling2 ~w: ~s\n",
+ ?debug("Not handling (no env) ~w: ~s\n",
[state__lookup_name(get_label(Fun), State),
t_to_string(t_product(ArgTypes))]),
- analyze_loop(NewState);
+ analyze_loop(NewState1);
Map ->
?debug("Handling fun ~p: ~s\n",
[state__lookup_name(get_label(Fun), State),
- t_to_string(state__fun_type(Fun, NewState))]),
- NewState1 = state__mark_fun_as_handled(NewState, Fun),
+ t_to_string(state__fun_type(Fun, NewState1))]),
Vars = cerl:fun_vars(Fun),
Map1 = enter_type_lists(Vars, ArgTypes, Map),
Body = cerl:fun_body(Fun),
@@ -2888,22 +2887,16 @@ state__new(Callgraph, Tree, Plt, Module, Records, BehaviourTranslations) ->
TreeMap = build_tree_map(Tree),
Funs = dict:fetch_keys(TreeMap),
FunTab = init_fun_tab(Funs, dict:new(), TreeMap, Callgraph, Plt, Opaques),
- Work = init_work([get_label(Tree)]),
- Env = dict:store(top, map__new(), dict:new()),
+ ExportedFuns =
+ [Fun || Fun <- Funs--[top], dialyzer_callgraph:is_escaping(Fun, Callgraph)],
+ Work = init_work(ExportedFuns),
+ Env = lists:foldl(fun(Fun, Env) -> dict:store(Fun, map__new(), Env) end,
+ dict:new(), Funs),
#state{callgraph = Callgraph, envs = Env, fun_tab = FunTab, opaques = Opaques,
plt = Plt, races = dialyzer_races:new(), records = Records,
warning_mode = false, warnings = [], work = Work, tree_map = TreeMap,
module = Module, behaviour_api_dict = BehaviourTranslations}.
-state__mark_fun_as_handled(#state{fun_tab = FunTab} = State, Fun0) ->
- Fun = get_label(Fun0),
- case dict:find(Fun, FunTab) of
- {ok, {not_handled, Entry}} ->
- State#state{fun_tab = dict:store(Fun, Entry, FunTab)};
- {ok, {_, _}} ->
- State
- end.
-
state__warning_mode(#state{warning_mode = WM}) ->
WM.
@@ -2981,7 +2974,7 @@ state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
{NotCalled, Ret} =
case dict:fetch(get_label(Fun), FunTab) of
{not_handled, {_Args0, Ret0}} -> {true, Ret0};
- {Args0, Ret0} -> {any_none(Args0), Ret0}
+ {_Args0, Ret0} -> {false, Ret0}
end,
case NotCalled of
true ->
@@ -3075,11 +3068,11 @@ state__lookup_record(Tag, Arity, #state{records = Records}) ->
error
end.
-state__get_args(Tree, #state{fun_tab = FunTab}) ->
+state__get_args_and_status(Tree, #state{fun_tab = FunTab}) ->
Fun = get_label(Tree),
case dict:find(Fun, FunTab) of
- {ok, {not_handled, {ArgTypes, _}}} -> ArgTypes;
- {ok, {ArgTypes, _}} -> ArgTypes
+ {ok, {not_handled, {ArgTypes, _}}} -> {ArgTypes, false};
+ {ok, {ArgTypes, _}} -> {ArgTypes, true}
end.
build_tree_map(Tree) ->
@@ -3095,7 +3088,7 @@ build_tree_map(Tree) ->
cerl_trees:fold(Fun, dict:new(), Tree).
init_fun_tab([top|Left], Dict, TreeMap, Callgraph, Plt, Opaques) ->
- NewDict = dict:store(top, {not_handled, {[], t_none()}}, Dict),
+ NewDict = dict:store(top, {[], t_none()}, Dict),
init_fun_tab(Left, NewDict, TreeMap, Callgraph, Plt, Opaques);
init_fun_tab([Fun|Left], Dict, TreeMap, Callgraph, Plt, Opaques) ->
Arity = cerl:fun_arity(dict:fetch(Fun, TreeMap)),
@@ -3111,9 +3104,9 @@ init_fun_tab([Fun|Left], Dict, TreeMap, Callgraph, Plt, Opaques) ->
false -> {Args, t_unit()}
end
end;
- false -> {lists:duplicate(Arity, t_none()), t_unit()}
+ false -> {not_handled, {lists:duplicate(Arity, t_none()), t_unit()}}
end,
- NewDict = dict:store(Fun, {not_handled, FunEntry}, Dict),
+ NewDict = dict:store(Fun, FunEntry, Dict),
init_fun_tab(Left, NewDict, TreeMap, Callgraph, Plt, Opaques);
init_fun_tab([], Dict, _TreeMap, _Callgraph, _Plt, _Opaques) ->
Dict.
@@ -3137,7 +3130,8 @@ state__clean_not_called(#state{fun_tab = FunTab} = State) ->
end, FunTab),
State#state{fun_tab = NewFunTab}.
-state__all_fun_types(#state{fun_tab = FunTab}) ->
+state__all_fun_types(State) ->
+ #state{fun_tab = FunTab} = state__clean_not_called(State),
Tab1 = dict:erase(top, FunTab),
dict:map(fun(_Fun, {Args, Ret}) -> t_fun(Args, Ret)end, Tab1).
diff --git a/lib/dialyzer/test/options1_SUITE_data/results/compiler b/lib/dialyzer/test/options1_SUITE_data/results/compiler
index e82087ae86..6399e3e36b 100644
--- a/lib/dialyzer/test/options1_SUITE_data/results/compiler
+++ b/lib/dialyzer/test/options1_SUITE_data/results/compiler
@@ -20,6 +20,7 @@ cerl_inline.erl:2333: The pattern 'true' can never match the type 'false'
cerl_inline.erl:2355: The pattern 'true' can never match the type 'false'
cerl_inline.erl:238: The pattern 'true' can never match the type 'false'
cerl_inline.erl:2436: Function filename/1 will never be called
+cerl_inline.erl:244: Function counter_stats/0 will never be called
cerl_inline.erl:2700: The pattern 'true' can never match the type 'false'
cerl_inline.erl:2730: The pattern <{F, L, D}, Vs> can never match the type <[1..255,...],[any()]>
cerl_inline.erl:2738: The pattern <{F, L, D}, Vs> can never match the type <[1..255,...],[any()]>
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets
index 24cb39e52b..773525eb7f 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/inets
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets
@@ -8,6 +8,7 @@ http_lib.erl:424: The variable _ can never match since previous clauses complete
http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any()
http_lib.erl:99: Function getHeaderValue/2 will never be called
httpc_handler.erl:660: Function exit_session_ok/2 has no local return
+httpc_handler.erl:676: Function format_time/0 will never be called
httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:160: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:478: The pattern {'error', Reason} can never match the type 'ok' | {number(),#session{clientclose::boolean(),pipeline::[],quelength::1}}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify b/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify
index 87bf6f309f..06dc0d63ee 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify
+++ b/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify
@@ -1,4 +1,4 @@
cerl_hipeify.erl:370: Function will never be called
-cerl_hipeify.erl:370: Guard test fun((none()) -> none()) =:= F::{_,_,_} | {_,_,_,_} | {_,_,_,_,_} | {_,_,_,_,_,_} | {_,_,_,_,_,_,_} can never succeed
+cerl_hipeify.erl:370: Guard test fun((none()) -> no_return()) =:= F::{_,_,_} | {_,_,_,_} | {_,_,_,_,_} | {_,_,_,_,_,_} | {_,_,_,_,_,_,_} can never succeed
cerl_hipeify.erl:641: Function env__new_function_name/2 will never be called
diff --git a/lib/dialyzer/test/small_SUITE_data/results/inf_loop2 b/lib/dialyzer/test/small_SUITE_data/results/inf_loop2
index 7e9972ad98..142e4b2c37 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/inf_loop2
+++ b/lib/dialyzer/test/small_SUITE_data/results/inf_loop2
@@ -1,4 +1,4 @@
inf_loop2.erl:18: Function test/0 has no local return
inf_loop2.erl:19: The call lists:reverse('gazonk') will never return since it differs in the 1st argument from the success typing arguments: ([any()])
-inf_loop2.erl:22: Function loop/0 has no local return
+inf_loop2.erl:22: Function loop/0 will never be called
diff --git a/lib/dialyzer/test/small_SUITE_data/results/no_local_return b/lib/dialyzer/test/small_SUITE_data/results/no_local_return
new file mode 100644
index 0000000000..6ca1ed51d8
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/no_local_return
@@ -0,0 +1,3 @@
+
+no_local_return.erl:11: Function bar/1 will never be called
+no_local_return.erl:8: Function foo/0 will never be called
diff --git a/lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl b/lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl
new file mode 100644
index 0000000000..4e1a0b015a
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl
@@ -0,0 +1,12 @@
+-module(no_local_return).
+
+%% NOTE: No function is exported. Dialyzer produced a bogus
+%% 'Function foo/0 has no local return' warning
+%% when in fact typer was finding correct return values for both
+%% these functions.
+
+foo() ->
+ bar(42).
+
+bar(X) ->
+ lists:duplicate(X, gazonk).