aboutsummaryrefslogblamecommitdiffstats
path: root/lib/compiler/test/warnings_SUITE.erl
blob: 70b710045135c87ab6eda895feca4a37204cad64 (plain) (tree)
1
2
3
4
5
6
7
8
9

                   
  
                                                        
  


                                                                   
  






                                                                           
  











                                        
                                           

                                                      

       


                                                                    


                                                      
                                                            

                                                     
                                                      
                                                 
 
                                   
           
 
                                   

       


                                 
 
         
                

            


                                                   
                                                         
                         
                                                 

                                                  
 
                         
                                




                         
                                     
           

                                    
           
 




















                                          
                         



















                                                              
                                                        

                                                                
                         







                                                                  
                          














                                                               
                         





















































                                                            

                                               



                                                
                         



























                                                      
                                                    
                 
                         






























                                                        
                         






























                                                          
                         

















                                         
                         

                                                                       
                      
                                       






















                                                                        
                         



                                                                       
                  

























                                                                             



                                        






                                                                   





                                                             



















































                                                                           









                                                     












                                                              


















                                                                           


                                                                               
                         










                                                                      








                                                                         
                                 
                                    
               




















                                                                             

                                                        

                                            















                                                                 
                         


       









                                              















                                                        




                                                               
                                                             


                    
                                                                 








                                                            
                






                                                              
                                            
                               











                                                 









































































































                                                                            


                    








                                                      
                                                          


                         














                                                           




























                                                                 













                                                                 

       






































                                                                     














                                                                     





                                                                       







                                              





                    










































                                                                            























                                                        
 













                                                         









                                                     
                                                                      





                                                                  


                                                                      

                                          
                       
                                              


                                               

                                               
                                                            

                                  













                                                           



                      
                    
%%
%% %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;
                 <<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},
             {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 ->
              	    <<X:8>>;
              	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(<<A,B,T/bytes>>) ->
                 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>>,
                 <<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}}]}}],
    [] = 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 = <<A>>,
              _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<digit>" 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(<<a/binary>>) -> ok;
              a(<<a/integer>>) -> ok;
              a(<<a/float>>) -> ok;
              a(<<a/utf8>>) -> ok;
              a(<<a/utf16>>) -> ok;
              a(<<a/utf32>>) -> ok;
              a(<<a/utf32>>) -> 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).