1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(warnings_SUITE).
21
22%%-define(STANDALONE, true).
23
24-ifdef(STANDALONE).
25-define(line, put(line, ?LINE), ).
26-define(config(X,Y), foo).
27-define(privdir, "warnings_SUITE_priv").
28-define(t, test_server).
29-else.
30-include_lib("common_test/include/ct.hrl").
31-define(datadir, proplists:get_value(data_dir, Conf)).
32-define(privdir, proplists:get_value(priv_dir, Conf)).
33-endif.
34
35-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
36	 init_per_group/2,end_per_group/2,
37	 init_per_testcase/2,end_per_testcase/2]).
38
39-export([pattern/1,pattern2/1,pattern3/1,pattern4/1,
40	 guard/1,bad_arith/1,bool_cases/1,bad_apply/1,
41         files/1,effect/1,bin_opt_info/1,bin_construction/1,
42	 comprehensions/1,maps/1,maps_bin_opt_info/1,
43         redundant_boolean_clauses/1,
44	 underscore/1,no_warnings/1,
45	 bit_syntax/1,inlining/1,tuple_calls/1,
46         recv_opt_info/1,opportunistic_warnings/1]).
47
48init_per_testcase(_Case, Config) ->
49    Config.
50
51end_per_testcase(_Case, _Config) ->
52    ok.
53
54suite() ->
55    [{ct_hooks,[ts_install_cth]},
56     {timetrap,{minutes,2}}].
57
58all() ->
59    [{group,p}].
60
61groups() ->
62    [{p,test_lib:parallel(),
63      [pattern,pattern2,pattern3,pattern4,guard,
64       bad_arith,bool_cases,bad_apply,files,effect,
65       bin_opt_info,bin_construction,comprehensions,maps,
66       maps_bin_opt_info,
67       redundant_boolean_clauses,
68       underscore,no_warnings,bit_syntax,inlining,
69       tuple_calls,recv_opt_info,opportunistic_warnings]}].
70
71init_per_suite(Config) ->
72    test_lib:recompile(?MODULE),
73    Config.
74
75end_per_suite(_Config) ->
76    ok.
77
78init_per_group(_GroupName, Config) ->
79    Config.
80
81end_per_group(_GroupName, Config) ->
82    Config.
83
84
85pattern(Config) when is_list(Config) ->
86    %% Test warnings generated by v3_core.
87    Ts = [{pattern,
88           <<"%% Just a comment here.
89              f(a={glurf,2}=A) -> A.
90
91              g(A) ->
92                 case A of
93                   a=[_|_] -> error;
94                   Other -> true
95                 end.
96
97              foo(X) ->
98                 a = {nisse,b} = X.
99           ">>,
100           [warn_unused_vars],
101           {warnings,
102            [{{2,15},v3_core,{nomatch,pattern}},
103             {{6,20},v3_core,{nomatch,pattern}},
104             {{11,18},v3_core,{nomatch,pattern}}
105            ]}}],
106    [] = run(Config, Ts),
107    ok.
108
109pattern2(Config) when is_list(Config) ->
110    %% Test warnings generated by sys_core_fold.
111    %% If we disable Core Erlang optimizations, we expect that
112    %% v3_kernel should generate some of the warnings.
113    Source = <<"f(A) -> ok;
114                f(B) -> error.
115                t(A, B, C) ->
116                  case {A,B,C} of
117                    {a,B} -> ok;
118                    {_,B} -> ok
119                  end.
120                c(E) ->
121                  case E of
122                    _ -> ok;
123                    _ -> ok
124                  end.
125           ">>,
126
127    %% Test warnings from sys_core_fold.
128    Ts = [{pattern2,
129	   Source,
130	   [nowarn_unused_vars],
131           {warnings,[{{2,17},sys_core_fold,{nomatch,{shadow,1,{f,1}}}},
132                      {{4,19},sys_core_fold,{nomatch,no_clause}},
133                      {{5,21},sys_core_fold,{nomatch,clause_type}},
134                      {{6,21},sys_core_fold,{nomatch,clause_type}},
135                      {{11,21},sys_core_fold,{nomatch,{shadow,10}}}
136                     ]}}],
137    [] = run(Config, Ts),
138
139    %% Disable Core Erlang optimizations. v3_kernel should produce
140    %% a warning for the clause that didn't match.
141    Ts2 = [{pattern2,
142	    Source,
143	    [nowarn_unused_vars,no_copt],
144	    {warnings,
145	     [{{2,17},v3_kernel,{nomatch,{shadow,1}}},
146              {{11,21},v3_kernel,{nomatch,{shadow,10}}}
147             ]}}],
148    [] = run(Config, Ts2),
149    ok.
150
151pattern3(Config) when is_list(Config) ->
152    %% Test warnings generated by the pattern matching compiler
153    %% in v3_kernel.
154
155    Ts = [{pattern3,
156	   <<"
157            f({A,_}) -> {ok,A};
158            f([_|_]=B) -> {ok,B};
159            f({urk,nisse}) -> urka_glurka.
160           ">>,
161	   [nowarn_unused_vars],
162	   {warnings,
163            [{{4,13},v3_kernel,{nomatch,{shadow,2}}}]}}],
164    [] = run(Config, Ts),
165
166    ok.
167
168pattern4(Config) when is_list(Config) ->
169    %% Test warnings for clauses that cannot possibly match.
170
171    Ts = [{pattern4,
172	   <<"
173             t() ->
174               case true of
175                 false -> a;
176                 true -> b
177               end.
178
179             fi() ->
180               case true of
181                 false -> a;
182                 false -> b
183               end,
184               case true of
185                 true -> a;
186                 true -> b;
187                 X -> X
188               end,
189               case boolean of
190                 true -> a;
191                 false -> b
192               end.
193             int() ->
194               case 42 of
195                 [a|b] -> no;
196                 <<1>> -> no;
197                 <<X>> -> no;
198                 17 -> no;
199                 [] -> no;
200                 a -> no;
201                 {a,b,c} -> no
202               end.
203             tuple() ->
204               case {x,y,z} of
205                 \"xyz\" -> no;
206                 [a|b] -> no;
207                 <<1>> -> no;
208                 <<X>> -> no;
209                 17 -> no;
210                 [] -> no;
211                 a -> no;
212                 {a,b,c} -> no;
213                 {x,y} -> no
214               end.
215           ">>,
216	   [nowarn_unused_vars],
217	   {warnings,
218            [{{9,16},sys_core_fold,{nomatch,no_clause}},
219             {{11,18},sys_core_fold,{nomatch,shadow}},
220             {{15,18},sys_core_fold,{nomatch,shadow}},
221             {{18,16},sys_core_fold,{nomatch,no_clause}},
222             {{23,16},sys_core_fold,{nomatch,no_clause}},
223             {{33,16},sys_core_fold,{nomatch,no_clause}}
224	    ]}}],
225    [] = run(Config, Ts),
226
227    ok.
228
229guard(Config) when is_list(Config) ->
230    %% Test warnings for false guards.
231
232    Ts = [{guard,
233	   <<"
234              t(A, B) when element(x, dum) -> ok.
235
236              tt(A, B) when 1 == 2 -> ok.
237
238              ttt() when element(x, dum) -> ok.
239
240              t4(T, F) when element({F}, T) -> ok.
241              t5(T, F) when element([F], T) -> ok.
242              t6(Pos, F) when element(Pos, [F]) -> ok.
243              t7(Pos) when element(Pos, []) -> ok.
244           ">>,
245	   [nowarn_unused_vars],
246	   {warnings,
247            [{{2,15},sys_core_fold,{nomatch,guard}},
248             {{2,15},sys_core_fold,{nomatch,no_clause}},
249             {{2,28},sys_core_fold,
250              {failed,{eval_failure,
251                       {erlang,element,2},
252                       badarg}}},
253             {{4,15},sys_core_fold,{nomatch,guard}},
254             {{4,15},sys_core_fold,{nomatch,no_clause}},
255             {{6,15},sys_core_fold,{nomatch,guard}},
256             {{6,15},sys_core_fold,{nomatch,no_clause}},
257             {{6,26},sys_core_fold,
258              {failed,
259               {eval_failure,
260                {erlang,element,2},
261                badarg}}}
262	    ]}}],
263    [] = run(Config, Ts),
264
265    ok.
266
267bad_arith(Config) when is_list(Config) ->
268    Ts = [{bad_arith,
269           <<"f() ->
270                if
271                  a + 3 > 3 -> ok;
272                 true -> error
273              end.
274
275              g(A) ->
276                if
277                  is_integer(A), a + 3 > 3 -> ok;
278                  a + 3 > 42, is_integer(A) -> ok;
279                 true -> error
280              end.
281
282              h(A) ->
283                a + 3 + A.
284           ">>,
285	   [],
286	   {warnings,
287            [{{3,19},sys_core_fold,{nomatch,guard}},
288             {{3,21},sys_core_fold,
289              {failed,{eval_failure,
290                       {erlang,'+',2},
291                       badarith}}},
292             {{9,19},sys_core_fold,
293              {ignored,{no_effect,{erlang,is_integer,1}}}},
294             {{9,19},sys_core_fold,{nomatch,guard}},
295             {{9,36},sys_core_fold,
296              {failed,{eval_failure,
297                       {erlang,'+',2},
298                       badarith}}},
299             {{10,19},sys_core_fold,{nomatch,guard}},
300             {{10,21},sys_core_fold,
301              {failed,{eval_failure,
302                       {erlang,'+',2},
303                       badarith}}},
304             {{15,19},sys_core_fold,
305              {failed,{eval_failure,
306                       {erlang,'+',2},
307                       badarith}}}
308	    ] }}],
309    [] = run(Config, Ts),
310    ok.
311
312bool_cases(Config) when is_list(Config) ->
313    Ts = [{bool_cases,
314	   <<"
315            f(A, B) ->
316               case A > B of
317                 true -> true;
318                 false -> false;
319                 Other -> {error,not_bool}
320               end.
321
322            g(A, B) ->
323               case A =/= B of
324                 false -> false;
325                 true -> true;
326                 Other -> {error,not_bool}
327               end.
328
329            h(Bool) ->
330               case not Bool of
331                 maybe -> strange;
332                 false -> ok;
333                 true -> error
334               end.
335           ">>,
336           [nowarn_unused_vars],
337           {warnings,
338            [{{6,18},sys_core_fold,{nomatch,shadow}},
339             {{13,18},sys_core_fold,{nomatch,shadow}},
340             {{18,18},sys_core_fold,{nomatch,clause_type}} ]} }],
341    [] = run(Config, Ts),
342    ok.
343
344bad_apply(Config) when is_list(Config) ->
345    Ts = [{bad_apply,
346	   <<"
347             t(1) -> 42:42();
348             t(2) -> erlang:42();
349             t(3) -> 42:start();
350             t(4) -> []:start();
351             t(5) -> erlang:[]();
352             t(6) -> [a,b,c]().
353           ">>,
354           [],
355           {warnings,
356            [{{2,22},v3_kernel,{failed,bad_call}},
357             {{3,22},v3_kernel,{failed,bad_call}},
358             {{4,22},v3_kernel,{failed,bad_call}},
359             {{5,22},v3_kernel,{failed,bad_call}},
360             {{6,22},v3_kernel,{failed,bad_call}},
361             {{7,22},sys_core_fold,{failed,bad_call}}
362            ]}}],
363    [] = run(Config, Ts),
364
365    %% Also verify that the generated code generates the correct error.
366    try erlang:42() of
367	      _ -> ct:fail(should_fail)
368	  catch
369	      error:badarg -> ok
370	  end,
371    ok.
372
373files(Config) when is_list(Config) ->
374    Ts = [{files_1,
375	   <<"
376              -file(\"file1\", 14).
377
378              t1() ->
379                  1/0.
380
381              -file(\"file2\", 7).
382
383              t2() ->
384                  1/0.
385           ">>,
386           [],
387           {warnings,
388            [{"file1",[{{17,20},sys_core_fold,
389                        {failed,{eval_failure,
390                                 {erlang,'/',2},
391                                 badarith}}}]},
392             {"file2",[{{10,20},sys_core_fold,
393                        {failed,{eval_failure,
394                                 {erlang,'/',2},
395                                 badarith}}}]}]}}],
396
397    [] = run(Config, Ts),
398    ok.
399
400%% Test warnings for term construction and BIF calls in effect context.
401effect(Config) when is_list(Config) ->
402    Ts = [{no_warnings,
403           %% No warnings should be generated in the following functions.
404           <<"
405             m1(X, Sz) ->
406                if
407                  Sz =:= 0 -> X = 0;
408                  true -> ok
409                end,
410                ok.
411
412             m2(X, Sz) ->
413                if
414                  Sz =:= 0 -> X = {a,Sz};
415                  true -> ok
416                end,
417                ok.
418
419             m3(X, Sz) ->
420                if
421                  Sz =:= 0 -> X = [a,Sz];
422                  true -> ok
423                end,
424                ok.
425
426             m4(X, Sz, Var) ->
427                if
428                  Sz =:= 0 -> X = Var;
429                  true -> ok
430                end,
431                ok.
432
433             m5(X, Sz) ->
434                if
435                   Sz =:= 0 -> X = {a,b,c};
436                   true -> ok
437                end,
438                ok.
439
440             m6(X, Sz) ->
441                if
442                  Sz =:= 0 -> X = {a,Sz,[1,2,3]};
443                  true -> ok
444                end,
445                ok.
446
447             m7(X, Sz) ->
448                if
449                  Sz =:= 0 -> X = {a,Sz,[1,2,3],abs(Sz)};
450                  true -> ok
451                end,
452                ok.
453
454             m8(A, B) ->
455                case {A,B} of
456                  V -> V
457                end,
458                ok.
459
460             m9(Bs) ->
461                [{B,ok} = {B,foo:bar(B)} || B <- Bs],
462                ok.
463
464             m10(ConfigTableSize) ->
465               case ConfigTableSize of
466                 apa ->
467                   CurrentConfig = {id(camel_phase3),id(sms)},
468                   case CurrentConfig of
469                     {apa, bepa} -> ok;
470                     _ -> ok
471                   end
472               end,
473               ok.
474
475             id(I) -> I.
476             ">>,
477           [],[]},
478
479          {basic,
480           <<"
481             t(X) ->
482               case X of
483                warn_lc ->
484                    [is_integer(Z) || Z <- [1,2,3]];
485                warn_lc_2 ->
486                    [{error,Z} || Z <- [1,2,3]];
487                warn_lc_3 ->
488                    [{error,abs(Z)} || Z <- [1,2,3]];
489                no_warn_lc ->
490                    [put(last_integer, Z) || Z <- [1,2,3]]; %no warning
491                unused_tuple_literal ->
492                    {a,b,c};
493                unused_list_literal ->
494                    [1,2,3,4];
495                unused_integer ->
496                    42;
497                unused_arith ->
498                    X*X
499               end,
500               ok.
501             ">>,
502           [],
503           {warnings,[{{5,22},sys_core_fold,{ignored,{no_effect,{erlang,is_integer,1}}}},
504                      {{7,22},sys_core_fold,{ignored,useless_building}},
505                      {{9,22},sys_core_fold,{ignored,useless_building}},
506                      {{9,29},sys_core_fold,{ignored,{result,{erlang,abs,1}}}},
507                      {{13,21},sys_core_fold,{ignored,useless_building}},
508                      {{15,21},sys_core_fold,{ignored,useless_building}},
509                      {{17,21},sys_core_fold,{ignored,useless_building}},
510                      {{19,22},sys_core_fold,{ignored,{result, {erlang,'*',2}}}}
511                     ]}},
512
513          {nested,
514            <<"
515             t(X) ->
516               case X of
517                nested ->
518                    [{ok,node(),module:foo(),self(),[time(),date()],time()},
519                     is_integer(X)];
520                unused_bit_syntax ->
521                    <<X:8>>;
522                unused_fun ->
523                    fun() -> {ok,X} end;
524                unused_named_fun ->
525                    fun F(0) -> 1;
526                        F(N) -> N*F(N-1)
527                    end;
528                unused_atom ->
529                    ignore;                             %no warning
530                unused_nil ->
531                    [];                                 %no warning
532                comp_op ->
533                    X =:= 2;
534                cookie ->
535                    erlang:get_cookie();
536                result_ignore ->
537                    _ = list_to_integer(X);
538                warn_lc_4 ->
539                    %% No warning because of assignment to _.
540                    [_ = abs(Z) || Z <- [1,2,3]]
541               end,
542               ok.
543             ">>,
544           [],
545           {warnings,[{{5,21},sys_core_fold,{ignored,useless_building}},
546                      {{5,26},sys_core_fold,{ignored,{no_effect,{erlang,node,0}}}},
547                      {{5,46},sys_core_fold,{ignored,{no_effect,{erlang,self,0}}}},
548                      {{5,54},sys_core_fold,{ignored,{no_effect,{erlang,time,0}}}},
549                      {{5,61},sys_core_fold,{ignored,{no_effect,{erlang,date,0}}}},
550                      {{5,69},sys_core_fold,{ignored,{no_effect,{erlang,time,0}}}},
551                      {{6,22},sys_core_fold,{ignored,{no_effect,{erlang,is_integer,1}}}},
552                      {{8,21},sys_core_fold,{ignored,useless_building}},
553                      {{10,21},sys_core_fold,{ignored,useless_building}},
554                      {{12,21},sys_core_fold,{ignored,useless_building}},
555                      {{20,23},sys_core_fold,{ignored,{no_effect,{erlang,'=:=',2}}}},
556                      {{22,21},sys_core_fold,{ignored,{no_effect,{erlang,get_cookie,0}}}}
557                      ]}},
558
559          {seq,
560           <<"
561             t(T) ->
562               [ {a,b,T} ],  [ {x,y,T} ],
563               ok.
564             ">>,
565           [],
566           {warnings,[{{3,16},sys_core_fold,{ignored,useless_building}},
567                      {{3,30},sys_core_fold,{ignored,useless_building}}]}},
568
569          {propagated_literal,
570           <<"
571            foo(X) ->
572                Y = [$.],
573                %% There must not be a warning for constructing a term that
574                %% is never used.
575                fun() -> X = Y ++ [$.] end(),
576                ok.
577             ">>,
578           [],
579           []}
580         ],
581    [] = run(Config, Ts),
582    ok.
583
584bin_opt_info(Config) when is_list(Config) ->
585    Code = <<"
586             t1(Bin) ->
587               case Bin of
588                 _ when byte_size(Bin) > 20 -> erlang:error(too_long);
589                 <<_,T/binary>> -> t1(T);
590                 <<>> -> ok
591             end.
592
593             %% We use a tail in a BIF instruction, remote call, function
594             %% return, and an optimizable tail call for better coverage.
595             t2(<<A,B,T/bytes>>) ->
596                 if
597                     A > B -> t2(T);
598                     A =< B -> T
599                 end;
600             t2(<<_,T/bytes>>) when byte_size(T) < 4 ->
601                 foo;
602             t2(<<_,T/bytes>>) ->
603                 split_binary(T, 4).
604           ">>,
605
606    Ws = (catch run_test(Config, Code, [bin_opt_info])),
607
608    %% This is an inexact match since the pass reports exact instructions as
609    %% part of the warnings, which may include annotations that vary from run
610    %% to run.
611    {warnings,
612     [{5,beam_ssa_bsm,{unsuitable_call,
613                       {{b_local,{b_literal,t1},1},
614                        {used_before_match,
615                         {b_set,_,_,{bif,byte_size},[_]}}}}},
616      {5,beam_ssa_bsm,{binary_created,_,_}},
617      {11,beam_ssa_bsm,{binary_created,_,_}}, %% A =< B -> T
618      {13,beam_ssa_bsm,context_reused},       %% A > B -> t2(T);
619      {16,beam_ssa_bsm,{binary_created,_,_}}, %% when byte_size(T) < 4 ->
620      {19,beam_ssa_bsm,{remote_call,
621                        {b_remote,
622                         {b_literal,erlang},
623                         {b_literal,split_binary},2}}},
624      {19,beam_ssa_bsm,{binary_created,_,_}}  %% split_binary(T, 4)
625     ]} = Ws,
626
627    %% For coverage: don't give the bin_opt_info option.
628    [] = (catch run_test(Config, Code, [])),
629
630    ok.
631
632bin_construction(Config) when is_list(Config) ->
633    Ts = [{bin_construction,
634	   <<"
635             t() ->
636                 Bin = <<1,2,3>>,
637                 <<Bin:4/binary>>.
638
639             x() ->
640                 Bin = <<1,2,3,7:4>>,
641                 <<Bin/binary>>.
642
643             y() -> <<0.5>>.
644             z() -> <<99999999999999/utf8>>.
645             w() -> <<0.5:1/float>>.
646
647             a() ->
648               Size = bad_size,
649               <<1:Size>>.
650           ">>,
651           [],
652           {warnings,[{{4,18},sys_core_fold,{failed,embedded_binary_size}},
653                      {{8,18},sys_core_fold,{failed,{embedded_unit,8,28}}},
654                      {{10,21},v3_core,{failed,bad_binary}},
655                      {{11,21},sys_core_fold,{failed,bad_unicode}},
656                      {{12,21},sys_core_fold,{failed,bad_float_size}},
657                      {{16,18},v3_kernel,{failed,bad_segment_size}}
658                     ]}}],
659    [] = run(Config, Ts),
660
661    ok.
662
663comprehensions(Config) when is_list(Config) ->
664    Ts = [{tautologic_guards,
665           <<"
666             f() -> [ true || true ].
667             g() -> << <<1>> || true >>.
668           ">>,
669           [], []}],
670    run(Config, Ts),
671    ok.
672
673maps(Config) when is_list(Config) ->
674    Ts = [{bad_map,
675           <<"
676             t() ->
677                 case maybe_map of
678                     #{} -> ok;
679                     not_map -> error
680                 end.
681             x() ->
682                 case true of
683                     #{}  -> error;
684                     true -> ok
685                 end.
686           ">>,
687           [],
688           {warnings,[{{3,18},sys_core_fold,{nomatch,no_clause}},
689                      {{9,22},sys_core_fold,{nomatch,clause_type}}]}},
690	   {bad_map_src1,
691           <<"
692             t() ->
693                 M = {a,[]},
694                 {'EXIT',{badarg,_}} = (catch(M#{ a => 1 })),
695                 ok.
696           ">>,
697           [],
698           {warnings,[{{4,48},sys_core_fold,{failed,bad_map_update}}]}},
699	   {bad_map_src2,
700           <<"
701             t() ->
702		 M = id({a,[]}),
703		 {'EXIT',{badarg,_}} = (catch(M#{ a => 1})),
704		 ok.
705	     id(I) -> I.
706           ">>,
707	   [inline],
708	    []},
709	   {bad_map_src3,
710           <<"
711             t() ->
712                 {'EXIT',{badarg,_}} = (catch <<>>#{ a := 1}),
713                 ok.
714           ">>,
715           [],
716           {warnings,[{{3,51},sys_core_fold,{failed,bad_map_update}}]}},
717           {ok_map_literal_key,
718           <<"
719             t() ->
720		 V = id(1),
721		 M = id(#{ <<$h,$i>> => V }),
722		 V = case M of
723		    #{ <<0:257>> := Val } -> Val;
724		    #{ <<$h,$i>> := Val } -> Val
725		 end,
726		 ok.
727	     id(I) -> I.
728           ">>,
729           [],
730	   []},
731           {repeated_keys1,
732           <<"
733             foo1() ->
734                 #{a=>1,
735                   b=> 2,
736                   a=>3}.
737
738             bar1(M) ->
739                 M#{a=>1, b=> 2, a:=3}.
740
741             baz1(M) ->
742                 M#{a=>1, b=> 2, a:=3}.
743
744             foo2() ->
745                 #{\"a\"=>1, \"b\"=> 2, \"a\"=>3}.
746
747             bar2(M) ->
748                 M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}.
749
750             baz2(M) ->
751                 M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}.
752
753             foo3() ->
754                 #{\"a\"=>1,
755                   \"b\"=> 2,
756                   \"a\"=>3}.
757
758             bar3(M) ->
759                 M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}.
760
761             baz3(M) ->
762                 M#{<<\"a\">>=>1, <<\"b\">>=> 2, <<\"a\">>:=3}.
763           ">>,
764           [],
765           {warnings,[{{3,20},v3_core,{map_key_repeated,a}},
766                      {{8,21},v3_core,{map_key_repeated,a}},
767                      {{11,21},v3_core,{map_key_repeated,a}},
768                      {{14,20},v3_core,{map_key_repeated,"a"}},
769                      {{17,21},v3_core,{map_key_repeated,"a"}},
770                      {{20,21},v3_core,{map_key_repeated,"a"}},
771                      {{23,20},v3_core,{map_key_repeated,"a"}},
772                      {{28,21},v3_core,{map_key_repeated,"a"}},
773                      {{31,21},v3_core,{map_key_repeated,<<"a">>}}
774                     ]}},
775           {repeated_keys2,
776           <<"
777             foo4(K) ->
778                 #{\"a\"=>1, K => 1, \"b\"=> 2, \"a\"=>3, K=>2}.
779
780             bar4(M,K) ->
781                 M#{a=>1, K =>1, b=> 2, a:=3, K=>2}.
782
783             baz4(M,K) ->
784                 M#{<<\"a\">>=>1,
785                     K => 1, <<\"b\">>=> 2,
786                     <<\"a\">>:=3, K=>2}.
787
788             foo5(K) ->
789                 #{{\"a\",1}=>1, K => 1, \"b\"=> 2, {\"a\",1}=>3, K=>2}.
790
791             bar5(M,K) ->
792                 M#{{\"a\",<<\"b\">>}=>1, K =>1,
793                    \"b\"=> 2, {\"a\",<<\"b\">>}:=3, K=>2}.
794
795             baz5(M,K) ->
796                 M#{{<<\"a\">>,1}=>1, K => 1,
797                    <<\"b\">>=> 2, {<<\"a\">>,1}:=3,K=>2}.
798
799             foo6(K) ->
800                 #{#{\"a\"=>1}=>1, K => 1, \"b\"=> 2, #{\"a\"=>1}=>3, K=>2}.
801
802             bar6(M,K) ->
803                 M#{#{\"a\"=><<\"b\">>}=>1, K =>1,
804                    \"b\"=> 2, #{\"a\"=><<\"b\">>}:=3, K=>2}.
805
806             baz6(M,K) ->
807                 M#{#{<<\"a\">>=>1}=>1,
808                    K => 1,
809                    <<\"b\">>=> 2,
810                    #{<<\"a\">>=>1}:=3,K=>2}.
811
812             foo7(K) ->
813                 M1 = #{#{\"a\"=>1}=>1, K => 1, \"b\"=> 2},
814                 M1#{#{\"a\"=>1}=>3, K=>2}.
815
816             bar7(M,K) ->
817                 M1 = M#{#{\"a\"=><<\"b\">>}=>1, K =>1, \"b\"=> 2},
818                 M1#{#{\"a\"=><<\"b\">>}:=3, K=>2}.
819
820             baz7(M,K) ->
821                 M1 = M#{#{<<\"a\">>=>1}=>1,
822                    K => 1,
823                    <<\"b\">>=> 2},
824                 M1#{#{<<\"a\">>=>1}:=3,K=>2}.
825          ">>,
826           [],
827           {warnings,[{{3,20},v3_core,{map_key_repeated,"a"}},
828                      {{6,21},v3_core,{map_key_repeated,a}},
829                      {{9,21},v3_core,{map_key_repeated,<<"a">>}},
830                      {{14,20},v3_core,{map_key_repeated,{"a",1}}},
831                      {{17,21},v3_core,{map_key_repeated,{"a",<<"b">>}}},
832                      {{21,21},v3_core,{map_key_repeated,{<<"a">>,1}}},
833                      {{25,20},v3_core,{map_key_repeated,#{"a" => 1}}},
834                      {{28,21},v3_core,{map_key_repeated,#{"a" => <<"b">>}}},
835                      {{32,21},v3_core,{map_key_repeated,#{<<"a">> => 1}}}
836                     ]}}
837         ],
838    run(Config, Ts),
839    ok.
840
841maps_bin_opt_info(Config) when is_list(Config) ->
842    Ts = [{map_bsm,
843           <<"
844             t1(<<0:8,7:8,T/binary>>,#{val := I}=M) ->
845                 t1(T, M#{val := I+1});
846             t1(<<_:8>>,M) ->
847                 M.
848           ">>,
849           [bin_opt_info],
850           {warnings,[{3,beam_ssa_bsm,context_reused}]}}],
851    [] = run(Config, Ts),
852    ok.
853
854redundant_boolean_clauses(Config) when is_list(Config) ->
855    Ts = [{redundant_boolean_clauses,
856           <<"
857             t(X) ->
858                 case X == 0 of
859                     false -> no;
860                     false -> no;
861                     true -> yes
862                 end.
863           ">>,
864           [],
865           {warnings,[{{5,22},sys_core_fold,{nomatch,shadow}}]}}],
866    run(Config, Ts),
867    ok.
868
869underscore(Config) when is_list(Config) ->
870    %% The code template.
871    S0 = <<"
872            f(A) ->
873              _VAR1 = <<A>>,
874              _VAR2 = {ok,A},
875              _VAR3 = [A],
876              ok.
877            g(A) ->
878              _VAR1 = A/0,
879              _VAR2 = date(),
880              ok.
881            h() ->
882               _VAR1 = fun() -> ok end,
883              ok.
884            i(A) ->
885               _VAR1 = #{A=>42},
886              ok.
887	 ">>,
888
889    %% Define all possible warnings.
890    Warnings = [{{3,23},sys_core_fold,{ignored,useless_building}},
891                {{4,23},sys_core_fold,{ignored,useless_building}},
892                {{5,23},sys_core_fold,{ignored,useless_building}},
893                {{8,24},sys_core_fold,{ignored,{result,{erlang,'/',2}}}},
894                {{9,23},sys_core_fold,{ignored,{no_effect,{erlang,date,0}}}},
895                {{12,24},sys_core_fold,{ignored,useless_building}},
896                {{15,24},sys_core_fold,{ignored,useless_building}}],
897
898
899    %% Compile the unmodified template. Assigning to variable that
900    %% begins with '_' should suppress all warnings.
901    Ts0 = [{underscore0,S0,[],[]}],
902    [] = run(Config, Ts0),
903
904    %% Replace all "_VAR<digit>" variables with a plain underscore.
905    %% There should still be no warnings.
906    S1 = re:replace(S0, "_VAR\\d+", "_", [global]),
907    io:format("~s\n", [S1]),
908    Ts1 = [{underscore1,S1,[],[]}],
909    [] = run(Config, Ts1),
910
911    %% Make sure that we get warnings if we remove "_VAR<digit> = ".
912    S2 = re:replace(S0, "_VAR\\d = ", "        ", [global]),
913    io:format("~s\n", [S2]),
914    Ts2 = [{underscore2,S2,[],{warnings,Warnings}}],
915    [] = run(Config, Ts2),
916
917    %% We should also get warnings if we assign to a variables that don't
918    %% begin with underscore (as well as warnings for unused variables from
919    %% erl_lint).
920    S3 = re:replace(S0, "_(?=VAR\\d+)", " ", [global]),
921    io:format("~s\n", [S3]),
922    Ts3 = [{underscore2,S3,[],{warnings,Warnings}}],
923    [] = run(Config, Ts3),
924
925    ok.
926
927no_warnings(Config) when is_list(Config) ->
928    Ts = [{no_warnings,
929           <<"-record(r, {s=ordsets:new(),a,b}).
930
931              a() ->
932                R = #r{},			%No warning expected.
933                {R#r.a,R#r.b}.
934
935              b(X) ->
936                T = true,
937                Var = [X],			%No warning expected.
938                case T of
939	          false -> Var;
940                  true -> []
941                end.
942
943              c() ->
944                R0 = {r,\"abc\",undefined,os:timestamp()}, %No warning.
945                case R0 of
946	          {r,V1,_V2,V3} -> {r,V1,\"def\",V3}
947                end.
948
949              d(In0, Bool) ->
950                {In1,Int} = case id(Bool) of
951                              false -> {In0,0}
952                            end,
953                [In1,Int].
954
955              id(I) -> I.
956           ">>,
957           [],
958           []}],
959    run(Config, Ts),
960    ok.
961
962bit_syntax(Config) ->
963    Ts = [{?FUNCTION_NAME,
964           <<"
965              a(<<-1>>) -> ok;
966              a(<<1023>>) -> ok;
967              a(<<777/signed>>) -> ok;
968              a(<<a/binary>>) -> ok;
969              a(<<a/integer>>) -> ok;
970              a(<<a/float>>) -> ok;
971              a(<<a/utf8>>) -> ok;
972              a(<<a/utf16>>) -> ok;
973              a(<<a/utf32>>) -> ok;
974              a(<<a/utf32>>) -> ok.
975              b(Bin) -> Sz = bad, <<42:Sz>> = Bin.
976              c(Sz, Bin) ->
977                case Bin of
978                  <<-42:Sz/unsigned>> -> ok;
979                  <<42:Sz/float>> -> ok;
980                  <<42:Sz/binary>> -> ok
981                end.
982              d(<<16#110000/utf8>>) -> error;
983              d(_) -> ok.
984             ">>,
985	   [],
986           {warnings,[{{2,15},sys_core_fold,{nomatch,no_clause}},
987                      {{2,19},sys_core_fold,{nomatch,{bit_syntax_unsigned,-1}}},
988                      {{3,19},sys_core_fold,{nomatch,{bit_syntax_truncated,
989                                             unsigned,1023,8}}},
990                      {{4,19},sys_core_fold,{nomatch,{bit_syntax_truncated,
991                                             signed,777,8}}},
992                      {{5,19},sys_core_fold,{nomatch,{bit_syntax_type,a,binary}}},
993                      {{6,19},sys_core_fold,{nomatch,{bit_syntax_type,a,integer}}},
994                      {{7,19},sys_core_fold,{nomatch,{bit_syntax_type,a,float}}},
995                      {{8,19},sys_core_fold,{nomatch,{bit_syntax_type,a,utf8}}},
996                      {{9,19},sys_core_fold,{nomatch,{bit_syntax_type,a,utf16}}},
997                      {{10,19},sys_core_fold,{nomatch,{bit_syntax_type,a,utf32}}},
998                      {{11,19},sys_core_fold,{nomatch,{bit_syntax_type,a,utf32}}},
999                      {{12,35},sys_core_fold,{nomatch,no_clause}},
1000                      {{12,37},sys_core_fold,{nomatch,{bit_syntax_size,bad}}},
1001                      {{15,21},sys_core_fold,{nomatch,{bit_syntax_unsigned,-42}}},
1002                      {{17,21},sys_core_fold,{nomatch,{bit_syntax_type,42,binary}}},
1003                      {{19,19},sys_core_fold,{nomatch,{bit_syntax_unicode,1114112}}}
1004                     ]}
1005          }],
1006    run(Config, Ts),
1007    ok.
1008
1009inlining(Config) ->
1010    %% Make sure that no spurious warnings are generated
1011    %% when inlining.
1012    Ts = [{inlining_1,
1013           <<"-compile(inline).
1014              compute1(X) -> add(X, 0).
1015              add(1, 0) -> 1;
1016              add(1, Y) -> 1 + Y;
1017              add(X, Y) -> X + Y.
1018           ">>,
1019           [],
1020           []},
1021	  {inlining_2,
1022           <<"-compile({inline,[add/2]}).
1023              compute1(X) -> add(X, 0).
1024              add(1, 0) -> 1;
1025              add(1, Y) -> 1 + Y;
1026              add(X, Y) -> X + Y.
1027           ">>,
1028           [],
1029           []}
1030	 ],
1031    run(Config, Ts),
1032    ok.
1033
1034tuple_calls(Config) ->
1035    %% Make sure that no spurious warnings are generated.
1036    Ts = [{inlining_1,
1037           <<"-compile(tuple_calls).
1038              dispatch(X) ->
1039                (list_to_atom(\"prefix_\" ++
1040                atom_to_list(suffix))):doit(X).
1041           ">>,
1042           [],
1043           []}
1044	 ],
1045    run(Config, Ts),
1046    ok.
1047
1048recv_opt_info(Config) when is_list(Config) ->
1049    Code = <<"
1050                simple_receive() ->
1051                    receive
1052                        Message -> handle:msg(Message)
1053                    end.
1054
1055                selective_receive(Tag, Message) ->
1056                    receive
1057                        {Tag, Message} -> handle:msg(Message)
1058                    end.
1059
1060                cross_function_receive() ->
1061                    cross_function_receive_1(make_ref()).
1062
1063                cross_function_receive_1(Tag) ->
1064                    receive
1065                        {Tag, Message} -> handle:msg(Message)
1066                    end.
1067
1068                optimized_receive(Process, Request) ->
1069                    MRef = monitor(process, Process),
1070                    Process ! {self(), MRef, Request},
1071                    receive
1072                        {MRef, Reply} ->
1073                            erlang:demonitor(MRef, [flush]),
1074                            handle:reply(Reply);
1075                        {'DOWN', MRef, _, _, Reason} ->
1076                            handle:error(Reason)
1077                    end.
1078           ">>,
1079
1080    Ws = (catch run_test(Config, Code, [recv_opt_info])),
1081
1082    %% This is an inexact match since the pass reports exact instructions as
1083    %% part of the warnings, which may include annotations that vary from run
1084    %% to run.
1085    {warnings,
1086        [%% simple_receive/0
1087         {3,beam_ssa_recv,matches_any_message},
1088         %% selective_receive/2
1089         {8,beam_ssa_recv,unoptimized_selective_receive},
1090         {13,beam_ssa_recv,reserved_receive_marker},
1091         %% cross_function_receive/0
1092         {13,beam_ssa_recv,{passed_marker,_}},
1093         %% cross_function_receive_1/1
1094         {16,beam_ssa_recv,{used_receive_marker,{parameter,1}}},
1095         %% optimized_receive/2
1096         {21,beam_ssa_recv,reserved_receive_marker},
1097         {23,beam_ssa_recv,{used_receive_marker,_}}]} = Ws,
1098
1099    %% For coverage: don't give the recv_opt_info option.
1100    [] = (catch run_test(Config, Code, [])),
1101
1102    ok.
1103
1104%% OTP-17260: Test that opportunistic warnings can be disabled.
1105opportunistic_warnings(Config) ->
1106    Source = <<"m(_) -> ok;
1107                m(_) -> error.
1108
1109                a() -> <<0.5>>.
1110                b() -> Bin = <<1,2,3,7:4>>, <<Bin/binary>>.
1111                c() -> Size = bad_size, <<1:Size>>.
1112
1113                i() -> {a,b,c}, ok.
1114           ">>,
1115
1116    %% Don't disable any warnings.
1117    Ts1 = [{nothing_disabled,
1118            Source,
1119            [],
1120            {warnings,[{{2,17},sys_core_fold,{nomatch,{shadow,1,{m,1}}}},
1121                       {{4,24},v3_core,{failed,bad_binary}},
1122                       {{5,45},sys_core_fold,{failed,{embedded_unit,8,28}}},
1123                       {{6,43},v3_kernel,{failed,bad_segment_size}},
1124                       {{8,24},sys_core_fold,{ignored,useless_building}}
1125                      ]}}],
1126    [] = run(Config, Ts1),
1127
1128    %% Disable all opportunistic warnings.
1129    Ts2 = [{all_disabled,
1130            Source,
1131            [nowarn_opportunistic],
1132            []}],
1133    [] = run(Config, Ts2),
1134
1135    %% Disable warnings for patterns that don't match.
1136    Ts3 = [{nomatch_disabled,
1137            Source,
1138            [nowarn_nomatch],
1139            {warnings,[{{4,24},v3_core,{failed,bad_binary}},
1140                       {{5,45},sys_core_fold,{failed,{embedded_unit,8,28}}},
1141                       {{6,43},v3_kernel,{failed,bad_segment_size}},
1142                       {{8,24},sys_core_fold,{ignored,useless_building}}
1143                      ]}}],
1144    [] = run(Config, Ts3),
1145
1146    %% Disable warnings for failures.
1147    Ts4 = [{failures_disabled,
1148            Source,
1149            [nowarn_failed],
1150            {warnings,[{{2,17},sys_core_fold,{nomatch,{shadow,1,{m,1}}}},
1151                       {{8,24},sys_core_fold,{ignored,useless_building}}
1152                      ]}}],
1153    [] = run(Config, Ts4),
1154
1155    %% Disable warnings for useless building.
1156    Ts5 = [{disabled_useless_building,
1157            Source,
1158            [nowarn_ignored],
1159            {warnings,[{{2,17},sys_core_fold,{nomatch,{shadow,1,{m,1}}}},
1160                       {{4,24},v3_core,{failed,bad_binary}},
1161                       {{5,45},sys_core_fold,{failed,{embedded_unit,8,28}}},
1162                       {{6,43},v3_kernel,{failed,bad_segment_size}}
1163                      ]}}],
1164    [] = run(Config, Ts5),
1165
1166    %% Disable warnings for useless building and failures.
1167    Ts6 = [{disabled_combination,
1168            Source,
1169            [nowarn_ignored,nowarn_failed],
1170            {warnings,[{{2,17},sys_core_fold,{nomatch,{shadow,1,{m,1}}}}
1171                      ]}}],
1172    [] = run(Config, Ts6),
1173
1174
1175    ok.
1176
1177%%%
1178%%% End of test cases.
1179%%%
1180
1181run(Config, Tests0) ->
1182    do_run(Config, Tests0),
1183
1184    %% Now test without column numbers.
1185    Tests = [lines_only(T) || T <- Tests0],
1186    do_run(Config, Tests).
1187
1188lines_only({Name,Test,Opts,{warnings,Result0}}) ->
1189    Result1 = lists:map(fun lines_only_1/1, Result0),
1190    Result = {warnings,lists:usort(Result1)},
1191    {Name,Test,[{error_location,line}|Opts],Result};
1192lines_only(NoWarnings) -> NoWarnings.
1193
1194lines_only_1({File,Es0}) when is_list(Es0) ->
1195    Es = [lines_only_1(E) || E <- Es0],
1196    {File,Es};
1197lines_only_1({Loc,Mod,Error}) ->
1198    case Loc of
1199        {Line,_Col} ->
1200            {Line,Mod,Error};
1201        Line when is_integer(Line) ->
1202            {Line,Mod,Error}
1203    end.
1204
1205do_run(Config, Tests) ->
1206    F = fun({N,P,Ws,E}, BadL) ->
1207                io:format("### ~s\n", [N]),
1208                case catch run_test(Config, P, Ws) of
1209                    E ->
1210                        BadL;
1211                    Bad ->
1212                        io:format("~nTest ~p failed. Expected~n  ~p~n"
1213                                  "but got~n  ~p~n", [N, E, Bad]),
1214			fail()
1215                end
1216        end,
1217    lists:foldl(F, [], Tests).
1218
1219%% Compiles a test module and returns the list of errors and warnings.
1220
1221run_test(Conf, Test0, Warnings) ->
1222    Module = "warnings" ++ test_lib:uniq(),
1223    Filename = Module ++ ".erl",
1224    DataDir = ?privdir,
1225    Test1 = ["-module(", Module, "). -file( \"", Filename, "\", 1). ", Test0],
1226    Test = iolist_to_binary(Test1),
1227    File = filename:join(DataDir, Filename),
1228    Opts = [binary,export_all,return|Warnings],
1229    ok = file:write_file(File, Test),
1230
1231    %% Compile once just to print all warnings (and cover more code).
1232    compile:file(File, [binary,export_all,report|Warnings]),
1233
1234    %% Test result of compilation.
1235    Res = case compile:file(File, Opts) of
1236	      {ok, _M, Bin, []} when is_binary(Bin) ->
1237		  [];
1238	      {ok, _M, Bin, Ws0} when is_binary(Bin) ->
1239		  %% We are not interested in warnings from
1240		  %% erl_lint here.
1241		  WsL = [{F,[W || {_,Mod,_}=W <- Ws,
1242				  Mod =/= erl_lint]} ||
1243			    {F,Ws} <- Ws0],
1244		  case WsL of
1245		      [{_File,Ws}] ->
1246                          print_warnings(Ws, Test),
1247                          {warnings, Ws};
1248		      _ ->
1249                          list_to_tuple([warnings, WsL])
1250		  end
1251	  end,
1252    file:delete(File),
1253    Res.
1254
1255print_warnings(Warnings, Source) ->
1256    Lines = binary:split(Source, <<"\n">>, [global]),
1257    Cs = [print_warning(W, Lines) || W <- Warnings],
1258    io:put_chars(Cs),
1259    ok.
1260
1261print_warning({{LineNum,Column},Mod,Data}, Lines) ->
1262    Line0 = lists:nth(LineNum, Lines),
1263    <<Line1:(Column-1)/binary,_/binary>> = Line0,
1264    Spaces = re:replace(Line1, <<"[^\t]">>, <<" ">>, [global]),
1265    CaretLine = [Spaces,"^"],
1266    [io_lib:format("~p:~p: ~ts\n",
1267                   [LineNum,Column,Mod:format_error(Data)]),
1268     Line0, "\n",
1269     CaretLine, "\n\n"];
1270print_warning(_, _) ->
1271    [].
1272
1273fail() ->
1274    ct:fail(failed).
1275