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