aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2014-02-03 12:24:34 +0100
committerBjörn Gustavsson <[email protected]>2014-02-05 09:59:34 +0100
commit89bbe43c61320d6415d2f530df54dc4f6ccf03d4 (patch)
treeaa285e1e88e63bfafa8c05898c31db2c61c95bdc /lib
parent8ad4c1c9b3a13d0236a03d4f47fb3b847d8e5cee (diff)
downloadotp-89bbe43c61320d6415d2f530df54dc4f6ccf03d4.tar.gz
otp-89bbe43c61320d6415d2f530df54dc4f6ccf03d4.tar.bz2
otp-89bbe43c61320d6415d2f530df54dc4f6ccf03d4.zip
dialyzer: Silence useless warnings about list comprehensions
Dialyzer will warn if the value of list comprehension is ignored by putting it in a sequence like this: [SomeSideEffect(E) || E <- Es], ok To avoid a warning, you'll have to write: _ = [SomeSideEffect(E) || E <- Es], ok Most of the time, this warning is merely annoying because it does not point out any real errors. Kostis Sagonas suggested that by suppressing the warning for list comprehension that return a list of a simple type (e.g. ['ok']), there would be no warning for code such as: [io:format("~p\n", [E]) || E <- Es], ok but there would be still be a warning for: [file:close(Fd) || Fd <- Fds], ok because an error condition is ignored.
Diffstat (limited to 'lib')
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl14
-rw-r--r--lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/unmatched_returns_SUITE_data/results/lc_warnings5
-rw-r--r--lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/lc_warnings.erl95
-rw-r--r--lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/opaque_atom_adt.erl9
5 files changed, 122 insertions, 2 deletions
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 33fa107019..288d2dfbeb 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -58,10 +58,12 @@
t_fun_range/2, t_integer/0, t_integers/1,
t_is_any/1, t_is_atom/1, t_is_atom/2, t_is_any_atom/3,
t_is_boolean/2,
- t_is_integer/2, t_is_nil/2, t_is_none/1, t_is_none_or_unit/1,
+ t_is_integer/2, t_is_list/1,
+ t_is_nil/2, t_is_none/1, t_is_none_or_unit/1,
t_is_number/2, t_is_reference/2, t_is_pid/2, t_is_port/2,
t_is_unit/1,
- t_limit/2, t_list/0, t_maybe_improper_list/0, t_module/0,
+ t_limit/2, t_list/0, t_list_elements/2,
+ t_maybe_improper_list/0, t_module/0,
t_none/0, t_non_neg_integer/0, t_number/0, t_number_vals/2,
t_pid/0, t_port/0, t_product/1, t_reference/0,
t_to_string/2, t_to_tlist/1,
@@ -293,6 +295,7 @@ traverse(Tree, Map, State) ->
t_is_any(ArgType)
orelse t_is_simple(ArgType, State)
orelse is_call_to_send(Arg)
+ orelse is_lc_simple_list(Arg, ArgType, State)
of
true -> % do not warn in these cases
State1;
@@ -2710,6 +2713,13 @@ is_call_to_send(Tree) ->
andalso (Arity =:= 2)
end.
+is_lc_simple_list(Tree, TreeType, State) ->
+ Opaques = State#state.opaques,
+ Ann = cerl:get_ann(Tree),
+ lists:member(list_comprehension, Ann)
+ andalso t_is_list(TreeType)
+ andalso t_is_simple(t_list_elements(TreeType, Opaques), State).
+
filter_match_fail([Clause] = Cls) ->
Body = cerl:clause_body(Clause),
case cerl:type(Body) of
diff --git a/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options b/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..49ac917f61
--- /dev/null
+++ b/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [unmatched_returns]}]}.
diff --git a/lib/dialyzer/test/unmatched_returns_SUITE_data/results/lc_warnings b/lib/dialyzer/test/unmatched_returns_SUITE_data/results/lc_warnings
new file mode 100644
index 0000000000..2784f2119e
--- /dev/null
+++ b/lib/dialyzer/test/unmatched_returns_SUITE_data/results/lc_warnings
@@ -0,0 +1,5 @@
+
+lc_warnings.erl:32: Expression produces a value of type [opaque_atom_adt:opaque_atom()], but this value is unmatched
+lc_warnings.erl:43: Expression produces a value of type [array()], but this value is unmatched
+lc_warnings.erl:65: Expression produces a value of type [lc_warnings:opaque_tuple()], but this value is unmatched
+lc_warnings.erl:7: Expression produces a value of type ['ok' | {'error',atom()}], but this value is unmatched
diff --git a/lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/lc_warnings.erl b/lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/lc_warnings.erl
new file mode 100644
index 0000000000..cb01a8fde3
--- /dev/null
+++ b/lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/lc_warnings.erl
@@ -0,0 +1,95 @@
+-module(lc_warnings).
+-compile([export_all]).
+
+close(Fs) ->
+ %% There should be a warning since we ignore a potential
+ %% {error,Error} return from file:close/1.
+ [file:close(F) || F <- Fs],
+
+ %% No warning because the type of unmatched return will be ['ok']
+ %% (which is a list of a simple type).
+ [ok = file:close(F) || F <- Fs],
+
+ %% Suppressed.
+ _ = [file:close(F) || F <- Fs],
+ ok.
+
+format(X) ->
+ %% No warning since the result of the list comprehension is
+ %% a list of simple.
+ [io:format("~p\n", [E]) || E <- X],
+
+ %% Warning explicitly suppressed.
+ _ = [io:format("~p\n", [E]) || E <- X],
+ ok.
+
+opaque1() ->
+ List = gen_atom(),
+ %% This is a list of an externally defined opaque type. Since
+ %% we are not allowed to peek inside opaque types, there should
+ %% be a warning (even though the type in this case happens to be
+ %% an atom).
+ [E || E <- List],
+
+ %% Suppressed.
+ _ = [E || E <- List],
+ ok.
+
+opaque2() ->
+ List = gen_array(),
+ %% This is an list of an externally defined opaque type. Since
+ %% we are not allowed to peek inside opaque types, there should
+ %% be a warning.
+ [E || E <- List],
+
+ %% Suppressed.
+ _ = [E || E <- List],
+ ok.
+
+opaque3() ->
+ List = gen_int(),
+
+ %% No warning, since we are allowed to look into the type and can
+ %% see that it is a simple type.
+ [E || E <- List],
+
+ %% Suppressed.
+ _ = [E || E <- List],
+ ok.
+
+opaque4() ->
+ List = gen_tuple(),
+
+ %% There should be a warning, since we are allowed to look inside
+ %% the opaque type and see that it is a tuple (non-simple).
+ [E || E <- List],
+
+ %% Suppressed.
+ _ = [E || E <- List],
+ ok.
+
+gen_atom() ->
+ [opaque_atom_adt:atom(ok)].
+
+gen_array() ->
+ [array:new()].
+
+
+gen_int() ->
+ [opaque_int(42)].
+
+gen_tuple() ->
+ [opaque_tuple(x, 25)].
+
+-opaque opaque_int() :: integer().
+
+-spec opaque_int(integer()) -> opaque_int().
+
+opaque_int(Int) -> Int.
+
+-opaque opaque_tuple() :: {any(),any()}.
+
+-spec opaque_tuple(any(), any()) -> opaque_tuple().
+
+opaque_tuple(X, Y) ->
+ {X,Y}.
diff --git a/lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/opaque_atom_adt.erl b/lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/opaque_atom_adt.erl
new file mode 100644
index 0000000000..b5b51fe75b
--- /dev/null
+++ b/lib/dialyzer/test/unmatched_returns_SUITE_data/src/lc_warnings/opaque_atom_adt.erl
@@ -0,0 +1,9 @@
+-module(opaque_atom_adt).
+-export([atom/1]).
+
+-opaque opaque_atom() :: atom().
+
+-spec atom(atom()) -> opaque_atom().
+
+atom(Atom) ->
+ Atom.