%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2003-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions 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_lib("common_test/include/ct.hrl"). -define(datadir, proplists:get_value(data_dir, Conf)). -define(privdir, proplists:get_value(priv_dir, Conf)). -endif. -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_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, comprehensions/1,maps/1,maps_bin_opt_info/1, redundant_boolean_clauses/1, latin1_fallback/1,underscore/1,no_warnings/1, bit_syntax/1,inlining/1,tuple_calls/1]). init_per_testcase(_Case, Config) -> Config. end_per_testcase(_Case, _Config) -> ok. suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> [{group,p}]. groups() -> [{p,test_lib:parallel(), [pattern,pattern2,pattern3,pattern4,guard, bad_arith,bool_cases,bad_apply,files,effect, bin_opt_info,bin_construction,comprehensions,maps, maps_bin_opt_info, redundant_boolean_clauses,latin1_fallback, underscore,no_warnings,bit_syntax,inlining, tuple_calls]}]. init_per_suite(Config) -> test_lib:recompile(?MODULE), Config. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. 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} ] }}], [] = 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}}, {4,sys_core_fold,no_clause_match}, {5,sys_core_fold,nomatch_clause_type}, {6,sys_core_fold,nomatch_clause_type}]}}], [] = 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}}]}}], [] = 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}}]}}], [] = 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; <> -> no; 17 -> no; [] -> no; a -> no; {a,b,c} -> no end. tuple() -> case {x,y,z} of \"xyz\" -> no; [a|b] -> no; <<1>> -> no; <> -> 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}, {11,sys_core_fold,nomatch_shadow}, {15,sys_core_fold,nomatch_shadow}, {18,sys_core_fold,no_clause_match}, {23,sys_core_fold,no_clause_match}, {33,sys_core_fold,no_clause_match} ]}}], [] = 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}} ]}}], [] = 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}} ] }}], [] = 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} ]} }], [] = 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}]}}], [] = run(Config, Ts), %% Also verify that the generated code generates the correct error. try erlang:42() of _ -> ct:fail(should_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}}]}]}}], [] = run(Config, Ts), ok. %% Test warnings for term construction and BIF calls in effect context. effect(Config) when is_list(Config) -> Ts = [{effect, <<" 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 -> <>; unused_fun -> fun() -> {ok,X} end; unused_named_fun -> fun F(0) -> 1; F(N) -> N*F(N-1) end; unused_atom -> ignore; %no warning unused_nil -> []; %no warning comp_op -> X =:= 2; cookie -> erlang:get_cookie(); result_ignore -> _ = list_to_integer(X); warn_lc_4 -> %% No warning because of assignment to _. [_ = abs(Z) || Z <- [1,2,3]] 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. m8(A, B) -> case {A,B} of V -> V end, ok. m9(Bs) -> [{B,ok} = {B,foo:bar(B)} || B <- Bs], ok. m10(ConfigTableSize) -> case ConfigTableSize of apa -> CurrentConfig = {id(camel_phase3),id(sms)}, case CurrentConfig of {apa, bepa} -> ok; _ -> ok end end, ok. id(I) -> I. ">>, [], {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}, {28,sys_core_fold,useless_building}, {36,sys_core_fold,{no_effect,{erlang,'=:=',2}}}, {38,sys_core_fold,{no_effect,{erlang,get_cookie,0}}}]}}], [] = 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. %% We use a tail in a BIF instruction, remote call, function %% return, and an optimizable tail call for better coverage. t2(<>) -> if A > B -> t2(T); A =< B -> T end; t2(<<_,T/bytes>>) when byte_size(T) < 4 -> foo; t2(<<_,T/bytes>>) -> split_binary(T, 4). ">>, Ws = (catch run_test(Config, Code, [bin_opt_info])), %% This is an inexact match since the pass reports exact instructions as %% part of the warnings, which may include annotations that vary from run %% to run. {warnings, [{5,beam_ssa_bsm,{unsuitable_call, {{b_local,{b_literal,t1},1}, {used_before_match, {b_set,_,_,{bif,byte_size},[_]}}}}}, {5,beam_ssa_bsm,{binary_created,_,_}}, {11,beam_ssa_bsm,{binary_created,_,_}}, %% A =< B -> T {13,beam_ssa_bsm,context_reused}, %% A > B -> t2(T); {16,beam_ssa_bsm,{binary_created,_,_}}, %% when byte_size(T) < 4 -> {19,beam_ssa_bsm,{remote_call, {b_remote, {b_literal,erlang}, {b_literal,split_binary},2}}}, {19,beam_ssa_bsm,{binary_created,_,_}} %% split_binary(T, 4) ]} = Ws, %% For coverage: don't give the bin_opt_info option. [] = (catch run_test(Config, Code, [])), ok. bin_construction(Config) when is_list(Config) -> Ts = [{bin_construction, <<" t() -> Bin = <<1,2,3>>, <>. x() -> Bin = <<1,2,3,7:4>>, <>. ">>, [], {warnings,[{4,sys_core_fold,embedded_binary_size}, {8,sys_core_fold,{embedded_unit,8,28}}]}}], [] = run(Config, Ts), ok. comprehensions(Config) when is_list(Config) -> Ts = [{tautologic_guards, <<" f() -> [ true || true ]. g() -> << <<1>> || true >>. ">>, [], []}], run(Config, Ts), ok. maps(Config) when is_list(Config) -> Ts = [{bad_map, <<" t() -> case maybe_map of #{} -> ok; not_map -> error end. x() -> case true of #{} -> error; true -> ok end. ">>, [], {warnings,[{3,sys_core_fold,no_clause_match}, {9,sys_core_fold,nomatch_clause_type}]}}, {bad_map_src1, <<" t() -> M = {a,[]}, {'EXIT',{badarg,_}} = (catch(M#{ a => 1 })), ok. ">>, [], {warnings,[{4,sys_core_fold,{eval_failure,badmap}}]}}, {bad_map_src2, <<" t() -> M = id({a,[]}), {'EXIT',{badarg,_}} = (catch(M#{ a => 1})), ok. id(I) -> I. ">>, [inline], []}, {bad_map_src3, <<" t() -> {'EXIT',{badarg,_}} = (catch <<>>#{ a := 1}), ok. ">>, [], {warnings,[{3,v3_core,badmap}]}}, {ok_map_literal_key, <<" t() -> V = id(1), M = id(#{ <<$h,$i>> => V }), V = case M of #{ <<0:257>> := Val } -> Val; #{ <<$h,$i>> := Val } -> Val end, ok. id(I) -> I. ">>, [], []}, {repeated_keys1, <<" foo1() -> #{a=>1, b=> 2, a=>3}. bar1(M) -> M#{a=>1, b=> 2, a:=3}. baz1(M) -> M#{a=>1, b=> 2, a:=3}. foo2() -> #{\"a\"=>1, \"b\"=> 2, \"a\"=>3}. bar2(M) -> M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}. baz2(M) -> M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}. foo3() -> #{\"a\"=>1, \"b\"=> 2, \"a\"=>3}. bar3(M) -> M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}. baz3(M) -> M#{<<\"a\">>=>1, <<\"b\">>=> 2, <<\"a\">>:=3}. ">>, [], {warnings,[{3,v3_core,{map_key_repeated,a}}, {8,v3_core,{map_key_repeated,a}}, {11,v3_core,{map_key_repeated,a}}, {14,v3_core,{map_key_repeated,"a"}}, {17,v3_core,{map_key_repeated,"a"}}, {20,v3_core,{map_key_repeated,"a"}}, {23,v3_core,{map_key_repeated,"a"}}, {28,v3_core,{map_key_repeated,"a"}}, {31,v3_core,{map_key_repeated,<<"a">>}}]}}, {repeated_keys2, <<" foo4(K) -> #{\"a\"=>1, K => 1, \"b\"=> 2, \"a\"=>3, K=>2}. bar4(M,K) -> M#{a=>1, K =>1, b=> 2, a:=3, K=>2}. baz4(M,K) -> M#{<<\"a\">>=>1, K => 1, <<\"b\">>=> 2, <<\"a\">>:=3, K=>2}. foo5(K) -> #{{\"a\",1}=>1, K => 1, \"b\"=> 2, {\"a\",1}=>3, K=>2}. bar5(M,K) -> M#{{\"a\",<<\"b\">>}=>1, K =>1, \"b\"=> 2, {\"a\",<<\"b\">>}:=3, K=>2}. baz5(M,K) -> M#{{<<\"a\">>,1}=>1, K => 1, <<\"b\">>=> 2, {<<\"a\">>,1}:=3,K=>2}. foo6(K) -> #{#{\"a\"=>1}=>1, K => 1, \"b\"=> 2, #{\"a\"=>1}=>3, K=>2}. bar6(M,K) -> M#{#{\"a\"=><<\"b\">>}=>1, K =>1, \"b\"=> 2, #{\"a\"=><<\"b\">>}:=3, K=>2}. baz6(M,K) -> M#{#{<<\"a\">>=>1}=>1, K => 1, <<\"b\">>=> 2, #{<<\"a\">>=>1}:=3,K=>2}. foo7(K) -> M1 = #{#{\"a\"=>1}=>1, K => 1, \"b\"=> 2}, M1#{#{\"a\"=>1}=>3, K=>2}. bar7(M,K) -> M1 = M#{#{\"a\"=><<\"b\">>}=>1, K =>1, \"b\"=> 2}, M1#{#{\"a\"=><<\"b\">>}:=3, K=>2}. baz7(M,K) -> M1 = M#{#{<<\"a\">>=>1}=>1, K => 1, <<\"b\">>=> 2}, M1#{#{<<\"a\">>=>1}:=3,K=>2}. ">>, [], {warnings,[{3,v3_core,{map_key_repeated,"a"}}, {6,v3_core,{map_key_repeated,a}}, {9,v3_core,{map_key_repeated,<<"a">>}}, {14,v3_core,{map_key_repeated,{"a",1}}}, {17,v3_core,{map_key_repeated,{"a",<<"b">>}}}, {21,v3_core,{map_key_repeated,{<<"a">>,1}}}, {25,v3_core,{map_key_repeated,#{"a" => 1}}}, {28,v3_core,{map_key_repeated,#{"a" => <<"b">>}}}, {32,v3_core,{map_key_repeated,#{<<"a">> => 1}}}]}} ], run(Config, Ts), ok. maps_bin_opt_info(Config) when is_list(Config) -> Ts = [{map_bsm, <<" t1(<<0:8,7:8,T/binary>>,#{val := I}=M) -> t1(T, M#{val := I+1}); t1(<<_:8>>,M) -> M. ">>, [bin_opt_info], {warnings,[{3,beam_ssa_bsm,context_reused}]}}], [] = run(Config, Ts), ok. redundant_boolean_clauses(Config) when is_list(Config) -> Ts = [{redundant_boolean_clauses, <<" t(X) -> case X == 0 of false -> no; false -> no; true -> yes end. ">>, [], {warnings,[{5,sys_core_fold,nomatch_shadow}]}}], run(Config, Ts), ok. latin1_fallback(Conf) when is_list(Conf) -> DataDir = ?privdir, IncFile = filename:join(DataDir, "include_me.hrl"), file:write_file(IncFile, <<"%% ",246," in include file\n">>), Ts1 = [{latin1_fallback1, %% Test that the compiler fall backs to latin-1 with %% a warning if a file has no encoding and does not %% contain correct UTF-8 sequences. <<"%% Bj",246,"rn t(_) -> \"",246,"\"; t(x) -> ok. ">>, [], {warnings,[{1,compile,reparsing_invalid_unicode}, {3,sys_core_fold,{nomatch_shadow,2}}]}}], [] = run(Conf, Ts1), Ts2 = [{latin1_fallback2, %% Test that the compiler fall backs to latin-1 with %% a warning if a file has no encoding and does not %% contain correct UTF-8 sequences. <<" -include(\"include_me.hrl\"). ">>, [], {warnings,[{1,compile,reparsing_invalid_unicode}]} }], [] = run(Conf, Ts2), Ts3 = [{latin1_fallback3, %% Test that the compiler fall backs to latin-1 with %% a warning if a file has no encoding and does not %% contain correct UTF-8 sequences. <<"-ifdef(NOTDEFINED). t(_) -> \"",246,"\"; t(x) -> ok. -endif. ">>, [], {warnings,[{2,compile,reparsing_invalid_unicode}]}}], [] = run(Conf, Ts3), ok. underscore(Config) when is_list(Config) -> S0 = <<"f(A) -> _VAR1 = <>, _VAR2 = {ok,A}, _VAR3 = [A], ok. g(A) -> _VAR1 = A/0, _VAR2 = date(), ok. h() -> _VAR1 = fun() -> ok end, ok. i(A) -> _VAR1 = #{A=>42}, ok. ">>, Ts0 = [{underscore0, S0, [], {warnings,[{2,sys_core_fold,useless_building}, {3,sys_core_fold,useless_building}, {4,sys_core_fold,useless_building}, {7,sys_core_fold,result_ignored}, {8,sys_core_fold,{no_effect,{erlang,date,0}}}, {11,sys_core_fold,useless_building}, {14,sys_core_fold,useless_building} ]}}], [] = run(Config, Ts0), %% Replace all "_VAR" variables with a plain underscore. %% Now there should be no warnings. S1 = re:replace(S0, "_VAR\\d+", "_", [global]), io:format("~s\n", [S1]), Ts1 = [{underscore1,S1,[],[]}], [] = run(Config, Ts1), ok. no_warnings(Config) when is_list(Config) -> Ts = [{no_warnings, <<"-record(r, {s=ordsets:new(),a,b}). a() -> R = #r{}, %No warning expected. {R#r.a,R#r.b}. b(X) -> T = true, Var = [X], %No warning expected. case T of false -> Var; true -> [] end. c() -> R0 = {r,\"abc\",undefined,os:timestamp()}, %No warning. case R0 of {r,V1,_V2,V3} -> {r,V1,\"def\",V3} end. d(In0, Bool) -> {In1,Int} = case id(Bool) of false -> {In0,0} end, [In1,Int]. id(I) -> I. ">>, [], []}], run(Config, Ts), ok. bit_syntax(Config) -> Ts = [{?FUNCTION_NAME, <<"a(<<-1>>) -> ok; a(<<1023>>) -> ok; a(<<777/signed>>) -> ok; a(<>) -> ok; a(<>) -> ok; a(<>) -> ok; a(<>) -> ok; a(<>) -> ok; a(<>) -> ok; a(<>) -> ok. b(Bin) -> Sz = bad, <<42:Sz>> = Bin. c(Sz, Bin) -> case Bin of <<-42:Sz/unsigned>> -> ok; <<42:Sz/float>> -> ok; <<42:Sz/binary>> -> ok end. ">>, [], {warnings,[{1,sys_core_fold,no_clause_match}, {1,sys_core_fold,{nomatch_bit_syntax_unsigned,-1}}, {2,sys_core_fold,{nomatch_bit_syntax_truncated, unsigned,1023,8}}, {3,sys_core_fold,{nomatch_bit_syntax_truncated, signed,777,8}}, {4,sys_core_fold,{nomatch_bit_syntax_type,a,binary}}, {5,sys_core_fold,{nomatch_bit_syntax_type,a,integer}}, {6,sys_core_fold,{nomatch_bit_syntax_type,a,float}}, {7,sys_core_fold,{nomatch_bit_syntax_type,a,utf8}}, {8,sys_core_fold,{nomatch_bit_syntax_type,a,utf16}}, {9,sys_core_fold,{nomatch_bit_syntax_type,a,utf32}}, {10,sys_core_fold,{nomatch_bit_syntax_type,a,utf32}}, {11,sys_core_fold,no_clause_match}, {11,sys_core_fold,{nomatch_bit_syntax_size,bad}}, {14,sys_core_fold,{nomatch_bit_syntax_unsigned,-42}}, {16,sys_core_fold,{nomatch_bit_syntax_type,42,binary}} ]} }], run(Config, Ts), ok. inlining(Config) -> %% Make sure that no spurious warnings are generated %% when inlining. Ts = [{inlining_1, <<"-compile(inline). compute1(X) -> add(X, 0). add(1, 0) -> 1; add(1, Y) -> 1 + Y; add(X, Y) -> X + Y. ">>, [], []}, {inlining_2, <<"-compile({inline,[add/2]}). compute1(X) -> add(X, 0). add(1, 0) -> 1; add(1, Y) -> 1 + Y; add(X, Y) -> X + Y. ">>, [], []} ], run(Config, Ts), ok. tuple_calls(Config) -> %% Make sure that no spurious warnings are generated. Ts = [{inlining_1, <<"-compile(tuple_calls). dispatch(X) -> (list_to_atom(\"prefix_\" ++ atom_to_list(suffix))):doit(X). ">>, [], []} ], 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 -> io: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) -> Module = "warnings_"++test_lib:uniq(), Filename = Module ++ ".erl", DataDir = ?privdir, Test = ["-module(", Module, "). ", Test0], File = filename:join(DataDir, Filename), Opts = [binary,export_all,return|Warnings], ok = file:write_file(File, Test), %% Compile once just to print all warnings. compile:file(File, [binary,export_all,report|Warnings]), %% Test result of compilation. 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() -> ct:fail(failed).