1Code.require_file("../test_helper.exs", __DIR__) 2 3defmodule Kernel.WarningTest do 4 use ExUnit.Case 5 import ExUnit.CaptureIO 6 7 defp capture_err(fun) do 8 capture_io(:stderr, fun) 9 end 10 11 test "outdented heredoc" do 12 output = 13 capture_err(fn -> 14 Code.eval_string(""" 15 ''' 16 outdented 17 ''' 18 """) 19 end) 20 21 assert output =~ "outdented heredoc line" 22 assert output =~ "nofile:2" 23 end 24 25 test "does not warn on incomplete tokenization" do 26 assert {:error, _} = Code.string_to_quoted(~s[:"foobar" do]) 27 end 28 29 test "operators formed by many of the same character followed by that character" do 30 output = 31 capture_err(fn -> 32 Code.eval_string("quote do: ....()") 33 end) 34 35 assert output =~ "found \"...\" followed by \".\", please use parens around \"...\" instead" 36 end 37 38 test "identifier that ends in ! followed by the = operator without a space in between" do 39 output = capture_err(fn -> Code.eval_string("foo!= 1") end) 40 assert output =~ "found identifier \"foo!\", ending with \"!\"" 41 42 output = capture_err(fn -> Code.eval_string(":foo!= :foo!") end) 43 assert output =~ "found atom \":foo!\", ending with \"!\"" 44 end 45 46 describe "unnecessary quotes" do 47 test "does not warn for unnecessary quotes in uppercase atoms/keywords" do 48 assert capture_err(fn -> Code.eval_string(~s/:"Foo"/) end) == "" 49 assert capture_err(fn -> Code.eval_string(~s/["Foo": :bar]/) end) == "" 50 assert capture_err(fn -> Code.eval_string(~s/:"Foo"/) end) == "" 51 assert capture_err(fn -> Code.eval_string(~s/:"foo@bar"/) end) == "" 52 assert capture_err(fn -> Code.eval_string(~s/:"héllò"/) end) == "" 53 end 54 55 test "warns for unnecessary quotes" do 56 assert capture_err(fn -> Code.eval_string(~s/:"foo"/) end) =~ 57 "found quoted atom \"foo\" but the quotes are not required" 58 59 assert capture_err(fn -> Code.eval_string(~s/["foo": :bar]/) end) =~ 60 "found quoted keyword \"foo\" but the quotes are not required" 61 62 assert capture_err(fn -> Code.eval_string(~s/[Kernel."length"([])]/) end) =~ 63 "found quoted call \"length\" but the quotes are not required" 64 end 65 end 66 67 test "unused variable" do 68 output = 69 capture_err(fn -> 70 # Note we use compile_string because eval_string does not emit unused vars warning 71 Code.compile_string(""" 72 defmodule Sample do 73 module = 1 74 def hello(arg), do: nil 75 end 76 file = 2 77 file = 3 78 file 79 """) 80 end) 81 82 assert output =~ "variable \"arg\" is unused" 83 assert output =~ "variable \"module\" is unused" 84 assert output =~ "variable \"file\" is unused" 85 after 86 purge(Sample) 87 end 88 89 test "unused variable that could be pinned" do 90 output = 91 capture_err(fn -> 92 # Note we use compile_string because eval_string does not emit unused vars warning 93 Code.compile_string(""" 94 defmodule Sample do 95 def test do 96 compare_local = "hello" 97 match?(compare_local, "hello") 98 99 compare_nested = "hello" 100 case "hello" do 101 compare_nested -> true 102 _other -> false 103 end 104 end 105 end 106 """) 107 end) 108 109 assert output =~ 110 "variable \"compare_local\" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)" 111 112 assert output =~ 113 "variable \"compare_nested\" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used)" 114 after 115 purge(Sample) 116 end 117 118 test "unused compiler variable" do 119 output = 120 capture_err(fn -> 121 Code.eval_string(""" 122 defmodule Sample do 123 def hello(__MODULE___), do: :ok 124 def world(_R), do: :ok 125 end 126 """) 127 end) 128 129 assert output =~ "unknown compiler variable \"__MODULE___\"" 130 refute output =~ "unknown compiler variable \"_R\"" 131 after 132 purge(Sample) 133 end 134 135 test "nested unused variable" do 136 message = "variable \"x\" is unused" 137 138 assert capture_err(fn -> 139 assert_raise CompileError, ~r/undefined function x/, fn -> 140 Code.eval_string(""" 141 case false do 142 true -> x = 1 143 _ -> 1 144 end 145 x 146 """) 147 end 148 end) =~ message 149 150 assert capture_err(fn -> 151 assert_raise CompileError, ~r/undefined function x/, fn -> 152 Code.eval_string(""" 153 false and (x = 1) 154 x 155 """) 156 end 157 end) =~ message 158 159 assert capture_err(fn -> 160 assert_raise CompileError, ~r/undefined function x/, fn -> 161 Code.eval_string(""" 162 true or (x = 1) 163 x 164 """) 165 end 166 end) =~ message 167 168 assert capture_err(fn -> 169 assert_raise CompileError, ~r/undefined function x/, fn -> 170 Code.eval_string(""" 171 if false do 172 x = 1 173 end 174 x 175 """) 176 end 177 end) =~ message 178 179 assert capture_err(fn -> 180 assert_raise CompileError, ~r/undefined function x/, fn -> 181 Code.eval_string(""" 182 cond do 183 false -> x = 1 184 true -> 1 185 end 186 x 187 """) 188 end 189 end) =~ message 190 191 assert capture_err(fn -> 192 assert_raise CompileError, ~r/undefined function x/, fn -> 193 Code.eval_string(""" 194 receive do 195 :foo -> x = 1 196 after 197 0 -> 1 198 end 199 x 200 """) 201 end 202 end) =~ message 203 204 assert capture_err(fn -> 205 assert_raise CompileError, ~r/undefined function x/, fn -> 206 Code.eval_string(""" 207 false && (x = 1) 208 x 209 """) 210 end 211 end) =~ message 212 213 assert capture_err(fn -> 214 assert_raise CompileError, ~r/undefined function x/, fn -> 215 Code.eval_string(""" 216 true || (x = 1) 217 x 218 """) 219 end 220 end) =~ message 221 222 assert capture_err(fn -> 223 assert_raise CompileError, ~r/undefined function x/, fn -> 224 Code.eval_string(""" 225 with true <- true do 226 x = false 227 end 228 x 229 """) 230 end 231 end) =~ message 232 233 assert capture_err(fn -> 234 assert_raise CompileError, ~r/undefined function x/, fn -> 235 Code.eval_string(""" 236 fn -> 237 x = true 238 end 239 x 240 """) 241 end 242 end) =~ message 243 end 244 245 test "unused variable in redefined function in different file" do 246 output = 247 capture_err(fn -> 248 Code.eval_string(""" 249 defmodule Sample do 250 defmacro __using__(_) do 251 quote location: :keep do 252 def function(arg) 253 end 254 end 255 end 256 """) 257 258 code = """ 259 defmodule RedefineSample do 260 use Sample 261 def function(var123), do: nil 262 end 263 """ 264 265 Code.eval_string(code, [], file: "redefine_sample.ex") 266 end) 267 268 assert output =~ "redefine_sample.ex:3" 269 assert output =~ "variable \"var123\" is unused" 270 after 271 purge(Sample) 272 purge(RedefineSample) 273 end 274 275 test "useless literal" do 276 message = "code block contains unused literal \"oops\"" 277 278 assert capture_err(fn -> 279 Code.eval_string(""" 280 "oops" 281 :ok 282 """) 283 end) =~ message 284 285 assert capture_err(fn -> 286 Code.eval_string(""" 287 fn -> 288 "oops" 289 :ok 290 end 291 """) 292 end) =~ message 293 294 assert capture_err(fn -> 295 Code.eval_string(""" 296 try do 297 "oops" 298 :ok 299 after 300 :ok 301 end 302 """) 303 end) =~ message 304 end 305 306 test "useless attr" do 307 message = 308 capture_err(fn -> 309 Code.eval_string(""" 310 defmodule Sample do 311 @foo 1 312 @bar 1 313 @foo 314 315 def bar do 316 @bar 317 :ok 318 end 319 end 320 """) 321 end) 322 323 assert message =~ "module attribute @foo in code block has no effect as it is never returned " 324 assert message =~ "module attribute @bar in code block has no effect as it is never returned " 325 after 326 purge(Sample) 327 end 328 329 test "useless var" do 330 message = "variable foo in code block has no effect as it is never returned " 331 332 assert capture_err(fn -> 333 Code.eval_string(""" 334 foo = 1 335 foo 336 :ok 337 """) 338 end) =~ message 339 340 assert capture_err(fn -> 341 Code.eval_string(""" 342 fn -> 343 foo = 1 344 foo 345 :ok 346 end 347 """) 348 end) =~ message 349 350 assert capture_err(fn -> 351 Code.eval_string(""" 352 try do 353 foo = 1 354 foo 355 :ok 356 after 357 :ok 358 end 359 """) 360 end) =~ message 361 362 assert capture_err(fn -> 363 Code.eval_string(""" 364 node() 365 :ok 366 """) 367 end) == "" 368 end 369 370 test "underscored variable on match" do 371 assert capture_err(fn -> 372 Code.eval_string(""" 373 {_arg, _arg} = {1, 1} 374 """) 375 end) =~ "the underscored variable \"_arg\" appears more than once in a match" 376 end 377 378 test "underscored variable on use" do 379 assert capture_err(fn -> 380 Code.eval_string(""" 381 fn _var -> _var + 1 end 382 """) 383 end) =~ "the underscored variable \"_var\" is used after being set" 384 385 assert capture_err(fn -> 386 Code.eval_string(""" 387 fn var!(_var, Foo) -> var!(_var, Foo) + 1 end 388 """) 389 end) =~ "" 390 end 391 392 test "unused function" do 393 assert capture_err(fn -> 394 Code.eval_string(""" 395 defmodule Sample1 do 396 defp hello, do: nil 397 end 398 """) 399 end) =~ "function hello/0 is unused\n nofile:2" 400 401 assert capture_err(fn -> 402 Code.eval_string(""" 403 defmodule Sample2 do 404 defp hello(0), do: hello(1) 405 defp hello(1), do: :ok 406 end 407 """) 408 end) =~ "function hello/1 is unused\n nofile:2" 409 410 assert capture_err(fn -> 411 Code.eval_string(~S""" 412 defmodule Sample3 do 413 def a, do: nil 414 def b, do: d(10) 415 defp c(x, y \\ 1), do: [x, y] 416 defp d(x), do: x 417 end 418 """) 419 end) =~ "function c/2 is unused\n nofile:4" 420 421 assert capture_err(fn -> 422 Code.eval_string(~S""" 423 defmodule Sample4 do 424 def a, do: nil 425 defp b(x \\ 1, y \\ 1) 426 defp b(x, y), do: [x, y] 427 end 428 """) 429 end) =~ "function b/2 is unused\n nofile:3" 430 after 431 purge([Sample1, Sample2, Sample3, Sample4]) 432 end 433 434 test "unused cyclic functions" do 435 message = 436 capture_err(fn -> 437 Code.eval_string(""" 438 defmodule Sample do 439 defp a, do: b() 440 defp b, do: a() 441 end 442 """) 443 end) 444 445 assert message =~ "function a/0 is unused\n nofile:2" 446 assert message =~ "function b/0 is unused\n nofile:3" 447 after 448 purge(Sample) 449 end 450 451 test "unused macro" do 452 assert capture_err(fn -> 453 Code.eval_string(""" 454 defmodule Sample do 455 defmacrop hello, do: nil 456 end 457 """) 458 end) =~ "macro hello/0 is unused" 459 after 460 purge(Sample) 461 end 462 463 test "shadowing" do 464 assert capture_err(fn -> 465 Code.eval_string(""" 466 defmodule Sample do 467 def test(x) do 468 case x do 469 {:file, fid} -> fid 470 {:path, _} -> fn(fid) -> fid end 471 end 472 end 473 end 474 """) 475 end) == "" 476 after 477 purge(Sample) 478 end 479 480 test "unused default args" do 481 assert capture_err(fn -> 482 Code.eval_string(~S""" 483 defmodule Sample1 do 484 def a, do: b(1, 2, 3) 485 defp b(arg1 \\ 1, arg2 \\ 2, arg3 \\ 3), do: [arg1, arg2, arg3] 486 end 487 """) 488 end) =~ "default values for the optional arguments in b/3 are never used\n nofile:3" 489 490 assert capture_err(fn -> 491 Code.eval_string(~S""" 492 defmodule Sample2 do 493 def a, do: b(1, 2) 494 defp b(arg1 \\ 1, arg2 \\ 2, arg3 \\ 3), do: [arg1, arg2, arg3] 495 end 496 """) 497 end) =~ 498 "the default values for the first 2 optional arguments in b/3 are never used\n nofile:3" 499 500 assert capture_err(fn -> 501 Code.eval_string(~S""" 502 defmodule Sample3 do 503 def a, do: b(1) 504 defp b(arg1 \\ 1, arg2 \\ 2, arg3 \\ 3), do: [arg1, arg2, arg3] 505 end 506 """) 507 end) =~ 508 "the default value for the first optional argument in b/3 is never used\n nofile:3" 509 510 assert capture_err(fn -> 511 Code.eval_string(~S""" 512 defmodule Sample4 do 513 def a, do: b(1) 514 defp b(arg1 \\ 1, arg2, arg3 \\ 3), do: [arg1, arg2, arg3] 515 end 516 """) 517 end) == "" 518 519 assert capture_err(fn -> 520 Code.eval_string(~S""" 521 defmodule Sample5 do 522 def a, do: b(1, 2, 3) 523 defp b(arg1 \\ 1, arg2 \\ 2, arg3 \\ 3) 524 525 defp b(arg1, arg2, arg3), do: [arg1, arg2, arg3] 526 end 527 """) 528 end) =~ "default values for the optional arguments in b/3 are never used\n nofile:3" 529 530 assert capture_err(fn -> 531 Code.eval_string(~S""" 532 defmodule Sample6 do 533 def a, do: b(1, 2) 534 defp b(arg1 \\ 1, arg2 \\ 2, arg3 \\ 3) 535 536 defp b(arg1, arg2, arg3), do: [arg1, arg2, arg3] 537 end 538 """) 539 end) =~ 540 "the default values for the first 2 optional arguments in b/3 are never used\n nofile:3" 541 after 542 purge([Sample1, Sample2, Sample3, Sample4, Sample5, Sample6]) 543 end 544 545 test "unused import" do 546 assert capture_err(fn -> 547 Code.compile_string(""" 548 defmodule Sample do 549 import :lists 550 def a, do: nil 551 end 552 """) 553 end) =~ "unused import :lists\n" 554 555 assert capture_err(fn -> 556 Code.compile_string(""" 557 import :lists 558 """) 559 end) =~ "unused import :lists\n" 560 after 561 purge(Sample) 562 end 563 564 test "unused import of one of the functions in :only" do 565 output = 566 capture_err(fn -> 567 Code.compile_string(""" 568 defmodule Sample do 569 import String, only: [upcase: 1, downcase: 1, trim: 1] 570 def a, do: upcase("hello") 571 end 572 """) 573 end) 574 575 assert output =~ "unused import String.downcase/1" 576 assert output =~ "unused import String.trim/1" 577 after 578 purge(Sample) 579 end 580 581 test "unused import of any of the functions in :only" do 582 assert capture_err(fn -> 583 Code.compile_string(""" 584 defmodule Sample do 585 import String, only: [upcase: 1, downcase: 1] 586 def a, do: nil 587 end 588 """) 589 end) =~ "unused import String\n" 590 after 591 purge(Sample) 592 end 593 594 test "unused alias" do 595 assert capture_err(fn -> 596 Code.compile_string(""" 597 defmodule Sample do 598 alias :lists, as: List 599 def a, do: nil 600 end 601 """) 602 end) =~ "unused alias List" 603 after 604 purge(Sample) 605 end 606 607 test "unused alias when also import" do 608 assert capture_err(fn -> 609 Code.compile_string(""" 610 defmodule Sample do 611 alias :lists, as: List 612 import MapSet 613 new() 614 end 615 """) 616 end) =~ "unused alias List" 617 after 618 purge(Sample) 619 end 620 621 test "unused inside dynamic module" do 622 import List, only: [flatten: 1], warn: false 623 624 assert capture_err(fn -> 625 defmodule Sample do 626 import String, only: [downcase: 1] 627 628 def world do 629 flatten([1, 2, 3]) 630 end 631 end 632 end) =~ "unused import String" 633 after 634 purge(Sample) 635 end 636 637 test "duplicate map keys" do 638 output = 639 capture_err(fn -> 640 defmodule DuplicateMapKeys do 641 assert %{a: :b, a: :c} == %{a: :c} 642 assert %{m: :n, m: :o, m: :p} == %{m: :p} 643 assert %{1 => 2, 1 => 3} == %{1 => 3} 644 end 645 end) 646 647 assert output =~ "key :a will be overridden in map" 648 assert output =~ "key :m will be overridden in map" 649 assert output =~ "key 1 will be overridden in map" 650 651 assert map_size(%{System.unique_integer() => 1, System.unique_integer() => 2}) == 2 652 end 653 654 test "unused guard" do 655 assert capture_err(fn -> 656 Code.eval_string(""" 657 defmodule Sample do 658 def atom_case do 659 v = "bc" 660 case v do 661 _ when is_atom(v) -> :ok 662 _ -> :fail 663 end 664 end 665 end 666 """) 667 end) =~ "this check/guard will always yield the same result" 668 after 669 purge(Sample) 670 end 671 672 test "length(list) == 0 in guard" do 673 error_message = 674 capture_err(fn -> 675 Code.eval_string(""" 676 defmodule Sample do 677 def list_case do 678 v = [] 679 case v do 680 _ when length(v) == 0 -> :ok 681 _ -> :fail 682 end 683 end 684 end 685 """) 686 end) 687 688 assert error_message =~ "do not use \"length(v) == 0\" to check if a list is empty" 689 690 assert error_message =~ 691 "Prefer to pattern match on an empty list or use \"v == []\" as a guard" 692 after 693 purge(Sample) 694 end 695 696 test "length(list) > 0 in guard" do 697 error_message = 698 capture_err(fn -> 699 Code.eval_string(""" 700 defmodule Sample do 701 def list_case do 702 v = [] 703 case v do 704 _ when length(v) > 0 -> :ok 705 _ -> :fail 706 end 707 end 708 end 709 """) 710 end) 711 712 assert error_message =~ "do not use \"length(v) > 0\" to check if a list is not empty" 713 714 assert error_message =~ 715 "Prefer to pattern match on a non-empty list, such as [_ | _], or use \"v != []\" as a guard" 716 after 717 purge(Sample) 718 end 719 720 test "late function heads" do 721 assert capture_err(fn -> 722 Code.eval_string(""" 723 defmodule Sample1 do 724 defmacro __using__(_) do 725 quote do 726 def add(a, b), do: a + b 727 end 728 end 729 end 730 731 defmodule Sample2 do 732 use Sample1 733 @doc "hello" 734 def add(a, b) 735 end 736 """) 737 end) == "" 738 739 assert capture_err(fn -> 740 Code.eval_string(""" 741 defmodule Sample3 do 742 def add(a, b), do: a + b 743 @doc "hello" 744 def add(a, b) 745 end 746 """) 747 end) =~ "function head for def add/2 must come at the top of its direct implementation" 748 after 749 purge([Sample1, Sample2, Sample3]) 750 end 751 752 test "used import via alias" do 753 assert capture_err(fn -> 754 Code.eval_string(""" 755 defmodule Sample1 do 756 import List, only: [flatten: 1] 757 758 defmacro generate do 759 List.duplicate(quote(do: flatten([1, 2, 3])), 100) 760 end 761 end 762 763 defmodule Sample2 do 764 import Sample1 765 generate() 766 end 767 """) 768 end) == "" 769 after 770 purge([Sample1, Sample2]) 771 end 772 773 test "clause not match" do 774 assert capture_err(fn -> 775 Code.eval_string(""" 776 defmodule Sample do 777 def hello, do: nil 778 def hello, do: nil 779 end 780 """) 781 end) =~ 782 ~r"this clause( for hello/0)? cannot match because a previous clause at line 2 always matches" 783 after 784 purge(Sample) 785 end 786 787 test "generated clause not match" do 788 assert capture_err(fn -> 789 Code.eval_string(""" 790 defmodule Sample do 791 defmacro __using__(_) do 792 quote do 793 def hello, do: nil 794 def hello, do: nil 795 end 796 end 797 end 798 defmodule UseSample do 799 use Sample 800 end 801 """) 802 end) =~ 803 ~r"this clause( for hello/0)? cannot match because a previous clause at line 10 always matches" 804 after 805 purge(Sample) 806 purge(UseSample) 807 end 808 809 test "deprecated not left in right" do 810 assert capture_err(fn -> 811 Code.eval_string("not 1 in [1, 2, 3]") 812 end) =~ "deprecated" 813 end 814 815 test "clause with defaults should be first" do 816 message = "def hello/1 has multiple clauses and also declares default values" 817 818 assert capture_err(fn -> 819 Code.eval_string(~S""" 820 defmodule Sample1 do 821 def hello(arg), do: arg 822 def hello(arg \\ 0), do: arg 823 end 824 """) 825 end) =~ message 826 827 assert capture_err(fn -> 828 Code.eval_string(~S""" 829 defmodule Sample2 do 830 def hello(_arg) 831 def hello(arg \\ 0), do: arg 832 end 833 """) 834 end) =~ message 835 after 836 purge([Sample1, Sample2]) 837 end 838 839 test "clauses with default should use header" do 840 message = "def hello/1 has multiple clauses and also declares default values" 841 842 assert capture_err(fn -> 843 Code.eval_string(~S""" 844 defmodule Sample do 845 def hello(arg \\ 0), do: arg 846 def hello(arg), do: arg 847 end 848 """) 849 end) =~ message 850 after 851 purge(Sample) 852 end 853 854 test "unused with local with overridable" do 855 assert capture_err(fn -> 856 Code.eval_string(""" 857 defmodule Sample do 858 def hello, do: world() 859 defp world, do: :ok 860 defoverridable [hello: 0] 861 def hello, do: :ok 862 end 863 """) 864 end) =~ "function world/0 is unused" 865 after 866 purge(Sample) 867 end 868 869 test "undefined module attribute" do 870 assert capture_err(fn -> 871 Code.eval_string(""" 872 defmodule Sample do 873 @foo 874 end 875 """) 876 end) =~ 877 "undefined module attribute @foo, please remove access to @foo or explicitly set it before access" 878 after 879 purge(Sample) 880 end 881 882 test "parens with module attribute" do 883 assert capture_err(fn -> 884 Code.eval_string(""" 885 defmodule Sample do 886 @foo 13 887 @foo() 888 end 889 """) 890 end) =~ 891 "the @foo() notation (with parenthesis) is deprecated, please use @foo (without parenthesis) instead" 892 after 893 purge(Sample) 894 end 895 896 test "undefined module attribute in function" do 897 assert capture_err(fn -> 898 Code.eval_string(""" 899 defmodule Sample do 900 def hello do 901 @foo 902 end 903 end 904 """) 905 end) =~ 906 "undefined module attribute @foo, please remove access to @foo or explicitly set it before access" 907 after 908 purge(Sample) 909 end 910 911 test "undefined module attribute with file" do 912 assert capture_err(fn -> 913 Code.eval_string(""" 914 defmodule Sample do 915 @foo 916 end 917 """) 918 end) =~ 919 "undefined module attribute @foo, please remove access to @foo or explicitly set it before access" 920 after 921 purge(Sample) 922 end 923 924 test "parse transform" do 925 assert capture_err(fn -> 926 Code.eval_string(""" 927 defmodule Sample do 928 @compile {:parse_transform, :ms_transform} 929 end 930 """) 931 end) =~ "@compile {:parse_transform, :ms_transform} is deprecated" 932 after 933 purge(Sample) 934 end 935 936 test "@compile inline no warning for unreachable function" do 937 refute capture_err(fn -> 938 Code.eval_string(""" 939 defmodule Sample do 940 @compile {:inline, foo: 1} 941 942 defp foo(_), do: :ok 943 end 944 """) 945 end) =~ "inlined function foo/1 undefined" 946 after 947 purge(Sample) 948 end 949 950 test "in guard empty list" do 951 assert capture_err(fn -> 952 Code.eval_string(""" 953 defmodule Sample do 954 def a(x) when x in [], do: x 955 end 956 """) 957 end) =~ "this check/guard will always yield the same result" 958 after 959 purge(Sample) 960 end 961 962 test "no effect operator" do 963 assert capture_err(fn -> 964 Code.eval_string(""" 965 defmodule Sample do 966 def a(x) do 967 x != :foo 968 :ok 969 end 970 end 971 """) 972 end) =~ "use of operator != has no effect" 973 after 974 purge(Sample) 975 end 976 977 # TODO: Simplify when we require Erlang/OTP 24 978 if System.otp_release() >= "24" do 979 @argument_error_message "the call to :erlang.atom_to_binary/2" 980 @arithmetic_error_message "the call to +/2" 981 else 982 @argument_error_message "this expression" 983 @arithmetic_error_message "this expression" 984 end 985 986 test "eval failure warning" do 987 assert capture_err(fn -> 988 Code.eval_string(""" 989 defmodule Sample1 do 990 def foo, do: Atom.to_string "abc" 991 end 992 """) 993 end) =~ "#{@argument_error_message} will fail with ArgumentError\n nofile:2" 994 995 assert capture_err(fn -> 996 Code.eval_string(""" 997 defmodule Sample2 do 998 def foo, do: 1 + nil 999 end 1000 """) 1001 end) =~ "#{@arithmetic_error_message} will fail with ArithmeticError\n nofile:2" 1002 after 1003 purge([Sample1, Sample2]) 1004 end 1005 1006 test "undefined function for behaviour" do 1007 assert capture_err(fn -> 1008 Code.eval_string(""" 1009 defmodule Sample1 do 1010 @callback foo :: term 1011 end 1012 1013 defmodule Sample2 do 1014 @behaviour Sample1 1015 end 1016 """) 1017 end) =~ 1018 "function foo/0 required by behaviour Sample1 is not implemented (in module Sample2)" 1019 after 1020 purge([Sample1, Sample2]) 1021 end 1022 1023 test "undefined macro for behaviour" do 1024 assert capture_err(fn -> 1025 Code.eval_string(""" 1026 defmodule Sample1 do 1027 @macrocallback foo :: Macro.t 1028 end 1029 1030 defmodule Sample2 do 1031 @behaviour Sample1 1032 end 1033 """) 1034 end) =~ 1035 "macro foo/0 required by behaviour Sample1 is not implemented (in module Sample2)" 1036 after 1037 purge([Sample1, Sample2]) 1038 end 1039 1040 test "wrong kind for behaviour" do 1041 assert capture_err(fn -> 1042 Code.eval_string(""" 1043 defmodule Sample1 do 1044 @callback foo :: term 1045 end 1046 1047 defmodule Sample2 do 1048 @behaviour Sample1 1049 defmacro foo, do: :ok 1050 end 1051 """) 1052 end) =~ 1053 "function foo/0 required by behaviour Sample1 was implemented as \"defmacro\" but should have been \"def\"" 1054 after 1055 purge([Sample1, Sample2]) 1056 end 1057 1058 test "conflicting behaviour" do 1059 assert capture_err(fn -> 1060 Code.eval_string(""" 1061 defmodule Sample1 do 1062 @callback foo :: term 1063 end 1064 1065 defmodule Sample2 do 1066 @callback foo :: term 1067 end 1068 1069 defmodule Sample3 do 1070 @behaviour Sample1 1071 @behaviour Sample2 1072 end 1073 """) 1074 end) =~ 1075 "conflicting behaviours found. function foo/0 is required by Sample1 and Sample2 (in module Sample3)" 1076 after 1077 purge([Sample1, Sample2, Sample3]) 1078 end 1079 1080 test "duplicate behaviour" do 1081 assert capture_err(fn -> 1082 Code.eval_string(""" 1083 defmodule Sample1 do 1084 @callback foo :: term 1085 end 1086 1087 defmodule Sample2 do 1088 @behaviour Sample1 1089 @behaviour Sample1 1090 end 1091 """) 1092 end) =~ 1093 "the behavior Sample1 has been declared twice (conflict in function foo/0 in module Sample2)" 1094 after 1095 purge([Sample1, Sample2]) 1096 end 1097 1098 test "undefined behaviour" do 1099 assert capture_err(fn -> 1100 Code.eval_string(""" 1101 defmodule Sample do 1102 @behaviour UndefinedBehaviour 1103 end 1104 """) 1105 end) =~ "@behaviour UndefinedBehaviour does not exist (in module Sample)" 1106 after 1107 purge(Sample) 1108 end 1109 1110 test "empty behaviours" do 1111 assert capture_err(fn -> 1112 Code.eval_string(""" 1113 defmodule EmptyBehaviour do 1114 end 1115 defmodule Sample do 1116 @behaviour EmptyBehaviour 1117 end 1118 """) 1119 end) =~ "module EmptyBehaviour is not a behaviour (in module Sample)" 1120 after 1121 purge(Sample) 1122 purge(EmptyBehaviour) 1123 end 1124 1125 test "undefined behavior" do 1126 assert capture_err(fn -> 1127 Code.eval_string(""" 1128 defmodule Sample do 1129 @behavior Hello 1130 end 1131 """) 1132 end) =~ "@behavior attribute is not supported, please use @behaviour instead" 1133 after 1134 purge(Sample) 1135 end 1136 1137 test "undefined function for protocol" do 1138 assert capture_err(fn -> 1139 Code.eval_string(""" 1140 defprotocol Sample1 do 1141 def foo(subject) 1142 end 1143 1144 defimpl Sample1, for: Atom do 1145 end 1146 """) 1147 end) =~ 1148 "function foo/1 required by protocol Sample1 is not implemented (in module Sample1.Atom)" 1149 after 1150 purge([Sample1, Sample1.Atom]) 1151 end 1152 1153 test "warn when callbacks and friends are defined inside a protocol" do 1154 message = 1155 capture_err(fn -> 1156 Code.eval_string(~S""" 1157 defprotocol SampleWithCallbacks do 1158 @spec with_specs(any(), keyword()) :: tuple() 1159 def with_specs(term, options \\ []) 1160 1161 @spec with_specs_and_when(any(), opts) :: tuple() when opts: keyword 1162 def with_specs_and_when(term, options \\ []) 1163 1164 def without_specs(term, options \\ []) 1165 1166 @callback foo(term) :: {:ok, term} 1167 @callback foo(term, keyword) :: {:ok, term, keyword} 1168 1169 @callback foo_when(x) :: {:ok, x} when x: term 1170 @callback foo_when(x, opts) :: {:ok, x, opts} when x: term, opts: keyword 1171 1172 @macrocallback bar(term) :: {:ok, term} 1173 @macrocallback bar(term, keyword) :: {:ok, term, keyword} 1174 1175 @optional_callbacks [foo: 1, foo: 2] 1176 @optional_callbacks [without_specs: 2] 1177 end 1178 """) 1179 end) 1180 1181 assert message =~ 1182 "cannot define @callback foo/1 inside protocol, use def/1 to outline your protocol definition\n nofile:1" 1183 1184 assert message =~ 1185 "cannot define @callback foo/2 inside protocol, use def/1 to outline your protocol definition\n nofile:1" 1186 1187 assert message =~ 1188 "cannot define @callback foo_when/1 inside protocol, use def/1 to outline your protocol definition\n nofile:1" 1189 1190 assert message =~ 1191 "cannot define @callback foo_when/2 inside protocol, use def/1 to outline your protocol definition\n nofile:1" 1192 1193 assert message =~ 1194 "cannot define @macrocallback bar/1 inside protocol, use def/1 to outline your protocol definition\n nofile:1" 1195 1196 assert message =~ 1197 "cannot define @macrocallback bar/2 inside protocol, use def/1 to outline your protocol definition\n nofile:1" 1198 1199 assert message =~ 1200 "cannot define @optional_callbacks inside protocol, all of the protocol definitions are required\n nofile:1" 1201 after 1202 purge([SampleWithCallbacks]) 1203 end 1204 1205 test "overridden def name" do 1206 assert capture_err(fn -> 1207 Code.eval_string(""" 1208 defmodule Sample do 1209 def foo(x, 1), do: x + 1 1210 def foo(), do: nil 1211 def foo(x, 2), do: x * 2 1212 end 1213 """) 1214 end) =~ 1215 "clauses with the same name should be grouped together, \"def foo/2\" was previously defined (nofile:2)" 1216 after 1217 purge(Sample) 1218 end 1219 1220 test "overridden def name and arity" do 1221 assert capture_err(fn -> 1222 Code.eval_string(""" 1223 defmodule Sample do 1224 def foo(x, 1), do: x + 1 1225 def bar(), do: nil 1226 def foo(x, 2), do: x * 2 1227 end 1228 """) 1229 end) =~ 1230 "clauses with the same name and arity (number of arguments) should be grouped together, \"def foo/2\" was previously defined (nofile:2)" 1231 after 1232 purge(Sample) 1233 end 1234 1235 test "warning with overridden file" do 1236 output = 1237 capture_err(fn -> 1238 Code.eval_string(""" 1239 defmodule Sample do 1240 @file "sample" 1241 def foo(x), do: :ok 1242 end 1243 """) 1244 end) 1245 1246 assert output =~ "variable \"x\" is unused" 1247 assert output =~ "sample:3" 1248 after 1249 purge(Sample) 1250 end 1251 1252 test "warning on unnecessary code point escape" do 1253 assert capture_err(fn -> 1254 Code.eval_string("?\\n + ?\\\\") 1255 end) == "" 1256 1257 assert capture_err(fn -> 1258 Code.eval_string("?\\w") 1259 end) =~ "unknown escape sequence ?\\w, use ?w instead" 1260 end 1261 1262 test "warning on code point escape" do 1263 assert capture_err(fn -> 1264 Code.eval_string("? ") 1265 end) =~ "found ? followed by code point 0x20 (space), please use ?\\s instead" 1266 1267 assert capture_err(fn -> 1268 Code.eval_string("?\\ ") 1269 end) =~ "found ?\\ followed by code point 0x20 (space), please use ?\\s instead" 1270 end 1271 1272 test "duplicated docs in the same clause" do 1273 output = 1274 capture_err(fn -> 1275 Code.eval_string(""" 1276 defmodule Sample do 1277 @doc "Something" 1278 @doc "Another" 1279 def foo, do: :ok 1280 1281 Module.eval_quoted(__MODULE__, quote(do: @doc false)) 1282 @doc "Doc" 1283 def bar, do: :ok 1284 end 1285 """) 1286 end) 1287 1288 assert output =~ "redefining @doc attribute previously set at line 2" 1289 assert output =~ "nofile:3: Sample (module)" 1290 refute output =~ "nofile:7" 1291 after 1292 purge(Sample) 1293 end 1294 1295 test "duplicate docs across clauses" do 1296 assert capture_err(fn -> 1297 Code.eval_string(""" 1298 defmodule Sample1 do 1299 defmacro __using__(_) do 1300 quote do 1301 @doc "hello" 1302 def add(a, 1), do: a + 1 1303 end 1304 end 1305 end 1306 1307 defmodule Sample2 do 1308 use Sample1 1309 @doc "world" 1310 def add(a, 2), do: a + 2 1311 end 1312 """) 1313 end) == "" 1314 1315 assert capture_err(fn -> 1316 Code.eval_string(""" 1317 defmodule Sample3 do 1318 @doc "hello" 1319 def add(a, 1), do: a + 1 1320 @doc "world" 1321 def add(a, b) 1322 end 1323 """) 1324 end) =~ "" 1325 1326 assert capture_err(fn -> 1327 Code.eval_string(""" 1328 defmodule Sample4 do 1329 @doc "hello" 1330 def add(a, 1), do: a + 1 1331 @doc "world" 1332 def add(a, 2), do: a + 2 1333 end 1334 """) 1335 end) =~ "redefining @doc attribute previously set at line " 1336 after 1337 purge([Sample1, Sample2, Sample3, Sample4]) 1338 end 1339 1340 test "reserved doc metadata keys" do 1341 output = 1342 capture_err(fn -> 1343 Code.eval_string(""" 1344 defmodule Sample do 1345 @typedoc opaque: false 1346 @type t :: binary 1347 1348 @doc defaults: 3, since: "1.2.3" 1349 def foo(a), do: a 1350 end 1351 """) 1352 end) 1353 1354 assert output =~ "ignoring reserved documentation metadata key: :opaque" 1355 assert output =~ "ignoring reserved documentation metadata key: :defaults" 1356 refute output =~ ":since" 1357 after 1358 purge(Sample) 1359 end 1360 1361 describe "typespecs" do 1362 test "unused types" do 1363 output = 1364 capture_err(fn -> 1365 Code.eval_string(""" 1366 defmodule Sample do 1367 @type pub :: any 1368 @opaque op :: any 1369 @typep priv :: any 1370 @typep priv_args(var1, var2) :: {var1, var2} 1371 @typep priv2 :: any 1372 @typep priv3 :: priv2 | atom 1373 1374 @spec my_fun(priv3) :: pub 1375 def my_fun(var), do: var 1376 end 1377 """) 1378 end) 1379 1380 assert output =~ "nofile:4" 1381 assert output =~ "type priv/0 is unused" 1382 assert output =~ "nofile:5" 1383 assert output =~ "type priv_args/2 is unused" 1384 refute output =~ "type pub/0 is unused" 1385 refute output =~ "type op/0 is unused" 1386 refute output =~ "type priv2/0 is unused" 1387 refute output =~ "type priv3/0 is unused" 1388 after 1389 purge(Sample) 1390 end 1391 1392 test "underspecified opaque types" do 1393 output = 1394 capture_err(fn -> 1395 Code.eval_string(""" 1396 defmodule Sample do 1397 @opaque op1 :: term 1398 @opaque op2 :: any 1399 @opaque op3 :: atom 1400 end 1401 """) 1402 end) 1403 1404 assert output =~ "nofile:2" 1405 assert output =~ "@opaque type op1/0 is underspecified and therefore meaningless" 1406 assert output =~ "nofile:3" 1407 assert output =~ "@opaque type op2/0 is underspecified and therefore meaningless" 1408 refute output =~ "nofile:4" 1409 refute output =~ "op3" 1410 after 1411 purge(Sample) 1412 end 1413 1414 test "underscored types variables" do 1415 output = 1416 capture_err(fn -> 1417 Code.eval_string(""" 1418 defmodule Sample do 1419 @type in_typespec_vars(_var1, _var1) :: atom 1420 @type in_typespec(_var2) :: {atom, _var2} 1421 1422 @spec in_spec(_var3) :: {atom, _var3} when _var3: var 1423 def in_spec(a), do: {:ok, a} 1424 end 1425 """) 1426 end) 1427 1428 assert output =~ "nofile:2" 1429 assert output =~ ~r/the underscored type variable "_var1" is used more than once/ 1430 assert output =~ "nofile:3" 1431 assert output =~ ~r/the underscored type variable "_var2" is used more than once/ 1432 assert output =~ "nofile:5" 1433 assert output =~ ~r/the underscored type variable "_var3" is used more than once/ 1434 after 1435 purge(Sample) 1436 end 1437 1438 test "typedoc on typep" do 1439 assert capture_err(fn -> 1440 Code.eval_string(""" 1441 defmodule Sample do 1442 @typedoc "Something" 1443 @typep priv :: any 1444 @spec foo() :: priv 1445 def foo(), do: nil 1446 end 1447 """) 1448 end) =~ "type priv/0 is private, @typedoc's are always discarded for private types" 1449 after 1450 purge(Sample) 1451 end 1452 1453 test "discouraged types" do 1454 message = 1455 capture_err(fn -> 1456 Code.eval_string(""" 1457 defmodule Sample do 1458 @type foo :: string() 1459 @type bar :: nonempty_string() 1460 end 1461 """) 1462 end) 1463 1464 string_discouraged = 1465 "string() type use is discouraged. " <> 1466 "For character lists, use charlist() type, for strings, String.t()\n" 1467 1468 nonempty_string_discouraged = 1469 "nonempty_string() type use is discouraged. " <> 1470 "For non-empty character lists, use nonempty_charlist() type, for strings, String.t()\n" 1471 1472 assert message =~ string_discouraged 1473 assert message =~ nonempty_string_discouraged 1474 after 1475 purge(Sample) 1476 end 1477 1478 test "unreachable specs" do 1479 message = 1480 capture_err(fn -> 1481 Code.eval_string(""" 1482 defmodule Sample do 1483 defp my_fun(x), do: x 1484 @spec my_fun(integer) :: integer 1485 end 1486 """) 1487 end) 1488 1489 assert message != "" 1490 after 1491 purge(Sample) 1492 end 1493 1494 test "nested type annotations" do 1495 message = "invalid type annotation. Type annotations cannot be nested" 1496 1497 assert capture_err(fn -> 1498 Code.eval_string(""" 1499 defmodule Sample do 1500 @type my_type :: ann_type :: nested_ann_type :: atom 1501 end 1502 """) 1503 end) =~ message 1504 1505 purge(Sample) 1506 1507 assert capture_err(fn -> 1508 Code.eval_string(""" 1509 defmodule Sample do 1510 @type my_type :: ann_type :: nested_ann_type :: atom | port 1511 end 1512 """) 1513 end) =~ message 1514 1515 purge(Sample) 1516 1517 assert capture_err(fn -> 1518 Code.eval_string(""" 1519 defmodule Sample do 1520 @spec foo :: {pid, ann_type :: nested_ann_type :: atom} 1521 def foo, do: nil 1522 end 1523 """) 1524 end) =~ message 1525 after 1526 purge(Sample) 1527 end 1528 1529 test "invalid type annotations" do 1530 message = 1531 "invalid type annotation. When using the | operator to represent the union of types, " <> 1532 "make sure to wrap type annotations in parentheses" 1533 1534 assert capture_err(fn -> 1535 Code.eval_string(""" 1536 defmodule Sample do 1537 @type my_type :: pid | ann_type :: atom 1538 end 1539 """) 1540 end) =~ message 1541 1542 purge(Sample) 1543 1544 assert capture_err(fn -> 1545 Code.eval_string(""" 1546 defmodule Sample do 1547 @type my_type :: pid | ann_type :: atom | port 1548 end 1549 """) 1550 end) =~ message 1551 1552 purge(Sample) 1553 1554 assert capture_err(fn -> 1555 Code.eval_string(""" 1556 defmodule Sample do 1557 @type my_type :: {port, pid | ann_type :: atom | port} 1558 end 1559 """) 1560 end) =~ message 1561 after 1562 purge(Sample) 1563 end 1564 end 1565 1566 test "attribute with no use" do 1567 content = 1568 capture_err(fn -> 1569 Code.eval_string(""" 1570 defmodule Sample do 1571 @at "Something" 1572 end 1573 """) 1574 end) 1575 1576 assert content =~ "module attribute @at was set but never used" 1577 assert content =~ "nofile:2" 1578 after 1579 purge(Sample) 1580 end 1581 1582 test "registered attribute with no use" do 1583 content = 1584 capture_err(fn -> 1585 Code.eval_string(""" 1586 defmodule Sample do 1587 Module.register_attribute(__MODULE__, :at, []) 1588 @at "Something" 1589 end 1590 """) 1591 end) 1592 1593 assert content =~ "module attribute @at was set but never used" 1594 assert content =~ "nofile:3" 1595 after 1596 purge(Sample) 1597 end 1598 1599 test "typedoc with no type" do 1600 assert capture_err(fn -> 1601 Code.eval_string(""" 1602 defmodule Sample do 1603 @typedoc "Something" 1604 end 1605 """) 1606 end) =~ "module attribute @typedoc was set but no type follows it" 1607 after 1608 purge(Sample) 1609 end 1610 1611 test "doc with no function" do 1612 assert capture_err(fn -> 1613 Code.eval_string(""" 1614 defmodule Sample do 1615 @doc "Something" 1616 end 1617 """) 1618 end) =~ "module attribute @doc was set but no definition follows it" 1619 after 1620 purge(Sample) 1621 end 1622 1623 test "pipe without explicit parentheses" do 1624 assert capture_err(fn -> 1625 Code.eval_string(""" 1626 [5, 6, 7, 3] 1627 |> Enum.map_join "", &(Integer.to_string(&1)) 1628 |> String.to_integer 1629 """) 1630 end) =~ "parentheses are required when piping into a function call" 1631 end 1632 1633 test "variable is being expanded to function call" do 1634 output = 1635 capture_err(fn -> 1636 Code.eval_string(""" 1637 self 1638 defmodule Sample do 1639 def my_node(), do: node 1640 end 1641 """) 1642 end) 1643 1644 assert output =~ "variable \"self\" does not exist and is being expanded to \"self()\"" 1645 assert output =~ "variable \"node\" does not exist and is being expanded to \"node()\"" 1646 after 1647 purge(Sample) 1648 end 1649 1650 defmodule User do 1651 defstruct [:name] 1652 end 1653 1654 test ":__struct__ is ignored when using structs" do 1655 assert capture_err(fn -> 1656 code = """ 1657 assert %Kernel.WarningTest.User{__struct__: Ignored, name: "joe"} == 1658 %Kernel.WarningTest.User{name: "joe"} 1659 """ 1660 1661 Code.eval_string(code, [], __ENV__) 1662 end) =~ "key :__struct__ is ignored when using structs" 1663 1664 assert capture_err(fn -> 1665 code = """ 1666 user = %Kernel.WarningTest.User{name: "meg"} 1667 assert %Kernel.WarningTest.User{user | __struct__: Ignored, name: "joe"} == 1668 %Kernel.WarningTest.User{__struct__: Kernel.WarningTest.User, name: "joe"} 1669 """ 1670 1671 Code.eval_string(code, [], __ENV__) 1672 end) =~ "key :__struct__ is ignored when using structs" 1673 end 1674 1675 test "catch comes before rescue in try block" do 1676 output = 1677 capture_err(fn -> 1678 Code.eval_string(""" 1679 try do 1680 :trying 1681 catch 1682 _ -> :caught 1683 rescue 1684 _ -> :error 1685 end 1686 """) 1687 end) 1688 1689 assert output =~ ~s("catch" should always come after "rescue" in try) 1690 end 1691 1692 test "catch comes before rescue in def" do 1693 output = 1694 capture_err(fn -> 1695 Code.eval_string(""" 1696 defmodule Sample do 1697 def foo do 1698 :trying 1699 catch 1700 _, _ -> :caught 1701 rescue 1702 _ -> :error 1703 end 1704 end 1705 """) 1706 end) 1707 1708 assert output =~ ~s("catch" should always come after "rescue" in def) 1709 after 1710 purge(Sample) 1711 end 1712 1713 test "unused variable in defguard" do 1714 assert capture_err(fn -> 1715 Code.eval_string(""" 1716 defmodule Sample do 1717 defguard foo(bar, baz) when bar 1718 end 1719 """) 1720 end) =~ "variable \"baz\" is unused" 1721 after 1722 purge(Sample) 1723 end 1724 1725 test "unused import in defguard" do 1726 assert capture_err(fn -> 1727 Code.compile_string(""" 1728 defmodule Sample do 1729 import Record 1730 defguard is_record(baz) when baz 1731 end 1732 """) 1733 end) =~ "unused import Record\n" 1734 after 1735 purge(Sample) 1736 end 1737 1738 test "unused private guard" do 1739 assert capture_err(fn -> 1740 Code.compile_string(""" 1741 defmodule Sample do 1742 defguardp foo(bar, baz) when bar + baz 1743 end 1744 """) 1745 end) =~ "macro foo/2 is unused\n" 1746 after 1747 purge(Sample) 1748 end 1749 1750 test "defguard overriding defmacro" do 1751 assert capture_err(fn -> 1752 Code.eval_string(""" 1753 defmodule Sample do 1754 defmacro foo(bar), do: bar == :bar 1755 defguard foo(baz) when baz == :baz 1756 end 1757 """) 1758 end) =~ 1759 ~r"this clause( for foo/1)? cannot match because a previous clause at line 2 always matches" 1760 after 1761 purge(Sample) 1762 end 1763 1764 test "defmacro overriding defguard" do 1765 assert capture_err(fn -> 1766 Code.eval_string(""" 1767 defmodule Sample do 1768 defguard foo(baz) when baz == :baz 1769 defmacro foo(bar), do: bar == :bar 1770 end 1771 """) 1772 end) =~ 1773 ~r"this clause( for foo/1)? cannot match because a previous clause at line 2 always matches" 1774 after 1775 purge(Sample) 1776 end 1777 1778 test "struct comparisons" do 1779 expressions = [ 1780 ~s(~N"2018-01-28 12:00:00"), 1781 ~s(~T"12:00:00"), 1782 ~s(~D"2018-01-28"), 1783 "%File.Stat{}" 1784 ] 1785 1786 for op <- [:<, :>, :<=, :>=], 1787 expression <- expressions do 1788 assert capture_err(fn -> 1789 Code.eval_string("x #{op} #{expression}", x: 1) 1790 end) =~ "invalid comparison with struct literal #{expression}" 1791 1792 assert capture_err(fn -> 1793 Code.eval_string("#{expression} #{op} x", x: 1) 1794 end) =~ "invalid comparison with struct literal #{expression}" 1795 end 1796 end 1797 1798 test "deprecated GenServer super on callbacks" do 1799 assert capture_err(fn -> 1800 Code.eval_string(""" 1801 defmodule Sample do 1802 use GenServer 1803 1804 def handle_call(a, b, c) do 1805 super(a, b, c) 1806 end 1807 end 1808 """) 1809 end) =~ "calling super for GenServer callback handle_call/3 is deprecated" 1810 after 1811 purge(Sample) 1812 end 1813 1814 test "super is allowed on GenServer.child_spec/1" do 1815 refute capture_err(fn -> 1816 Code.eval_string(""" 1817 defmodule Sample do 1818 use GenServer 1819 1820 def child_spec(opts) do 1821 super(opts) 1822 end 1823 end 1824 """) 1825 end) =~ "calling super for GenServer callback child_spec/1 is deprecated" 1826 after 1827 purge(Sample) 1828 end 1829 1830 test "nested comparison operators" do 1831 message = 1832 capture_err(fn -> 1833 Code.compile_string(""" 1834 1 < 3 < 5 1835 """) 1836 end) 1837 1838 assert message =~ "Elixir does not support nested comparisons" 1839 assert message =~ "1 < 3 < 5" 1840 1841 message = 1842 capture_err(fn -> 1843 Code.compile_string(""" 1844 x = 5 1845 y = 7 1846 1 < x < y < 10 1847 """) 1848 end) 1849 1850 assert message =~ "Elixir does not support nested comparisons" 1851 assert message =~ "1 < x < y < 10" 1852 end 1853 1854 test "def warns if only clause is else" do 1855 message = 1856 capture_err(fn -> 1857 Code.compile_string(""" 1858 defmodule Sample do 1859 def foo do 1860 :bar 1861 else 1862 _other -> :ok 1863 end 1864 end 1865 """) 1866 end) 1867 1868 assert message =~ "\"else\" shouldn't be used as the only clause in \"def\"" 1869 after 1870 purge(Sample) 1871 end 1872 1873 test "try warns if only clause is else" do 1874 message = 1875 capture_err(fn -> 1876 Code.compile_string(""" 1877 try do 1878 :ok 1879 else 1880 other -> other 1881 end 1882 """) 1883 end) 1884 1885 assert message =~ "\"else\" shouldn't be used as the only clause in \"try\"" 1886 end 1887 1888 test "sigil w/W warns on trailing comma at macro expansion time" do 1889 for sigil <- ~w(w W), 1890 modifier <- ~w(a s c) do 1891 output = 1892 capture_err(fn -> 1893 {:ok, ast} = 1894 "~#{sigil}(foo, bar baz)#{modifier}" 1895 |> Code.string_to_quoted() 1896 1897 Macro.expand(ast, __ENV__) 1898 end) 1899 1900 assert output =~ "the sigils ~w/~W do not allow trailing commas" 1901 end 1902 end 1903 1904 test "warnings on trailing comma on call" do 1905 assert capture_err(fn -> Code.eval_string("Keyword.merge([], foo: 1,)") end) =~ 1906 "trailing commas are not allowed inside function/macro call arguments" 1907 end 1908 1909 test "defstruct warns with duplicate keys" do 1910 assert capture_err(fn -> 1911 Code.eval_string(""" 1912 defmodule TestMod do 1913 defstruct [:foo, :bar, foo: 1] 1914 end 1915 """) 1916 end) =~ "duplicate key :foo found in struct" 1917 after 1918 purge(TestMod) 1919 end 1920 1921 test "deprecate nullary remote zero-arity capture with parens" do 1922 assert capture_err(fn -> 1923 Code.eval_string(""" 1924 import System, only: [pid: 0] 1925 &pid/0 1926 """) 1927 end) == "" 1928 1929 assert capture_err(fn -> 1930 Code.eval_string(""" 1931 &System.pid()/0 1932 """) 1933 end) =~ 1934 "extra parentheses on a remote function capture &System.pid()/0 have been deprecated. Please remove the parentheses: &System.pid/0" 1935 end 1936 1937 defp purge(list) when is_list(list) do 1938 Enum.each(list, &purge/1) 1939 end 1940 1941 defp purge(module) when is_atom(module) do 1942 :code.delete(module) 1943 :code.purge(module) 1944 end 1945end 1946