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