aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/test/warnings_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/test/warnings_SUITE.erl')
-rw-r--r--lib/compiler/test/warnings_SUITE.erl554
1 files changed, 554 insertions, 0 deletions
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
new file mode 100644
index 0000000000..6e60ab88cb
--- /dev/null
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -0,0 +1,554 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(warnings_SUITE).
+
+%%-define(STANDALONE, true).
+
+-ifdef(STANDALONE).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(privdir, "warnings_SUITE_priv").
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(datadir, ?config(data_dir, Conf)).
+-define(privdir, ?config(priv_dir, Conf)).
+-endif.
+
+-export([all/1,init_per_testcase/2,fin_per_testcase/2]).
+
+-export([pattern/1,pattern2/1,pattern3/1,pattern4/1,
+ guard/1,bad_arith/1,bool_cases/1,bad_apply/1,
+ files/1,effect/1,bin_opt_info/1,bin_construction/1]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(2)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ test_lib:recompile(?MODULE),
+ [pattern,pattern2,pattern3,pattern4,
+ guard,bad_arith,bool_cases,bad_apply,files,effect,
+ bin_opt_info,bin_construction].
+
+pattern(Config) when is_list(Config) ->
+ %% Test warnings generated by v3_core.
+ Ts = [{pattern,
+ <<"%% Just a comment here.
+ f(a={glurf,2}=A) -> A.
+
+ g(A) ->
+ case A of
+ a=[_|_] -> error;
+ Other -> true
+ end.
+
+ foo(X) ->
+ a = {nisse,b} = X.
+ ">>,
+ [warn_unused_vars],
+ {warnings,
+ [{2,v3_core,nomatch},
+ {6,v3_core,nomatch},
+ {11,v3_core,nomatch} ] }}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+pattern2(Config) when is_list(Config) ->
+ %% Test warnings generated by sys_core_fold.
+ %% If we disable Core Erlang optimizations, we expect that
+ %% v3_kernel should generate some of the warnings.
+ Source = <<"f(A) -> ok;
+ f(B) -> error.
+ t(A, B, C) ->
+ case {A,B,C} of
+ {a,B} -> ok;
+ {_,B} -> ok
+ end.
+ ">>,
+
+ %% Test warnings from sys_core_fold.
+ Ts = [{pattern2,
+ Source,
+ [nowarn_unused_vars],
+ {warnings,[{2,sys_core_fold,{nomatch_shadow,1}},
+ {5,sys_core_fold,nomatch_clause_type},
+ {6,sys_core_fold,nomatch_clause_type}]}}],
+ ?line [] = run(Config, Ts),
+
+ %% Disable Core Erlang optimizations. v3_kernel should produce
+ %% a warning for the clause that didn't match.
+ Ts2 = [{pattern2,
+ Source,
+ [nowarn_unused_vars,no_copt],
+ {warnings,
+ [{2,v3_kernel,{nomatch_shadow,1}}]}}],
+ ?line [] = run(Config, Ts2),
+ ok.
+
+pattern3(Config) when is_list(Config) ->
+ %% Test warnings generated by the pattern matching compiler
+ %% in v3_kernel.
+
+ Ts = [{pattern3,
+ <<"
+ f({A,_}) -> {ok,A};
+ f([_|_]=B) -> {ok,B};
+ f({urk,nisse}) -> urka_glurka.
+ ">>,
+ [nowarn_unused_vars],
+ {warnings,
+ [{4,v3_kernel,{nomatch_shadow,2}}]}}],
+ ?line [] = run(Config, Ts),
+
+ ok.
+
+pattern4(Config) when is_list(Config) ->
+ %% Test warnings for clauses that cannot possibly match.
+
+ Ts = [{pattern4,
+ <<"
+ t() ->
+ case true of
+ false -> a;
+ true -> b
+ end.
+
+ fi() ->
+ case true of
+ false -> a;
+ false -> b
+ end,
+ case true of
+ true -> a;
+ true -> b;
+ X -> X
+ end,
+ case boolean of
+ true -> a;
+ false -> b
+ end.
+ int() ->
+ case 42 of
+ [a|b] -> no;
+ <<1>> -> no;
+ <<X>> -> no;
+ 17 -> no;
+ [] -> no;
+ a -> no;
+ {a,b,c} -> no
+ end.
+ tuple() ->
+ case {x,y,z} of
+ \"xyz\" -> no;
+ [a|b] -> no;
+ <<1>> -> no;
+ <<X>> -> no;
+ 17 -> no;
+ [] -> no;
+ a -> no;
+ {a,b,c} -> no;
+ {x,y} -> no
+ end.
+ ">>,
+ [nowarn_unused_vars],
+ {warnings,
+ [{9,sys_core_fold,no_clause_match},
+ {18,sys_core_fold,no_clause_match},
+ {23,sys_core_fold,no_clause_match},
+ {33,sys_core_fold,no_clause_match}
+ ]}}],
+ ?line [] = run(Config, Ts),
+
+ ok.
+
+guard(Config) when is_list(Config) ->
+ %% Test warnings for false guards.
+
+ Ts = [{guard,
+ <<"
+ t(A, B) when element(x, dum) -> ok.
+
+ tt(A, B) when 1 == 2 -> ok.
+
+ ttt() when element(x, dum) -> ok.
+
+ t4(T, F) when element({F}, T) -> ok.
+ t5(T, F) when element([F], T) -> ok.
+ t6(Pos, F) when element(Pos, [F]) -> ok.
+ t7(Pos) when element(Pos, []) -> ok.
+ ">>,
+ [nowarn_unused_vars],
+ {warnings,
+ [{2,sys_core_fold,no_clause_match},
+ {2,sys_core_fold,nomatch_guard},
+ {2,sys_core_fold,{eval_failure,badarg}},
+ {4,sys_core_fold,no_clause_match},
+ {4,sys_core_fold,nomatch_guard},
+ {6,sys_core_fold,no_clause_match},
+ {6,sys_core_fold,nomatch_guard},
+ {6,sys_core_fold,{eval_failure,badarg}},
+ {8,sys_core_fold,no_clause_match},
+ {8,sys_core_fold,nomatch_guard},
+ {8,sys_core_fold,{eval_failure,badarg}},
+ {9,sys_core_fold,no_clause_match},
+ {9,sys_core_fold,nomatch_guard},
+ {9,sys_core_fold,{eval_failure,badarg}},
+ {10,sys_core_fold,no_clause_match},
+ {10,sys_core_fold,nomatch_guard},
+ {10,sys_core_fold,{eval_failure,badarg}},
+ {11,sys_core_fold,no_clause_match},
+ {11,sys_core_fold,nomatch_guard},
+ {11,sys_core_fold,{eval_failure,badarg}}
+ ]}}],
+ ?line [] = run(Config, Ts),
+
+ ok.
+
+bad_arith(Config) when is_list(Config) ->
+ Ts = [{bad_arith,
+ <<"f() ->
+ if
+ a + 3 > 3 -> ok;
+ true -> error
+ end.
+
+ g(A) ->
+ if
+ is_integer(A), a + 3 > 3 -> ok;
+ a + 3 > 42, is_integer(A) -> ok;
+ true -> error
+ end.
+
+ h(A) ->
+ a + 3 + A.
+ ">>,
+ [],
+ {warnings,
+ [{3,sys_core_fold,nomatch_guard},
+ {3,sys_core_fold,{eval_failure,badarith}},
+ {9,sys_core_fold,nomatch_guard},
+ {9,sys_core_fold,{eval_failure,badarith}},
+ {10,sys_core_fold,nomatch_guard},
+ {10,sys_core_fold,{eval_failure,badarith}},
+ {15,sys_core_fold,{eval_failure,badarith}}
+ ] }}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+bool_cases(Config) when is_list(Config) ->
+ Ts = [{bool_cases,
+ <<"
+ f(A, B) ->
+ case A > B of
+ true -> true;
+ false -> false;
+ Other -> {error,not_bool}
+ end.
+
+ g(A, B) ->
+ case A =/= B of
+ false -> false;
+ true -> true;
+ Other -> {error,not_bool}
+ end.
+
+ h(Bool) ->
+ case not Bool of
+ maybe -> strange;
+ false -> ok;
+ true -> error
+ end.
+ ">>,
+ [nowarn_unused_vars],
+ {warnings,
+ [{6,sys_core_fold,nomatch_shadow},
+ {13,sys_core_fold,nomatch_shadow},
+ {18,sys_core_fold,nomatch_clause_type} ]} }],
+ ?line [] = run(Config, Ts),
+ ok.
+
+bad_apply(Config) when is_list(Config) ->
+ Ts = [{bad_apply,
+ <<"
+ t(1) -> 42:42();
+ t(2) -> erlang:42();
+ t(3) -> 42:start();
+ t(4) -> []:start();
+ t(5) -> erlang:[]().
+ ">>,
+ [],
+ {warnings,
+ [{2,v3_kernel,bad_call},
+ {3,v3_kernel,bad_call},
+ {4,v3_kernel,bad_call},
+ {5,v3_kernel,bad_call},
+ {6,v3_kernel,bad_call}]}}],
+ ?line [] = run(Config, Ts),
+
+ %% Also verify that the generated code generates the correct error.
+ ?line try erlang:42() of
+ _ -> ?line ?t:fail()
+ catch
+ error:badarg -> ok
+ end,
+ ok.
+
+files(Config) when is_list(Config) ->
+ Ts = [{files_1,
+ <<"
+ -file(\"file1\", 14).
+
+ t1() ->
+ 1/0.
+
+ -file(\"file2\", 7).
+
+ t2() ->
+ 1/0.
+ ">>,
+ [],
+ {warnings,
+ [{"file1",[{17,sys_core_fold,{eval_failure,badarith}}]},
+ {"file2",[{10,sys_core_fold,{eval_failure,badarith}}]}]}}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+%% Test warnings for term construction and BIF calls in effect context.
+effect(Config) when is_list(Config) ->
+ Ts = [{lc,
+ <<"
+ t(X) ->
+ case X of
+ warn_lc ->
+ [is_integer(Z) || Z <- [1,2,3]];
+ warn_lc_2 ->
+ [{error,Z} || Z <- [1,2,3]];
+ warn_lc_3 ->
+ [{error,abs(Z)} || Z <- [1,2,3]];
+ no_warn_lc ->
+ [put(last_integer, Z) || Z <- [1,2,3]]; %no warning
+ unused_tuple_literal ->
+ {a,b,c};
+ unused_list_literal ->
+ [1,2,3,4];
+ unused_integer ->
+ 42;
+ unused_arith ->
+ X*X;
+ nested ->
+ [{ok,node(),?MODULE:foo(),self(),[time(),date()],time()},
+ is_integer(X)];
+ unused_bit_syntax ->
+ <<X:8>>;
+ unused_fun ->
+ fun() -> {ok,X} end;
+ unused_atom ->
+ ignore; %no warning
+ unused_nil ->
+ []; %no warning
+ comp_op ->
+ X =:= 2;
+ cookie ->
+ erlang:get_cookie()
+ end,
+ ok.
+
+ %% No warnings should be generated in the following functions.
+ m1(X, Sz) ->
+ if
+ Sz =:= 0 -> X = 0;
+ true -> ok
+ end,
+ ok.
+
+ m2(X, Sz) ->
+ if
+ Sz =:= 0 -> X = {a,Sz};
+ true -> ok
+ end,
+ ok.
+
+ m3(X, Sz) ->
+ if
+ Sz =:= 0 -> X = [a,Sz];
+ true -> ok
+ end,
+ ok.
+
+ m4(X, Sz, Var) ->
+ if
+ Sz =:= 0 -> X = Var;
+ true -> ok
+ end,
+ ok.
+
+ m5(X, Sz) ->
+ if
+ Sz =:= 0 -> X = {a,b,c};
+ true -> ok
+ end,
+ ok.
+
+ m6(X, Sz) ->
+ if
+ Sz =:= 0 -> X = {a,Sz,[1,2,3]};
+ true -> ok
+ end,
+ ok.
+
+ m7(X, Sz) ->
+ if
+ Sz =:= 0 -> X = {a,Sz,[1,2,3],abs(Sz)};
+ true -> ok
+ end,
+ ok.
+ ">>,
+ [],
+ {warnings,[{5,sys_core_fold,{no_effect,{erlang,is_integer,1}}},
+ {7,sys_core_fold,useless_building},
+ {9,sys_core_fold,result_ignored},
+ {9,sys_core_fold,useless_building},
+ {13,sys_core_fold,useless_building},
+ {15,sys_core_fold,useless_building},
+ {17,sys_core_fold,useless_building},
+ {19,sys_core_fold,result_ignored},
+ {21,sys_core_fold,useless_building},
+ {21,sys_core_fold,{no_effect,{erlang,date,0}}},
+ {21,sys_core_fold,{no_effect,{erlang,node,0}}},
+ {21,sys_core_fold,{no_effect,{erlang,self,0}}},
+ {21,sys_core_fold,{no_effect,{erlang,time,0}}},
+ {22,sys_core_fold,useless_building},
+ {22,sys_core_fold,{no_effect,{erlang,is_integer,1}}},
+ {24,sys_core_fold,useless_building},
+ {26,sys_core_fold,useless_building},
+ {32,sys_core_fold,{no_effect,{erlang,'=:=',2}}},
+ {34,sys_core_fold,{no_effect,{erlang,get_cookie,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+bin_opt_info(Config) when is_list(Config) ->
+ Code = <<"
+ t1(Bin) ->
+ case Bin of
+ _ when byte_size(Bin) > 20 -> erlang:error(too_long);
+ <<_,T/binary>> -> t1(T);
+ <<>> -> ok
+ end.
+
+ t2(<<_,T/bytes>>) ->
+ split_binary(T, 4).
+ ">>,
+ Ts1 = [{bsm1,
+ Code,
+ [bin_opt_info],
+ {warnings,
+ [{4,sys_core_fold,orig_bin_var_used_in_guard},
+ {5,beam_bsm,{no_bin_opt,{{t1,1},no_suitable_bs_start_match}}},
+ {9,beam_bsm,{no_bin_opt,
+ {binary_used_in,{extfunc,erlang,split_binary,2}}}} ]}}],
+ ?line [] = run(Config, Ts1),
+
+ %% For coverage: don't give the bin_opt_info option.
+ Ts2 = [{bsm2,
+ Code,
+ [],
+ []}],
+ ?line [] = run(Config, Ts2),
+ ok.
+
+bin_construction(Config) when is_list(Config) ->
+ Ts = [{bin_construction,
+ <<"
+ t() ->
+ Bin = <<1,2,3>>,
+ <<Bin:4/binary>>.
+
+ x() ->
+ Bin = <<1,2,3,7:4>>,
+ <<Bin/binary>>.
+ ">>,
+ [],
+ {warnings,[{4,sys_core_fold,embedded_binary_size},
+ {8,sys_core_fold,{embedded_unit,8,28}}]}}],
+ ?line [] = run(Config, Ts),
+
+ ok.
+
+%%%
+%%% End of test cases.
+%%%
+
+run(Config, Tests) ->
+ F = fun({N,P,Ws,E}, BadL) ->
+ case catch run_test(Config, P, Ws) of
+ E ->
+ BadL;
+ Bad ->
+ ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ "but got~n ~p~n", [N, E, Bad]),
+ fail()
+ end
+ end,
+ lists:foldl(F, [], Tests).
+
+
+%% Compiles a test module and returns the list of errors and warnings.
+
+run_test(Conf, Test0, Warnings) ->
+ Filename = 'warnings_test.erl',
+ ?line DataDir = ?privdir,
+ ?line Test = ["-module(warnings_test). ", Test0],
+ ?line File = filename:join(DataDir, Filename),
+ ?line Opts = [binary,export_all,return|Warnings],
+ ?line ok = file:write_file(File, Test),
+
+ %% Compile once just to print all warnings.
+ ?line compile:file(File, [binary,export_all,report|Warnings]),
+
+ %% Test result of compilation.
+ ?line Res = case compile:file(File, Opts) of
+ {ok, _M, Bin, []} when is_binary(Bin) ->
+ [];
+ {ok, _M, Bin, Ws0} when is_binary(Bin) ->
+ %% We are not interested in warnings from
+ %% erl_lint here.
+ WsL = [{F,[W || {_,Mod,_}=W <- Ws,
+ Mod =/= erl_lint]} ||
+ {F,Ws} <- Ws0],
+ case WsL of
+ [{_File,Ws}] -> {warnings, Ws};
+ _ -> list_to_tuple([warnings, WsL])
+ end
+ end,
+ file:delete(File),
+ Res.
+
+fail() ->
+ io:format("failed~n"),
+ ?t:fail().