aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/test/erl_lint_SUITE.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/stdlib/test/erl_lint_SUITE.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/stdlib/test/erl_lint_SUITE.erl')
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl2783
1 files changed, 2783 insertions, 0 deletions
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
new file mode 100644
index 0000000000..bfbd7b3dc1
--- /dev/null
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -0,0 +1,2783 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(erl_lint_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(datadir, "erl_lint_SUITE_data").
+-define(privdir, "erl_lint_SUITE_priv").
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(datadir, ?config(data_dir, Conf)).
+-define(privdir, ?config(priv_dir, Conf)).
+-endif.
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+
+-export([unused_vars_warn/1,
+ unused_vars_warn_basic/1,
+ unused_vars_warn_lc/1,
+ unused_vars_warn_rec/1,
+ unused_vars_warn_fun/1,
+ unused_vars_OTP_4858/1,
+ export_vars_warn/1,
+ shadow_vars/1,
+ unused_import/1,
+ unused_function/1,
+ unsafe_vars/1,unsafe_vars2/1,
+ unsafe_vars_try/1,
+ guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
+ otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
+ otp_5917/1, otp_6585/1, otp_6885/1, export_all/1,
+ bif_clash/1,
+ behaviour_basic/1, behaviour_multiple/1,
+ otp_7550/1,
+ otp_8051/1,
+ format_warn/1,
+ on_load/1, on_load_successful/1, on_load_failing/1
+ ]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, _Config) ->
+ Dog = ?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [unused_vars_warn, export_vars_warn,
+ shadow_vars, unused_import, unused_function,
+ unsafe_vars, unsafe_vars2, unsafe_vars_try,
+ guard, otp_4886, otp_4988, otp_5091, otp_5276, otp_5338,
+ otp_5362, otp_5371, otp_7227, otp_5494, otp_5644, otp_5878, otp_5917, otp_6585,
+ otp_6885, export_all, bif_clash,
+ behaviour_basic, behaviour_multiple, otp_7550, otp_8051, format_warn,
+ on_load].
+
+unused_vars_warn(suite) ->
+ [unused_vars_warn_basic, unused_vars_warn_lc, unused_vars_warn_rec,
+ unused_vars_warn_fun, unused_vars_OTP_4858].
+
+unused_vars_warn_basic(doc) ->
+ "Warnings for unused variables in some simple cases.";
+unused_vars_warn_basic(suite) -> [];
+unused_vars_warn_basic(Config) when is_list(Config) ->
+ Ts = [{basic1,
+ <<"f(F) -> % F unused.
+ ok.
+
+ f(F, F) ->
+ ok.
+
+ g(_X) ->
+ y.
+
+ h(P) ->
+ P.
+
+ x(N) ->
+ case a:b() of
+ [N|Y] -> % Y unused.
+ ok
+ end.
+
+ y(N, L) ->
+ lists:map(fun(T) -> T*N end, L).
+
+ z(N, L) -> % N unused
+ lists:map(fun(N, T) -> T*N end, L). % N shadowed.
+
+
+ c(A) ->
+ case A of
+ 1 -> B = []; % B unused.
+ 2 -> B = []; % B unused.
+ 3 -> B = f, B
+ end.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{1,erl_lint,{unused_var,'F'}},
+ {15,erl_lint,{unused_var,'Y'}},
+ {22,erl_lint,{unused_var,'N'}},
+ {23,erl_lint,{shadowed_var,'N','fun'}},
+ {28,erl_lint,{unused_var,'B'}},
+ {29,erl_lint,{unused_var,'B'}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_vars_warn_lc(doc) ->
+ "Warnings for unused variables in list comprehensions.";
+unused_vars_warn_lc(suite) -> [];
+unused_vars_warn_lc(Config) when is_list(Config) ->
+ Ts = [{lc1,
+ <<"bin([X]) ->
+ [A || <<A:X>> <- []]; % X used, not shadowed.
+ bin({X}) ->
+ [X || <<X:X>> <- []]; % X used, and shadowed.
+ bin({X,Y,Z}) ->
+ [{A,B} || <<A:X>> <- Z, <<B:Y>> <- Z];
+ bin([X,Y,Z]) -> % Y unused.
+ [C || <<V:X>> <- Z, <<B:V>> <- Z, <<C:B>> <- Z].
+ ">>,
+ [warn_unused_vars],
+ {warnings, [{4,erl_lint,{shadowed_var,'X',generate}},
+ {7,erl_lint,{unused_var,'Y'}}]}},
+
+ {lc2,
+ <<"bin([X]) ->
+ [A || <<A:X>> <- []]; % X used, not shadowed.
+ bin({X}) ->
+ [X || <<X:X>> <- []]; % X used, and shadowed.
+ bin({X,Y,Z}) ->
+ [{A,B} || <<A:X>> <- Z, <<B:Y>> <- Z];
+ bin([X,Y,Z]) -> % Y unused.
+ [C || <<V:X>> <- Z, <<B:V>> <- Z, <<C:B>> <- Z].
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{4,erl_lint,{shadowed_var,'X',generate}},
+ {7,erl_lint,{unused_var,'Y'}}]}},
+
+ {lc3,
+ <<"a([A]) ->
+ B = foo,
+ [{C,B} || {C,_} <- A];
+ a({A}) ->
+ B = foo,
+ [C || {C,_} <- [B,A]];
+ a({A,A}) ->
+ B = foo,
+ [C || {C,_} <- B, B < A].
+ ">>,
+ [warn_unused_vars],
+ []},
+
+ {lc4,
+ <<"b(A) ->
+ B = foo, % B unused.
+ [C || {C,_} <- A].
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'B'}}]}},
+
+ {lc5,
+ <<"c(A) ->
+ B = foo,
+ [C || {C,_} <- A],
+ B.
+ ">>,
+ [warn_unused_vars],
+ []},
+
+ {lc6,
+ <<"d(A) ->
+ B = foo,
+ [{A,B} || {Id,_} <- A]. % Id unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{unused_var,'Id'}}]}},
+
+ {lc7,
+ <<"e(A) ->
+ B = foo, % B unused.
+ [B || B <- A]. % B shadowed.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc8,
+ <<"f(A) ->
+ B = foo,
+ [B || B <- A], % B shadowed.
+ B.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc9,
+ <<"g(A) ->
+ B = foo, % B unused.
+ [A || B <- A]. % B shadowed, B unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc10,
+ <<"h(A) ->
+ B = foo,
+ [A || B <- A], % B shadowed, B unused.
+ B.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc11,
+ <<"i(X) ->
+ [Z || Z <- X, % Z unused.
+ Z = X <- [foo]]. % X and Z shadowed. X unused!
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'Z'}},
+ {3,erl_lint,{unused_var,'X'}},
+ {3,erl_lint,{shadowed_var,'X',generate}},
+ {3,erl_lint,{shadowed_var,'Z',generate}}]}},
+
+ {lc12,
+ <<"j({X}) ->
+ [Z || Z <- X, % Z unused.
+ Z <- X = [[1,2,3]], % Z shadowed. Z unused.
+ Z <- X, % Z shadowed. Z unused.
+ Z <- X]; % Z shadowed.
+ j(X) ->
+ [foo || X <- X, % X shadowed.
+ X <- % X shadowed. X unused.
+ X =
+ Y = [[1,2,3]], % Y unused.
+ X <- [], % X shadowed.
+ X <- X]. % X shadowed. X unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'Z'}},
+ {3,erl_lint,{unused_var,'Z'}},
+ {3,erl_lint,{shadowed_var,'Z',generate}},
+ {4,erl_lint,{unused_var,'Z'}},
+ {4,erl_lint,{shadowed_var,'Z',generate}},
+ {5,erl_lint,{shadowed_var,'Z',generate}},
+ {7,erl_lint,{shadowed_var,'X',generate}},
+ {8,erl_lint,{unused_var,'X'}},
+ {8,erl_lint,{shadowed_var,'X',generate}},
+ {10,erl_lint,{unused_var,'Y'}},
+ {11,erl_lint,{shadowed_var,'X',generate}},
+ {12,erl_lint,{unused_var,'X'}},
+ {12,erl_lint,{shadowed_var,'X',generate}}]}},
+
+ {lc13,
+ <<"k(X) ->
+ [Z || Z <- Y = X]; % Y unused.
+ k(X) ->
+ [Z || Z <- X = Y = X]; % Y unused!
+ k(X) ->
+ [Z || Z <- begin X = Y = X, Y end];
+ k(X) ->
+ [{Y,W} || W <- Y = X]; % Y unbound
+ k(X) ->
+ [Z || Z <- (Y = X), % Y unused.
+ Y > X]; % Y unbound.
+ k(X) ->
+ [Y || Y = X > 3, Z = X]; % Z unused.
+ k(X) ->
+ [Z || Y = X > 3, Z = X]. % Y unused.
+ ">>,
+ [warn_unused_vars],
+ {error,[{8,erl_lint,{unbound_var,'Y'}},
+ {11,erl_lint,{unbound_var,'Y'}}],
+ [{2,erl_lint,{unused_var,'Y'}},
+ {4,erl_lint,{unused_var,'Y'}},
+ {8,erl_lint,{unused_var,'Y'}},
+ {10,erl_lint,{unused_var,'Y'}},
+ {13,erl_lint,{unused_var,'Z'}},
+ {15,erl_lint,{unused_var,'Y'}}]}},
+
+ {lc14,
+ <<"lc2() ->
+ Z = [[1],[2],[3]],
+ [X || Z <- Z, % Z shadowed.
+ X <- Z].
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{shadowed_var,'Z',generate}}]}},
+
+ {lc15,
+ <<"lc3() ->
+ Z = [1,2,3],
+ [X || X <- Z,
+ Z <- Z]. % Z shadowed. Z unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{4,erl_lint,{unused_var,'Z'}},
+ {4,erl_lint,{shadowed_var,'Z',generate}}]}},
+
+ {lc16,
+ <<"bin(Z) ->
+ case bar of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ case bar of
+ true ->
+ X = 2;
+ false ->
+ X = 3
+ end,
+ case foo of
+ true ->
+ Y = 3; % Y unused.
+ false ->
+ 4
+ end,
+ case foo of
+ 1 ->
+ U; % U unsafe.
+ 2 ->
+ [Z || <<U:X>> <- Z]; % (X exported.) U unused.
+ 3 ->
+ [Z || <<U:X>> <- Z], % (X exported.) U unused.
+ U % U unsafe.
+ end.
+ ">>,
+ [warn_unused_vars],
+ {error,[{22,erl_lint,{unsafe_var,'U',{'case',2}}},
+ {27,erl_lint,{unsafe_var,'U',{'case',2}}}],
+ [{16,erl_lint,{unused_var,'Y'}},
+ % {24,erl_lint,{exported_var,'X',{'case',8}}},
+ {24,erl_lint,{unused_var,'U'}},
+ % {26,erl_lint,{exported_var,'X',{'case',8}}},
+ {26,erl_lint,{unused_var,'U'}}]}},
+
+ {lc17,
+ <<"bin(Z) ->
+ %% This used to pass erl_lint...
+ case bar of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ case bar of
+ true ->
+ X = 2;
+ false ->
+ X = 3
+ end,
+ case foo of
+ true ->
+ Y = 3; % Y unused.
+ false ->
+ 4
+ end,
+ [Z || <<U:X>> <- Z], % (X exported.) U unused.
+ U. % U unsafe.
+ ">>,
+ [warn_unused_vars],
+ {error,[{22,erl_lint,{unsafe_var,'U',{'case',3}}}],
+ [{17,erl_lint,{unused_var,'Y'}},
+ % {21,erl_lint,{exported_var,'X',{'case',9}}},
+ {21,erl_lint,{unused_var,'U'}}]}},
+
+ {lc18,
+ <<"bin(Z) ->
+ case bar of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ case bar of
+ true ->
+ X = 2;
+ false ->
+ X = 3
+ end,
+ case foo of
+ true ->
+ Y = 3;
+ false ->
+ 4
+ end,
+ [B || <<U: % U unused
+ U>> <- X, <<B:Y>> <- Z]. % U unsafe. Y unsafe.
+ % U shadowed. (X exported.)
+ ">>,
+ [warn_unused_vars],
+ {error,[{21,erl_lint,{unsafe_var,'U',{'case',2}}},
+ {21,erl_lint,{unsafe_var,'Y',{'case',14}}}],
+ [{20,erl_lint,{unused_var,'U'}}
+ % ,{21,erl_lint,{exported_var,'X',{'case',8}}}
+ % ,{21,erl_lint,{shadowed_var,'U',generate}}
+ ]}},
+
+ {lc19,
+ <<"p({B,C}) ->
+ <<A:B,A:C>> = <<17:32>>;
+ p(B) ->
+ <<A:B>> = <<17:32>>. % A unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{4,erl_lint,{unused_var,'A'}}]}},
+
+ {lc20,
+ <<"c({I1,I2}) ->
+ if
+ <<I1:I2>> == <<>> ->
+ foo
+ end;
+ c([C1,C2]) -> % C1 unused.
+ case foo of
+ <<C2:C2,
+ C3:C2>> -> % C3 unused.
+ bar
+ end.
+
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{6,erl_lint,{unused_var,'C1'}},
+ {7,sys_core_fold,no_clause_match},
+ {9,erl_lint,{unused_var,'C3'}}]}},
+
+ {lc21,
+ <<"t() ->
+ S = 8,
+ case <<3:8>> of
+ <<X:S>> ->
+ X;
+ <<S:X>> -> % X unbound
+ foo
+ end;
+ t() ->
+ S = 8,
+ case <<3:8>> of
+ <<S:S>> ->
+ S;
+ <<Q:32>> -> % Q unused.
+ foo
+ end.
+ ">>,
+ [warn_unused_vars],
+ {error,[{6,erl_lint,{unbound_var,'X'}}],
+ [{14,erl_lint,{unused_var,'Q'}}]}}
+
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+
+unused_vars_warn_rec(doc) ->
+ "Warnings for unused variables in records.";
+unused_vars_warn_rec(suite) -> [];
+unused_vars_warn_rec(Config) when is_list(Config) ->
+ Ts = [{rec1, % An example provided by Bjorn.
+ <<"-record(edge,
+ {ltpr,
+ ltsu,
+ rtpr,
+ rtsu
+ }).
+
+ f1(#edge{ltpr = A, ltsu = A}) ->
+ true;
+ f1({Q, Q}) ->
+ true.
+
+ f2(Edge, Etab) ->
+ case gb_trees:lookup(Edge, Etab) of
+ {value,#edge{ltpr=Same,ltsu=Same}} -> ok;
+ {value,_} -> error
+ end.
+
+ bar(Edge, Etab) ->
+ case gb_trees:lookup(Edge, Etab) of
+ {Same,Same} -> ok;
+ {value,#edge{ltpr=Same}} -> ok; % Same unused.
+ {value,_} -> error
+ end.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{22,erl_lint,{unused_var,'Same'}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_vars_warn_fun(doc) ->
+ "Warnings for unused variables in records.";
+unused_vars_warn_fun(suite) -> [];
+unused_vars_warn_fun(Config) when is_list(Config) ->
+ Ts = [{fun1,
+ <<"a({A,B}) -> % A unused.
+ fun(A) -> B end; % A shadowed. A unused.
+ a([A,B]) ->
+ fun(<<A:B>>, % A shadowed. A unused.
+ <<Q:A>>) -> foo % Q unused.
+ end;
+ a({A,B,C,D,E}) ->
+ fun(E) when C == <<A:A>>, <<17:B>> == D -> % E shadowed. E unused.
+ foo
+ end,
+ E;
+ a([A,B,C,D,E]) -> % E unused.
+ fun() ->
+ (C == <<A:A>>) and (<<17:B>> == D)
+ end.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{1,erl_lint,{unused_var,'A'}},
+ {2,erl_lint,{unused_var,'A'}},
+ {2,erl_lint,{shadowed_var,'A','fun'}},
+ {4,erl_lint,{unused_var,'A'}},
+ {4,erl_lint,{shadowed_var,'A','fun'}},
+ {5,erl_lint,{unused_var,'Q'}},
+ {8,erl_lint,{unused_var,'E'}},
+ {8,erl_lint,{shadowed_var,'E','fun'}},
+ {8,sys_core_fold,useless_building},
+ {12,erl_lint,{unused_var,'E'}}]}},
+
+ {fun2,
+ <<"u() ->
+ case foo of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ fun(U) -> foo end, % U unused.
+ U; % U unsafe.
+ u() ->
+ case foo of
+ true ->
+ U = 2;
+ false ->
+ U = 3
+ end,
+ fun(U) -> foo end, % U shadowed. U unused.
+ U;
+ u() ->
+ case foo of
+ true ->
+ U = 2; % U unused.
+ false ->
+ U = 3 % U unused.
+ end,
+ fun(U) -> foo end. % U shadowed. U unused.
+ ">>,
+ [warn_unused_vars],
+ {error,[{9,erl_lint,{unsafe_var,'U',{'case',2}}}],
+ [{8,erl_lint,{unused_var,'U'}},
+ {17,erl_lint,{unused_var,'U'}},
+ {17,erl_lint,{shadowed_var,'U','fun'}},
+ {22,erl_lint,{unused_var,'U'}},
+ {24,erl_lint,{unused_var,'U'}},
+ {26,erl_lint,{unused_var,'U'}},
+ {26,erl_lint,{shadowed_var,'U','fun'}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_vars_OTP_4858(doc) ->
+ "Bit syntax, binsize variable used in the same matching.";
+unused_vars_OTP_4858(suite) -> [];
+unused_vars_OTP_4858(Config) when is_list(Config) ->
+ Ts = [{otp_4858,
+ <<"objs(<<Size:4/unit:8, B:Size/binary>>) ->
+ B.
+
+ fel(<<Size:4/unit:8, B:BadSize/binary>>) -> % BadSize unbound.
+ BadSize. % B, Size unused.
+
+ r9c_highlight() -> % B, Rest unused.
+ <<Size, B:Size/binary,Rest/binary>> = <<2,\"AB\",3,\"CDE\">>.
+ ">>,
+ [warn_unused_vars],
+ {error,[{4,erl_lint,{unbound_var,'BadSize'}}],
+ [{4,erl_lint,{unused_var,'B'}},
+ {4,erl_lint,{unused_var,'Size'}},
+ {8,erl_lint,{unused_var,'B'}},
+ {8,erl_lint,{unused_var,'Rest'}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+export_vars_warn(doc) ->
+ "Warnings for exported variables";
+export_vars_warn(suite) -> [];
+export_vars_warn(Config) when is_list(Config) ->
+ Ts = [{exp1,
+ <<"u() ->
+ case foo of
+ 1 ->
+ A = 1,
+ B = 2,
+ W = 3, % W unused.
+ Z = 3; % Z unused.
+ 2 ->
+ B = 2,
+ Z = 4 % Z unused.
+ end,
+ case bar of
+ true ->
+ A = 17, % A unsafe.
+ X = 3, % X unused.
+ U = 2,
+ U;
+ false ->
+ B = 19, % B exported.
+ U = 3; % U unused.
+ foo ->
+ X = 3,
+ X;
+ bar ->
+ X = 9, % X unused.
+ U = 14 % U unused.
+ end.
+ ">>,
+ [warn_unused_vars],
+ {error,[{14,erl_lint,{unsafe_var,'A',{'case',2}}}],
+ [{6,erl_lint,{unused_var,'W'}},
+ {7,erl_lint,{unused_var,'Z'}},
+ {10,erl_lint,{unused_var,'Z'}},
+ {15,erl_lint,{unused_var,'X'}},
+ {19,erl_lint,{exported_var,'B',{'case',2}}},
+ {20,erl_lint,{unused_var,'U'}},
+ {25,erl_lint,{unused_var,'X'}},
+ {26,erl_lint,{unused_var,'U'}}]}},
+
+ {exp2,
+ <<"bin(A) ->
+ receive
+ M ->
+ X = M,
+ Y = M,
+ Z = M
+ end,
+ [B || <<B:X>> <- A], % X exported.
+ Y = B, % Y exported. B unbound.
+ [B || B <- Z]. % Z exported. B shadowed.
+ ">>,
+ [warn_export_vars],
+ {error,[{9,erl_lint,{unbound_var,'B'}}],
+ [{8,erl_lint,{exported_var,'X',{'receive',2}}},
+ {9,erl_lint,{exported_var,'Y',{'receive',2}}},
+ {10,erl_lint,{exported_var,'Z',{'receive',2}}},
+ {10,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {exp3,
+ <<"bin(A) ->
+ receive
+ M ->
+ X = M,
+ Y = M,
+ Z = M
+ end,
+ [B || <<B:X>> <- A], % (X exported.)
+ Y = B, % Y exported. B unbound.
+ [B || B <- Z]. % (Z exported.) B shadowed.
+ ">>,
+ [],
+ {error,[{9,erl_lint,{unbound_var,'B'}}],
+ [{9,erl_lint,{exported_var,'Y',{'receive',2}}},
+ {10,erl_lint,{shadowed_var,'B',generate}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+shadow_vars(doc) ->
+ "Shadowed variables are tested in other places, but here we test "
+ "that the warning can be turned off.";
+shadow_vars(suite) -> [];
+shadow_vars(Config) when is_list(Config) ->
+ Ts = [{shadow1,
+ <<"bin(A) ->
+ receive
+ M ->
+ X = M,
+ Y = M,
+ Z = M
+ end,
+ [B || <<B:X>> <- A],
+ Y = B,
+ [B || B <- Z]. % B shadowed.
+ ">>,
+ [nowarn_shadow_vars],
+ {error,[{9,erl_lint,{unbound_var,'B'}}],
+ [{9,erl_lint,{exported_var,'Y',{'receive',2}}}]}}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_import(doc) ->
+ "Test that the 'warn_unused_import' option works.";
+unused_import(suite) -> [];
+unused_import(Config) when is_list(Config) ->
+ Ts = [{imp1,
+ <<"-import(lists, [map/2,foldl/3]).
+ t(L) ->
+ map(fun(X) -> 2*X end, L).
+ ">>,
+ [warn_unused_import],
+ {warnings,[{1,erl_lint,{unused_import,{{foldl,3},lists}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_function(doc) ->
+ "Test warnings for unused functions.";
+unused_function(suite) -> [];
+unused_function(Config) when is_list(Config) ->
+ Ts = [{func1,
+ <<"-export([t/1]).
+ t(L) ->
+ lists:map(fun(X) -> 2*X end, L).
+
+ fact(N) ->
+ fact_1(N, 1).
+
+ fact_1(1, P) -> P;
+ fact_1(N, P) -> fact_1(N-1, P*N).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {warnings,[{5,erl_lint,{unused_function,{fact,1}}},
+ {8,erl_lint,{unused_function,{fact_1,2}}}]}},
+
+ %% Turn off warnings for unused functions.
+ {func2,
+ <<"-export([t/1]).
+ t(L) ->
+ lists:map(fun(X) -> 2*X end, L).
+
+ b(X) ->
+ 32*X.
+ ">>,
+ {[nowarn_unused_function]}, %Tuple indicates no 'export_all'.
+ []},
+
+ %% Turn off warnings for unused functions using a -compile() directive.
+ {func3,
+ <<"-export([t/1]).
+ -compile(nowarn_unused_function).
+
+ t(L) ->
+ lists:map(fun(X) -> 2*X end, L).
+
+ b(X) ->
+ 32*X.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+unsafe_vars(doc) ->
+ "OTP-4671. Errors for unsafe variables";
+unsafe_vars(suite) -> [];
+unsafe_vars(Config) when is_list(Config) ->
+ Ts = [{unsafe1,
+ <<"t() ->
+ (X = true) orelse (Y = false),
+ Y.
+ ">>,
+ [warn_unused_vars],
+ {error,[{3,erl_lint,{unsafe_var,'Y',{'orelse',2}}}],
+ [{2,erl_lint,{unused_var,'X'}}]}},
+ {unsafe2,
+ <<"t2() ->
+ (X = true) orelse (Y = false),
+ X.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'Y'}}]}},
+ {unsafe3,
+ <<"t3() ->
+ (X = true) andalso (Y = false),
+ Y.
+ ">>,
+ [warn_unused_vars],
+ {error,[{3,erl_lint,{unsafe_var,'Y',{'andalso',2}}}],
+ [{2,erl_lint,{unused_var,'X'}}]}},
+ {unsafe4,
+ <<"t4() ->
+ (X = true) andalso (true = X),
+ X.
+ ">>,
+ [warn_unused_vars],
+ []},
+ {unsafe5,
+ <<"t5() ->
+ Y = 3,
+ (X = true) andalso (X = true),
+ {X,Y}.
+ ">>,
+ [warn_unused_vars],
+ []},
+ {unsafe6,
+ <<"t6() ->
+ X = true,
+ (X = true) andalso (true = X),
+ X.
+ ">>,
+ [warn_unused_vars],
+ []},
+ {unsafe7,
+ <<"t7() ->
+ (if true -> X = 3; false -> true end)
+ andalso (X > 2),
+ X.
+ ">>,
+ [warn_unused_vars],
+ {errors,[{3,erl_lint,{unsafe_var,'X',{'if',2}}},
+ {4,erl_lint,{unsafe_var,'X',{'if',2}}}],
+ []}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unsafe_vars2(doc) ->
+ "OTP-4831, seq8202. No warn_unused_vars and unsafe variables";
+unsafe_vars2(suite) -> [];
+unsafe_vars2(Config) when is_list(Config) ->
+ Ts = [{unsafe2_1,
+ <<"foo(State) ->
+ case State of
+ true ->
+ if
+ false -> ok;
+ true -> State1=State
+ end
+ end,
+ State1. % unsafe
+ ">>,
+ [warn_unused_vars],
+ {errors,[{9,erl_lint,{unsafe_var,'State1',{'if',4}}}],[]}},
+ {unsafe2_2,
+ <<"foo(State) ->
+ case State of
+ true ->
+ if
+ false -> ok;
+ true -> State1=State
+ end
+ end,
+ State1. % unsafe
+ ">>,
+ [],
+ {errors,[{9,erl_lint,{unsafe_var,'State1',{'if',4}}}],[]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unsafe_vars_try(doc) ->
+ "Errors for unsafe variables in try/catch constructs.";
+unsafe_vars_try(suite) -> [];
+unsafe_vars_try(Config) when is_list(Config) ->
+ Ts = [{unsafe_try1,
+ <<"foo2() ->
+ try self()
+ catch
+ Class:Data -> Result={Class,Data}
+ end,
+ Result.
+ foo3a() ->
+ try self() of
+ R -> R
+ catch
+ Class:Data -> Result={Class,Data}
+ end,
+ Result.
+ foo3b() ->
+ try self() of
+ Result -> ok
+ catch
+ Class:Data -> {Class,Data}
+ end,
+ Result.
+ ">>,
+ [],
+ {errors,[{6,erl_lint,{unsafe_var,'Result',{'try',2}}},
+ {13,erl_lint,{unsafe_var,'Result',{'try',8}}},
+ {20,erl_lint,{unsafe_var,'Result',{'try',15}}}],
+ []}},
+ {unsafe_try2,
+ <<"foo1a() ->
+ Try =
+ try self()
+ catch
+ Class:Data -> Rc={Class,Data}
+ after
+ Ra=ok
+ end,
+ {Try,Rc,Ra}.
+ foo1b() ->
+ Try =
+ try self() of
+ R -> R
+ catch
+ Class:Data -> Rc={Class,Data}
+ after
+ Ra=R
+ end,
+ {Try,Rc,Ra}.
+ foo2() ->
+ Try =
+ try self() of
+ R -> Ro=R
+ catch
+ Class:Data -> {Class,Data}
+ after
+ Ra=R
+ end,
+ {Try,Ro,Ra}.
+ foo3() ->
+ Try =
+ try self() of
+ R -> Ro=R
+ catch
+ Class:Data -> Rc={Class,Data}
+ after
+ Ra=R
+ end,
+ {Try,R,Ro,Rc,Ra}.
+ ">>,
+ [],
+ {errors,[{9,erl_lint,{unsafe_var,'Ra',{'try',3}}},
+ {9,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {17,erl_lint,{unsafe_var,'R',{'try',12}}},
+ {19,erl_lint,{unsafe_var,'Ra',{'try',12}}},
+ {19,erl_lint,{unsafe_var,'Rc',{'try',12}}},
+ {27,erl_lint,{unsafe_var,'R',{'try',22}}},
+ {29,erl_lint,{unsafe_var,'Ra',{'try',22}}},
+ {29,erl_lint,{unsafe_var,'Ro',{'try',22}}},
+ {37,erl_lint,{unsafe_var,'R',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'R',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'Ra',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'Rc',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'Ro',{'try',32}}}],
+ []}},
+ {unsafe_try3,
+ <<"foo1(X) ->
+ Try =
+ try R=self()
+ catch
+ Class:Data -> Rc={X,R,Class,Data}
+ end,
+ {X,Try,Rc}.
+ foo2(X) ->
+ Try =
+ try R=self() of
+ RR -> Ro={X,R,RR}
+ catch
+ Class:Data -> {X,R,RR,Ro,Class,Data}
+ end,
+ {X,Try,R,RR,Ro,Class,Data}.
+ foo3(X) ->
+ Try =
+ try R=self() of
+ RR -> {X,R,RR}
+ catch
+ Class:Data -> {X,R,RR,Class,Data}
+ after
+ Ra={X,R,RR,Class,Data}
+ end,
+ {X,Try,R,RR,Ra,Class,Data}.
+ ">>,
+ [],
+ {errors,[{5,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {7,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {11,erl_lint,{unsafe_var,'R',{'try',10}}},
+ {13,erl_lint,{unbound_var,'RR'}},
+ {13,erl_lint,{unbound_var,'Ro'}},
+ {13,erl_lint,{unsafe_var,'R',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'Class',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'Data',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'R',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'RR',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'Ro',{'try',10}}},
+ {19,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {21,erl_lint,{unbound_var,'RR'}},
+ {21,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'Class',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'Data',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'RR',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'Class',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'Data',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'RR',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'Ra',{'try',18}}}],
+ []}},
+ {unsafe_try4,
+ <<"foo1(X) ->
+ Try =
+ try R=self() of
+ RR -> Ro={X,R,RR}
+ catch
+ Class:Data -> Rc={X,R,RR,Ro,Class,Data}
+ after
+ Ra={X,R,RR,Ro,Rc,Class,Data}
+ end,
+ {X,Try,R,RR,Ro,Rc,Ra,Class,Data}.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {6,erl_lint,{unbound_var,'RR'}},
+ {6,erl_lint,{unbound_var,'Ro'}},
+ {6,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Class',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Data',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'RR',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Ro',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Class',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Data',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'RR',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Ra',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Ro',{'try',3}}}],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+guard(doc) ->
+ "OTP-4670. Guards, is_record in particular.";
+guard(suite) -> [];
+guard(Config) when is_list(Config) ->
+ %% Well, these could be plain code...
+ Ts = [{guard1,
+ <<"-record(apa, {}).
+ t(A) when atom(A) ->
+ atom;
+ t(A) when binary(A) ->
+ binary;
+ t(A) when constant(A) ->
+ constant;
+ t(A) when float(A) ->
+ float;
+ t(A) when function(A) ->
+ function;
+ t(A) when integer(A) ->
+ integer;
+ t(A) when is_atom(A) ->
+ is_atom;
+ t(A) when is_binary(A) ->
+ is_binary;
+ t(A) when is_constant(A) ->
+ is_constant;
+ t(A) when is_float(A) ->
+ is_float;
+ t(A) when is_function(A) ->
+ is_function;
+ t(A) when is_integer(A) ->
+ is_integer;
+ t(A) when is_list(A) ->
+ is_list;
+ t(A) when is_number(A) ->
+ is_number;
+ t(A) when is_pid(A) ->
+ is_pid;
+ t(A) when is_port(A) ->
+ is_port;
+ t(A) when is_record(A, apa) ->
+ is_record;
+ t(A) when is_record(A, apa, 1) ->
+ is_record;
+ t(A) when is_reference(A) ->
+ is_reference;
+ t(A) when is_tuple(A) ->
+ is_tuple;
+ t(A) when list(A) ->
+ list;
+ t(A) when number(A) ->
+ number;
+ t(A) when pid(A) ->
+ pid;
+ t(A) when port(A) ->
+ port;
+ t(A) when record(A, apa) ->
+ record;
+ t(A) when reference(A) ->
+ reference;
+ t(A) when tuple(A) ->
+ tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ {error,
+ [{6,erl_lint,illegal_guard_expr},{18,erl_lint,illegal_guard_expr}],
+ [{18,erl_lint,{removed,{erlang,is_constant,1},
+ "Removed in R13B"}}]}},
+ {guard2,
+ <<"-record(apa,{}).
+ t1(A) when atom(A), atom(A) ->
+ atom;
+ t1(A) when binary(A), binary(A) ->
+ binary;
+ t1(A) when constant(A), constant(A) ->
+ constant;
+ t1(A) when float(A), float(A) ->
+ float;
+ t1(A) when function(A), function(A) ->
+ function;
+ t1(A) when integer(A), integer(A) ->
+ integer;
+ t1(A) when is_atom(A), is_atom(A) ->
+ is_atom;
+ t1(A) when is_binary(A), is_binary(A) ->
+ is_binary;
+ t1(A) when is_constant(A), is_constant(A) ->
+ is_constant;
+ t1(A) when is_float(A), is_float(A) ->
+ is_float;
+ t1(A) when is_function(A), is_function(A) ->
+ is_function;
+ t1(A) when is_integer(A), is_integer(A) ->
+ is_integer;
+ t1(A) when is_list(A), is_list(A) ->
+ is_list;
+ t1(A) when is_number(A), is_number(A) ->
+ is_number;
+ t1(A) when is_pid(A), is_pid(A) ->
+ is_pid;
+ t1(A) when is_port(A), is_port(A) ->
+ is_port;
+ t1(A) when is_record(A, apa), is_record(A, apa) ->
+ is_record;
+ t1(A) when is_record(A, apa, 1), is_record(A, apa, 1) ->
+ is_record;
+ t1(A) when is_reference(A), is_reference(A) ->
+ is_reference;
+ t1(A) when is_tuple(A), is_tuple(A) ->
+ is_tuple;
+ t1(A) when list(A), list(A) ->
+ list;
+ t1(A) when number(A), number(A) ->
+ number;
+ t1(A) when pid(A), pid(A) ->
+ pid;
+ t1(A) when port(A), port(A) ->
+ port;
+ t1(A) when record(A, apa), record(A, apa) ->
+ record;
+ t1(A) when reference(A), reference(A) ->
+ reference;
+ t1(A) when tuple(A), tuple(A) ->
+ tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ {error,[{6,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr}],
+ [{18,erl_lint,{removed,{erlang,is_constant,1},
+ "Removed in R13B"}},
+ {18,erl_lint,{removed,{erlang,is_constant,1},
+ "Removed in R13B"}}]}},
+ {guard3,
+ <<"-record(apa,{}).
+ t2(A) when atom(A); atom(A) ->
+ atom;
+ t2(A) when binary(A); binary(A) ->
+ binary;
+ t2(A) when float(A); float(A) ->
+ float;
+ t2(A) when function(A); function(A) ->
+ function;
+ t2(A) when integer(A); integer(A) ->
+ integer;
+ t2(A) when is_atom(A); is_atom(A) ->
+ is_atom;
+ t2(A) when is_binary(A); is_binary(A) ->
+ is_binary;
+ t2(A) when is_float(A); is_float(A) ->
+ is_float;
+ t2(A) when is_function(A); is_function(A) ->
+ is_function;
+ t2(A) when is_integer(A); is_integer(A) ->
+ is_integer;
+ t2(A) when is_list(A); is_list(A) ->
+ is_list;
+ t2(A) when is_number(A); is_number(A) ->
+ is_number;
+ t2(A) when is_pid(A); is_pid(A) ->
+ is_pid;
+ t2(A) when is_port(A); is_port(A) ->
+ is_port;
+ t2(A) when is_record(A, apa); is_record(A, apa) ->
+ is_record;
+ t2(A) when is_record(A, gurka, 1); is_record(A, gurka, 1) ->
+ is_record;
+ t2(A) when is_reference(A); is_reference(A) ->
+ is_reference;
+ t2(A) when is_tuple(A); is_tuple(A) ->
+ is_tuple;
+ t2(A) when list(A); list(A) ->
+ list;
+ t2(A) when number(A); number(A) ->
+ number;
+ t2(A) when pid(A); pid(A) ->
+ pid;
+ t2(A) when port(A); port(A) ->
+ port;
+ t2(A) when record(A, apa); record(A, apa) ->
+ record;
+ t2(A) when reference(A); reference(A) ->
+ reference;
+ t2(A) when tuple(A); tuple(A) ->
+ tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ []},
+ {guard4,
+ <<"-record(apa, {}).
+ t3(A) when float(A) or float(A) -> % coercing... (badarg)
+ float;
+ t3(A) when is_atom(A) or is_atom(A) ->
+ is_atom;
+ t3(A) when is_binary(A) or is_binary(A) ->
+ is_binary;
+ t3(A) when is_float(A) or is_float(A) ->
+ is_float;
+ t3(A) when is_function(A) or is_function(A) ->
+ is_function;
+ t3(A) when is_integer(A) or is_integer(A) ->
+ is_integer;
+ t3(A) when is_list(A) or is_list(A) ->
+ is_list;
+ t3(A) when is_number(A) or is_number(A) ->
+ is_number;
+ t3(A) when is_pid(A) or is_pid(A) ->
+ is_pid;
+ t3(A) when is_port(A) or is_port(A) ->
+ is_port;
+ t3(A) when is_record(A, apa) or is_record(A, apa) ->
+ is_record;
+ t3(A) when is_record(A, apa, 1) or is_record(A, apa, 1) ->
+ is_record;
+ t3(A) when is_reference(A) or is_reference(A) ->
+ is_reference;
+ t3(A) when is_tuple(A) or is_tuple(A) ->
+ is_tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ []}],
+ ?line [] = run(Config, Ts),
+ Ts1 = [{guard5,
+ <<"-record(apa, {}).
+ t3(A) when record(A, {apa}) ->
+ foo;
+ t3(A) when is_record(A, {apa}) ->
+ foo;
+ t3(A) when erlang:is_record(A, {apa}) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, {apa}) ->
+ foo;
+ t3(A) when is_record(A, {apa}, 1) ->
+ foo;
+ t3(A) when erlang:is_record(A, {apa}, 1) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, {apa}, 1) ->
+ foo;
+ t3(A) when is_record(A, apa, []) ->
+ foo;
+ t3(A) when erlang:is_record(A, apa, []) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, apa, []) ->
+ foo;
+ t3(A) when record(A, apa) ->
+ foo;
+ t3(A) when is_record(A, apa) ->
+ foo;
+ t3(A) when erlang:is_record(A, apa) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, apa) ->
+ foo.
+ ">>,
+ [warn_unused_vars, nowarn_obsolete_guard],
+ {errors,[{2,erl_lint,illegal_guard_expr},
+ {4,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {8,erl_lint,illegal_guard_expr},
+ {10,erl_lint,illegal_guard_expr},
+ {12,erl_lint,illegal_guard_expr},
+ {14,erl_lint,illegal_guard_expr},
+ {16,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {20,erl_lint,illegal_guard_expr}],
+ []}},
+ {guard6,
+ <<"-record(apa,{a=a,b=foo:bar()}).
+ apa() ->
+ [X || X <- [], #apa{a = a} == {r,X,foo}];
+ apa() ->
+ [X || X <- [], #apa{b = b} == {r,X,foo}];
+ apa() ->
+ [X || X <- [], #ful{a = a} == {r,X,foo}].
+ ">>,
+ [],
+ {errors,[{7,erl_lint,{undefined_record,ful}}],
+ []}},
+ {guard7,
+ <<"-record(apa,{}).
+ t() ->
+ [X || X <- [1,#apa{},3], (3+is_record(X, apa)) or
+ (is_record(X, apa)*2)].
+ ">>,
+ [],
+ []}],
+ ?line [] = run(Config, Ts1),
+ ok.
+
+otp_4886(doc) ->
+ "OTP-4886. Calling is_record with given record name.";
+otp_4886(suite) -> [];
+otp_4886(Config) when is_list(Config) ->
+ Ts = [{otp_4886,
+ <<"t() ->
+ X = {foo},
+ is_record(X, foo),
+ erlang:is_record(X, foo),
+ {erlang,is_record}(X, foo),
+ %% Note: is_record/3 does not verify that the record is defined,
+ %% so the following lines should give no errors.
+ is_record(X, foo, 1),
+ erlang:is_record(X, foo, 1),
+ {erlang,is_record}(X, foo, 1).
+ ">>,
+ [],
+ {errors,[{3,erl_lint,{undefined_record,foo}},
+ {4,erl_lint,{undefined_record,foo}},
+ {5,erl_lint,{undefined_record,foo}}],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_4988(doc) ->
+ "OTP-4988. Error when in-lining non-existent functions.";
+otp_4988(suite) -> [];
+otp_4988(Config) when is_list(Config) ->
+ Ts = [{otp_4988,
+ <<"-compile({inline, [{f,3},{f,4},{f,2},{f,a},{1,foo}]}).
+ -compile({inline, {g,1}}).
+ -compile({inline, {g,12}}).
+ -compile(inline).
+ -compile({inline_size,100}).
+
+ f(A, B) ->
+ {g(A), B}.
+
+ g(A) ->
+ {A}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,{bad_inline,{1,foo}}},
+ {1,erl_lint,{bad_inline,{f,3}}},
+ {1,erl_lint,{bad_inline,{f,4}}},
+ {1,erl_lint,{bad_inline,{f,a}}},
+ {3,erl_lint,{bad_inline,{g,12}}}],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5091(doc) ->
+ "OTP-5091. Patterns and the bit syntax: invalid warnings.";
+otp_5091(suite) -> [];
+otp_5091(Config) when is_list(Config) ->
+ Ts = [{otp_5091_1,
+ <<"t() ->
+ [{Type, Value} || <<Type:16, _Len:16,
+ Value:_Len/binary>> <- []].
+ ">>,
+ [],
+ []},
+ {otp_5091_2,
+ <<"t() ->
+ %% This one has always been handled OK:
+ <<Type:16, _Len:16,
+ Value:_Len/binary>> = <<18:16, 9:16, \"123456789\">>,
+ {Type, Value}.
+ ">>,
+ [],
+ []},
+ {otp_5091_3,
+ <<"t() ->
+ fun(<<Type:16, _Len:16, Value:_Len/binary>>) ->
+ {Type, Value}
+ end.
+ ">>,
+ [],
+ []},
+ {otp_5091_4,
+ <<"t() ->
+ L = 8,
+ F = fun(<<A:L,B:A>>) -> B end,
+ F(<<16:8, 7:16>>).
+ ">>,
+ [],
+ []},
+ {otp_5091_5,
+ <<"t() ->
+ L = 8,
+ F = fun(<<L: % L shadowed.
+ L,
+ B:
+ L>>) -> B end,
+ F(<<16:8, 7:16>>).
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_6,
+ <<"t(A) ->
+ (fun(<<L:16,M:L,N:M>>) -> ok end)(A).
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'N'}}]}},
+ {otp_5091_7,
+ <<"t() ->
+ U = 8,
+ (fun(<<U: % U shadowed.
+ U>>) -> U end)(<<32:8>>).
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'U','fun'}}]}},
+ {otp_5091_8,
+ <<"t() ->
+ [X || <<A:8,
+ B:A>> <- [],
+ <<X:8>> <- [B]].
+ ">>,
+ [],
+ []},
+ {otp_5091_9,
+ <<"t() ->
+ L = 8,
+ F = fun(<<L: % Shadow.
+ L,
+ L:
+ L,
+ L:
+ L
+ >>) ->
+ L
+ end,
+ F(<<16:8, 8:16, 32:8>>).
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_10,
+ <<"t() ->
+ L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B.
+ ">>,
+ [],
+ []},
+ {otp_5091_11,
+ <<"t() ->
+ fun(<<L:16,L:L,L:L>>) -> ok end.
+ ">>,
+ [],
+ []},
+ {otp_5091_12,
+ <<"t([A,B]) ->
+ fun(<<A:B>>, % A shadowed and unused
+ <<Q:A>>) -> foo % Q unused. 'outer' A is used.
+ end.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'A'}},
+ {2,erl_lint,{shadowed_var,'A','fun'}},
+ {3,erl_lint,{unused_var,'Q'}}]}},
+ {otp_5091_13,
+ <<"t([A,B]) -> % A unused, B unused
+ fun({A,B}, % A shadowed, B unused, B shadowed
+ {Q,A}) -> foo % Q unused. 'inner' A is used
+ end.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{unused_var,'A'}},
+ {1,erl_lint,{unused_var,'B'}},
+ {2,erl_lint,{unused_var,'B'}},
+ {2,erl_lint,{shadowed_var,'A','fun'}},
+ {2,erl_lint,{shadowed_var,'B','fun'}},
+ {3,erl_lint,{unused_var,'Q'}}]}},
+ {otp_5091_14,
+ <<"t() ->
+ A = 4,
+ fun(<<A: % shadowed, unused
+ A>>) -> 2 end.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{unused_var,'A'}},
+ {3,erl_lint,{shadowed_var,'A','fun'}}]}},
+ {otp_5091_15,
+ <<"t() ->
+ A = 4, % unused
+ fun(<<A:8, % shadowed
+ 16:A>>) -> 2 end.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'A'}},
+ {3,erl_lint,{shadowed_var,'A','fun'}}]}},
+ {otp_5091_16,
+ <<"t() ->
+ A = 4,
+ fun(<<8:A, %
+ A:8>>) -> 7 end. % shadowed, unused
+ ">>,
+ [],
+ {warnings,[{4,erl_lint,{unused_var,'A'}},
+ {4,erl_lint,{shadowed_var,'A','fun'}}]}},
+ {otp_5091_17,
+ <<"t() ->
+ L = 16,
+ fun(<<L: % shadow
+ L>>, % 'outer' L
+ <<L: % shadow and match
+ L>>) -> % 'outer' L
+ a
+ end.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_18,
+ <<"t() ->
+ L = 4, % L unused
+ fun({L, % L shadowed
+ L},
+ {L,
+ L}) ->
+ a
+ end.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_19,
+ <<"t() ->
+ L = 4,
+ [L || <<L: % shadowed
+ L,
+ L:
+ L>> <- []].
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L',generate}}]}},
+ {otp_5091_20,
+ <<"t() ->
+ L = 4, % L unused.
+ [1 || L <- []]. % L unused, L shadowed.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L',generate}}]}},
+ {otp_5091_21,
+ <<"t() ->
+ L = 4,
+ [1 || L <- [L]]. % L shadowed. L unused.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L',generate}}]}},
+ {otp_5091_22,
+ <<"t() ->
+ L = 4, % unused
+ fun(L) -> L end. % shadowed
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_23,
+ <<"t([A,A]) -> a.">>, [], []},
+ {otp_5091_24,
+ <<"t({A,A}) -> a.">>, [], []},
+ {otp_5091_25,
+ <<"-record(r, {f1,f2}).
+ t(#r{f1 = A, f2 = A}) -> a.">>, [], []}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5276(doc) ->
+ "OTP-5276. Check the 'deprecated' attributed.";
+otp_5276(suite) -> [];
+otp_5276(Config) when is_list(Config) ->
+ Ts = [{otp_5276_1,
+ <<"-deprecated([{frutt,0,next_version}]).
+ -deprecated([{does_not_exist,1}]).
+ -deprecated('foo bar').
+ -deprecated(module).
+ -deprecated([{f,'_'}]).
+ -deprecated([{t,0}]).
+ -deprecated([{t,'_',eventually}]).
+ -deprecated([{'_','_',never}]).
+ -deprecated([{{badly,formed},1}]).
+ -deprecated([{'_','_',next_major_release}]).
+ -export([t/0]).
+ frutt() -> ok.
+ t() -> ok.
+ ">>,
+ {[]},
+ {error,[{1,erl_lint,{bad_deprecated,{frutt,0}}},
+ {2,erl_lint,{bad_deprecated,{does_not_exist,1}}},
+ {3,erl_lint,{invalid_deprecated,'foo bar'}},
+ {5,erl_lint,{bad_deprecated,{f,'_'}}},
+ {8,erl_lint,{invalid_deprecated,{'_','_',never}}},
+ {9,erl_lint,{invalid_deprecated,{{badly,formed},1}}}],
+ [{12,erl_lint,{unused_function,{frutt,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5917(doc) ->
+ "OTP-5917. Check the 'deprecated' attributed.";
+otp_5917(suite) -> [];
+otp_5917(Config) when is_list(Config) ->
+ Ts = [{otp_5917_1,
+ <<"-compile(export_all).
+
+ -deprecated({t,0}).
+
+ t() ->
+ foo.
+ ">>,
+ {[]},
+ []}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_6585(doc) ->
+ "OTP-6585. Check the deprecated guards list/1, pid/1, ....";
+otp_6585(suite) -> [];
+otp_6585(Config) when is_list(Config) ->
+ Ts = [{otp_6585_1,
+ <<"-compile(export_all).
+
+ -record(r, {}).
+
+ f(A) when list(A) -> list;
+ f(R) when record(R, r) -> rec;
+ f(P) when pid(P) -> pid.
+
+ t() ->
+ f([]).
+ ">>,
+ [warn_obsolete_guard],
+ {warnings,[{5,erl_lint,{obsolete_guard,{list,1}}},
+ {6,erl_lint,{obsolete_guard,{record,2}}},
+ {7,erl_lint,{obsolete_guard,{pid,1}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5338(doc) ->
+ "OTP-5338. Bad warning in record initialization.";
+otp_5338(suite) -> [];
+otp_5338(Config) when is_list(Config) ->
+ %% OTP-5878: variables like X are no longer allowed in initialisations
+ Ts = [{otp_5338,
+ <<"-record(c, {a = <<X:7/binary-unit:8>>}).
+ t() ->
+ X = <<\"hejsans\">>,
+ #c{}.
+ ">>,
+ [],
+ {error,[{1,erl_lint,{unbound_var,'X'}}],
+ [{3,erl_lint,{unused_var,'X'}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5362(doc) ->
+ "OTP-5362. deprecated_function, "
+ "{nowarn_unused_funtion,FAs}, 'better' line numbers.";
+otp_5362(suite) -> [];
+otp_5362(Config) when is_list(Config) ->
+ Ts = [{otp_5362_1,
+ <<"-include_lib(\"stdlib/include/qlc.hrl\").
+
+ -file(?FILE, 1000).
+
+ t() ->
+ qlc:q([X || X <- [],
+ begin A = 3, true end]).
+ ">>,
+ {[warn_unused_vars]},
+ {warnings,[{1002,erl_lint,{unused_function,{t,0}}},
+ {1004,erl_lint,{unused_var,'A'}}]}},
+
+ {otp_5362_2,
+ <<"-export([inline/0]).
+
+ -import(lists.foo, [a/1,b/1]). % b/1 is not used
+
+ -compile([{inline,{inl,7}}]). % undefined
+ -compile([{inline,[{inl,17}]}]). % undefined
+ -compile([{inline,{inl,1}}]). % OK
+
+ foop() -> % unused function
+ a([]), % used import, OK
+ fipp(). % undefined
+
+ inline() ->
+ inl(foo).
+
+ inl(_) ->
+ true.
+
+ not_used() -> % unused function
+ true.
+
+ -compile({nowarn_unused_function,[{and_not_used,2}]}). % unknown
+ and_not_used(_) -> % unused function
+ foo.
+
+ -compile({nowarn_unused_function,{unused_function,2}}).
+ unused_function(_, _) ->
+ ok.
+ ">>,
+ {[warn_unused_vars, warn_unused_import]},
+ {error,[{5,erl_lint,{bad_inline,{inl,7}}},
+ {6,erl_lint,{bad_inline,{inl,17}}},
+ {11,erl_lint,{undefined_function,{fipp,0}}},
+ {22,erl_lint,{bad_nowarn_unused_function,{and_not_used,2}}}],
+ [{3,erl_lint,{unused_import,{{b,1},'lists.foo'}}},
+ {9,erl_lint,{unused_function,{foop,0}}},
+ {19,erl_lint,{unused_function,{not_used,0}}},
+ {23,erl_lint,{unused_function,{and_not_used,1}}}]}},
+
+ {otp_5362_3,
+ <<"-record(a, {x,
+ x}).
+ -record(a, {x,
+ X}). % erl_parse
+ -record(a, [x,
+ x]). % erl_parse
+ -record(ok, {a,b}).
+
+ -record(r, {a = #ok{},
+ b = (#ok{})#ok.a}).
+
+ t() ->
+ {#a{},
+ #nix{},
+ #ok{nix = []},
+ #ok{Var = 4},
+ #r{}
+ }.
+ ">>,
+ {[nowarn_unused_function]},
+ {errors2, [{4,erl_parse,"bad record field"},
+ {5,erl_parse,"bad record declaration"}],
+ [{2,erl_lint,{redefine_field,a,x}},
+ {14,erl_lint,{undefined_record,nix}},
+ {15,erl_lint,{undefined_field,ok,nix}},
+ {16,erl_lint,{field_name_is_variable,ok,'Var'}}]}},
+
+ {otp_5362_4,
+ <<"-compile(nowarn_deprecated_function).
+ -compile(nowarn_bif_clash).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function,
+ warn_deprecated_function,
+ warn_bif_clash]},
+ {error,
+ [{5,erl_lint,{call_to_redefined_bif,{spawn,1}}}],
+ [{3,erl_lint,{redefine_bif,{spawn,1}}},
+ {4,erl_lint,{deprecated,{erlang,hash,2},{erlang,phash2,2},
+ "in a future release"}}]}},
+
+ {otp_5362_5,
+ <<"-compile(nowarn_deprecated_function).
+ -compile(nowarn_bif_clash).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function]},
+ {warnings,
+ [{3,erl_lint,{redefine_bif,{spawn,1}}}]}},
+
+ %% The special nowarn_X are not affected by general warn_X.
+ {otp_5362_6,
+ <<"-compile({nowarn_deprecated_function,{erlang,hash,2}}).
+ -compile({nowarn_bif_clash,{spawn,1}}).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function,
+ warn_deprecated_function,
+ warn_bif_clash]},
+ {warnings,
+ [{3,erl_lint,{redefine_bif,{spawn,1}}}]}},
+
+ {otp_5362_7,
+ <<"-export([spawn/1]).
+ -compile({nowarn_deprecated_function,{erlang,hash,2}}).
+ -compile({nowarn_bif_clash,{spawn,1}}).
+ -compile({nowarn_bif_clash,{spawn,2}}). % bad
+ -compile([{nowarn_deprecated_function,
+ [{erlang,hash,-1},{3,hash,-1}]}, % 2 bad
+ {nowarn_deprecated_function, {{a,b,c},hash,-1}}]). % bad
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function]},
+ {error,[{4,erl_lint,{bad_nowarn_bif_clash,{spawn,2}}}],
+ [{5,erl_lint,{bad_nowarn_deprecated_function,{3,hash,-1}}},
+ {5,erl_lint,{bad_nowarn_deprecated_function,{erlang,hash,-1}}},
+ {5,erl_lint,{bad_nowarn_deprecated_function,{{a,b,c},hash,-1}}}]}
+ },
+
+ {otp_5362_8,
+ <<"-export([spawn/1]).
+ -compile(warn_deprecated_function).
+ -compile(warn_bif_clash).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function,
+ {nowarn_bif_clash,{spawn,1}}]}, % has no effect
+ {warnings,
+ [{5,erl_lint,{deprecated,{erlang,hash,2},{erlang,phash2,2},
+ "in a future release"}}]}},
+
+ {otp_5362_9,
+ <<"-include_lib(\"stdlib/include/qlc.hrl\").
+ -record(a, {x = qlc:q([{X,Y} || {X} <- [],{Y} <- [],X =:= Y])}).
+ -export([t/0]).
+ t() -> #a{}.
+ ">>,
+ {[]},
+ []}
+
+ ],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5371(doc) ->
+ "OTP-5371. Aliases for bit syntax expressions are no longer allowed.";
+otp_5371(suite) -> [];
+otp_5371(Config) when is_list(Config) ->
+ Ts = [{otp_5371_1,
+ <<"t(<<A:8>> = <<B:8>>) ->
+ {A,B}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_5371_2,
+ <<"x([<<A:8>>] = [<<B:8>>]) ->
+ {A,B}.
+ y({a,<<A:8>>} = {b,<<B:8>>}) ->
+ {A,B}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern},
+ {3,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_5371_3,
+ <<"-record(foo, {a,b,c}).
+ -record(bar, {x,y,z}).
+ -record(buzz, {x,y}).
+ a(#foo{a = <<X:8>>} = #bar{x = <<Y:8>>}) ->
+ {X,Y}.
+ b(#foo{b = <<X:8>>} = #foo{b = <<Y:4,Z:4>>}) ->
+ {X,Y,Z}.
+ c(#foo{a = <<X:8>>} = #buzz{x = <<Y:8>>}) ->
+ {X,Y}.
+ d(#foo{a=x,b = <<X:8>>} = #buzz{y = <<Y:8>>}) ->
+ {X,Y}.
+ e(#foo{a=x,b = <<X:8>>} = #buzz{x=glurf,y = <<Y:8>>}) ->
+ {X,Y}.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,illegal_bin_pattern},
+ {6,erl_lint,illegal_bin_pattern},
+ {8,erl_lint,illegal_bin_pattern},
+ {10,erl_lint,illegal_bin_pattern},
+ {12,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_5371_4,
+ <<"-record(foo, {a,b,c}).
+ -record(bar, {x,y,z}).
+ -record(buzz, {x,y}).
+ a(#foo{a = <<X:8>>,b=x} = #foo{b = <<Y:8>>}) ->
+ {X,Y}.
+ b(#foo{a = <<X:8>>} = #bar{y = <<Y:4,Z:4>>}) ->
+ {X,Y,Z}.
+ c(#foo{a = <<X:8>>} = #buzz{y = <<Y:8>>}) ->
+ {X,Y}.
+ ">>,
+ [],
+ {warnings,[{4,v3_core,nomatch},
+ {6,v3_core,nomatch},
+ {8,v3_core,nomatch}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_7227(doc) -> "OTP_7227. Some aliases for bit syntax expressions were still allowed.";
+otp_7227(Config) when is_list(Config) ->
+ Ts = [{otp_7227_1,
+ <<"t([<<A:8>> = {C,D} = <<B:8>>]) ->
+ {A,B,C,D}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_2,
+ <<"t([(<<A:8>> = {C,D}) = <<B:8>>]) ->
+ {A,B,C,D}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_3,
+ <<"t([(<<A:8>> = {C,D}) = (<<B:8>> = <<C:8>>)]) ->
+ {A,B,C,D}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern},
+ {1,erl_lint,illegal_bin_pattern},
+ {1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_4,
+ <<"t(Val) ->
+ <<A:8>> = <<B:8>> = Val,
+ {A,B}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_5,
+ <<"t(Val) ->
+ <<A:8>> = X = <<B:8>> = Val,
+ {A,B,X}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_6,
+ <<"t(X, Y) ->
+ <<A:8>> = <<X:4,Y:4>>,
+ A.
+ ">>,
+ [],
+ []},
+ {otp_7227_7,
+ <<"t(Val) ->
+ (<<A:8>> = X) = (<<B:8>> = <<A:4,B:4>>) = Val,
+ {A,B,X}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern},
+ {2,erl_lint,illegal_bin_pattern},
+ {2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_8,
+ <<"t(Val) ->
+ (<<A:8>> = X) = (Y = <<B:8>>) = Val,
+ {A,B,X,Y}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_9,
+ <<"t(Val) ->
+ (Z = <<A:8>> = X) = (Y = <<B:8>> = W) = Val,
+ {A,B,X,Y,Z,W}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5494(doc) ->
+ "OTP-5494. Warnings for functions exported more than once.";
+otp_5494(suite) -> [];
+otp_5494(Config) when is_list(Config) ->
+ Ts = [{otp_5494_1,
+ <<"-export([t/0]).
+ -export([t/0]).
+ t() -> a.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{duplicated_export,{t,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5644(doc) ->
+ "OTP-5644. M:F/A in record initialization.";
+otp_5644(suite) -> [];
+otp_5644(Config) when is_list(Config) ->
+ %% This test is a no-op. Although {function,mfa,i,1} was
+ %% transformed into {function,Line,i,1} by copy_expr, the module
+ %% was never checked (Line is the line number).
+ %% (OTP-5878: somewhat modified.)
+ Ts = [{otp_5644,
+ <<"-record(c, {a = fun ?MODULE:i/1(17)}).
+ t() ->
+ #c{}.
+
+ i(X) ->
+ X.
+ ">>,
+ [],
+ []}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5878(doc) ->
+ "OTP-5878. Record declaration: forward references, introduced variables.";
+otp_5878(suite) -> [];
+otp_5878(Config) when is_list(Config) ->
+ Ts = [{otp_5878_10,
+ <<"-record(rec1, {a = #rec2{}}).
+ -record(rec2, {a = #rec1{}}).
+ t() ->#rec1{}.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{undefined_record,rec2}}],
+ [{2,erl_lint,{unused_record,rec2}}]}},
+
+ {otp_5878_20,
+ <<"-record(r1, {a = begin A = 4, {A,B} end}). % B unbound
+ -record(r2, {e = begin A = 3, #r1{} end}).
+ t() -> #r2{}.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{unbound_var,'B'}},
+ {1,erl_lint,{variable_in_record_def,'A'}},
+ {2,erl_lint,{variable_in_record_def,'A'}}],
+ [{1,erl_lint,{unused_record,r1}}]}},
+
+ {otp_5878_30,
+ <<"-record(r1, {t = case foo of _ -> 3 end}).
+ -record(r2, {a = case foo of A -> A; _ -> 3 end}).
+ -record(r3, {a = case foo of A -> A end}).
+ t() -> {#r1{},#r2{},#r3{}}.
+ ">>,
+ [warn_unused_record],
+ {errors,[{2,erl_lint,{variable_in_record_def,'A'}},
+ {3,erl_lint,{variable_in_record_def,'A'}}],
+ []}},
+
+ {otp_5878_40,
+ <<"-record(r1, {foo = A}). % A unbound
+ -record(r2, {a = fun(X) -> X end(3)}).
+ -record(r3, {a = [X || X <- [1,2,3]]}).
+ t() -> {#r1{},#r2{},#r3{}}.
+ ">>,
+ [warn_unused_record],
+ {errors,[{1,erl_lint,{unbound_var,'A'}}],[]}},
+
+ {otp_5878_50,
+ <<"-record(r1, {a = {A, % A unbound
+ A}}). % A unbound
+ -record(r2, {a = begin case foo of
+ A -> A
+ end,
+ A
+ end}).
+ -record(r3, {a = fun(X) ->
+ case foo of
+ A -> A
+ end
+ end
+ }).
+ -record(r4, {a = case foo of
+ foo ->
+ case foo of
+ A -> A
+ end;
+ _ ->
+ bar
+ end}).
+ t() -> {#r1{},#r2{},#r3{},#r4{}}.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{unbound_var,'A'}},
+ {2,erl_lint,{unbound_var,'A'}},
+ {4,erl_lint,{variable_in_record_def,'A'}},
+ {17,erl_lint,{variable_in_record_def,'A'}}],
+ [{8,erl_lint,{unused_var,'X'}}]}},
+
+ {otp_5878_60,
+ <<"-record(r1, {a = fun(NotShadowing) -> NotShadowing end}).
+ t() ->
+ NotShadowing = 17,
+ {#r1{}, NotShadowing}.
+ ">>,
+ [warn_unused_record],
+ []},
+
+ {otp_5878_70,
+ <<"-record(r1, {a = fun(<<X:8>>) -> X end,
+ b = case <<17:8>> of
+ <<_:Y>> -> Y;
+ <<Y:8>> ->
+ Y
+ end}).
+ t() -> #r1{}.
+ ">>,
+ [warn_unused_record],
+ {errors,[{3,erl_lint,{unbound_var,'Y'}},
+ {4,erl_lint,{variable_in_record_def,'Y'}}],
+ []}},
+
+ {otp_5878_80,
+ <<"-record(r, {a = [X || {A,Y} <- [{1,2},V={3,4}],
+ begin Z = [1,2,3], true end,
+ X <- Z ++ [A,Y]]}).
+ t() ->#r{}.
+ ">>,
+ [warn_unused_record],
+ {warnings,[{1,erl_lint,{unused_var,'V'}}]}},
+
+ {otp_5878_90,
+ <<"-record(r, {a = foo()}). % unused
+
+ t() -> ok.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{undefined_function,{foo,0}}}],
+ [{1,erl_lint,{unused_record,r}}]}}
+
+ ],
+ ?line [] = run(Config, Ts),
+
+ Abstr = <<"-module(lint_test, [A, B]).
+
+ -export([args/1]).
+
+ -record(r, {a = A, b = THIS}). % A and THIS are unbound
+
+ %% param:args(compile,param:new(1,2)).
+
+ args(C) ->
+ X = local(C),
+ Z = new(A, B),
+ F = fun(THIS) -> {x, A} end, % THIS unused and shadowed
+ {X, Z, THIS, F, #r{}}.
+
+ local(C) ->
+ module_info(C).
+ ">>,
+ ?line {error,[{5,erl_lint,{unbound_var,'A'}},
+ {5,erl_lint,{unbound_var,'THIS'}}],
+ [{12,erl_lint,{unused_var,'THIS'}},
+ {12,erl_lint,{shadowed_var,'THIS','fun'}}]}
+ = run_test2(Config, Abstr, [warn_unused_record]),
+
+ QLC1 = <<"-module(lint_test).
+ -include_lib(\"stdlib/include/qlc.hrl\").
+ -export([t/0]).
+ -record(r1, {a = qlc:e(qlc:q([X || X <- [1,2,3]]))}).
+ -record(r2, {a = qlc:q([X || X <- [1,2,3]])}).
+ -record(r3, {a = qlc:q([X || {A,Y} <- [{1,2},V={3,4}],
+ begin Z = [1,2,3], true end,
+ X <- Z ++ [A,Y]])}).
+ t() -> {#r1{},#r2{},#r3{}}.
+ ">>,
+ ?line {error,[{8,qlc,{used_generator_variable,'A'}},
+ {8,qlc,{used_generator_variable,'Y'}},
+ {8,qlc,{used_generator_variable,'Z'}}],
+ [{6,erl_lint,{unused_var,'V'}}]} =
+ run_test2(Config, QLC1, [warn_unused_record]),
+
+ Ill1 = <<"-module(lint_test).
+ -export([t/0]).
+ -record(r, {a = true}).
+ -record(r1, {a,b}).
+ -record(r2, {a = #r1{a = true}}).
+ -record(r3, {a = A}). % A is unbound
+ -record(r4, {a = dict:new()}).
+
+ t() ->
+ case x() of
+ _ when (#r{})#r.a ->
+ a;
+ _ when (#r4{})#r.a -> % illegal
+ b;
+ _ when (#r3{q = 5})#r.a -> % no warning for unbound A
+ q;
+ _ when (#r{q = 5})#r.a ->
+ a;
+ _ when (((#r{a = #r2{}})#r.a)#r2.a)#r1.a ->
+ b;
+ _ when #r{a = dict:new()} -> % illegal
+ c;
+ _ when l() > 3 -> % illegal, does not use l/0...
+ d;
+ _ ->
+ w
+ end.
+
+ l() ->
+ foo.
+
+ x() ->
+ bar.
+ ">>,
+
+ ?line {errors,[{6,erl_lint,{unbound_var,'A'}},
+ {13,erl_lint,illegal_guard_expr},
+ {15,erl_lint,{undefined_field,r3,q}},
+ {17,erl_lint,{undefined_field,r,q}},
+ {21,erl_lint,illegal_guard_expr},
+ {23,erl_lint,illegal_guard_expr}],
+ []} =
+ run_test2(Config, Ill1, [warn_unused_record]),
+
+ Ill2 = <<"-module(lint_test).
+ -export([t/0]).
+ t() ->
+ case x() of
+ _ when l()
+ or
+ l() ->
+ foo
+ end.
+ ">>,
+ ?line {errors,[{4,erl_lint,{undefined_function,{x,0}}},
+ {5,erl_lint,illegal_guard_expr},
+ {7,erl_lint,illegal_guard_expr}],
+ []} =
+ run_test2(Config, Ill2, [warn_unused_record]),
+
+ Ill3 = <<"t() -> ok.">>,
+ ?line {errors,[{1,erl_lint,undefined_module}],[]} =
+ run_test2(Config, Ill3, [warn_unused_record]),
+
+ Usage1 = <<"-module(lint_test).
+ -export([t/0]).
+ -record(u1, {a}).
+ -record(u2, {a = #u1{}}).
+ -record(u3, {a}). % unused
+ -record(u4, {a = #u3{}}). % unused
+
+ t() ->
+ {#u2{}}.
+ ">>,
+ ?line {warnings,[{5,erl_lint,{unused_record,u3}},
+ {6,erl_lint,{unused_record,u4}}]} =
+ run_test2(Config, Usage1, [warn_unused_record]),
+
+ Usage2 = <<"-module(lint_test).
+ -export([t/0]).
+ -record(u1, {a}).
+ -record(u2, {a = #u1{}}).
+ -file(\"some_file.hrl\", 1).
+ -record(u3, {a}). % unused, but on other file
+ -record(u4, {a = #u3{}}). % -\"-
+
+ t() ->
+ {#u2{}}.
+ ">>,
+ ?line [] = run_test2(Config, Usage2, [warn_unused_record]),
+
+ %% This a completely different story...
+ %% The linter checks if qlc.hrl hasn't been included
+ QLC2 = <<"-module(lint_test).
+ -import(qlc, [q/2]).
+ -export([t/0]).
+
+ t() ->
+ H1 = qlc:q([X || X <- [1,2]]),
+ H2 = qlc:q([X || X <- [1,2]], []),
+ H3 = q([X || X <- [1,2]], []),
+ {H1,H2,H3}.
+ ">>,
+ ?line {warnings,[{6,erl_lint,{missing_qlc_hrl,1}},
+ {7,erl_lint,{missing_qlc_hrl,2}},
+ {8,erl_lint,{missing_qlc_hrl,2}}]} =
+ run_test2(Config, QLC2, [warn_unused_record]),
+
+ %% Records that are used by types are not unused.
+ %% (Thanks to Fredrik Thulin and Kostis Sagonas.)
+ UsedByType = <<"-module(t).
+ -export([foo/1]).
+ -record(sipurl, {host :: string()}).
+ -record(keylist, {list = [] :: [_]}).
+ -type sip_headers() :: #keylist{}.
+ -record(request, {uri :: #sipurl{}, header :: sip_headers()}).
+
+ foo(#request{}) -> ok.
+ ">>,
+ ?line [] = run_test2(Config, UsedByType, [warn_unused_record]),
+
+ ok.
+
+otp_6885(doc) ->
+ "OTP-6885. Binary fields in bit syntax matching is now only allowed at the end.";
+otp_6885(suite) -> [];
+otp_6885(Config) when is_list(Config) ->
+ Ts = <<"-module(otp_6885).
+ -export([t/1]).
+ t(<<_/binary,I>>) -> I;
+ t(<<X/binary,I:X>>) -> I;
+ t(<<B/binary,T/binary>>) -> {B,T}.
+
+ build(A, B) ->
+ <<A/binary,B/binary>>.
+
+ foo(<<\"abc\"/binary>>) ->
+ ok;
+ foo(<<\"abc\":13/integer>>) ->
+ ok;
+ foo(<<\"abc\"/float>>) ->
+ ok;
+ foo(<<\"abc\":19>>) ->
+ ok;
+ foo(<<\"abc\"/utf8>>) ->
+ ok;
+ foo(<<\"abc\"/utf16>>) ->
+ ok;
+ foo(<<\"abc\"/utf32>>) ->
+ ok.
+
+ ">>,
+ ?line {errors,[{3,erl_lint,unsized_binary_not_at_end},
+ {4,erl_lint,unsized_binary_not_at_end},
+ {5,erl_lint,unsized_binary_not_at_end},
+ {10,erl_lint,typed_literal_string},
+ {12,erl_lint,typed_literal_string},
+ {14,erl_lint,typed_literal_string},
+ {16,erl_lint,typed_literal_string}],
+ []} = run_test2(Config, Ts, []),
+ ok.
+
+export_all(doc) ->
+ "OTP-7392. Warning for export_all.";
+export_all(Config) when is_list(Config) ->
+ Ts = <<"-module(export_all_module).
+ -compile([export_all]).
+
+ id(I) -> I.
+ ">>,
+ ?line [] = run_test2(Config, Ts, []),
+ ?line {warnings,[{2,erl_lint,export_all}]} =
+ run_test2(Config, Ts, [warn_export_all]),
+ ok.
+
+bif_clash(doc) ->
+ "Test warnings for functions that clash with BIFs.";
+bif_clash(suite) -> [];
+bif_clash(Config) when is_list(Config) ->
+ Ts = [{clash1,
+ <<"t(X) ->
+ size(X).
+
+ %% No warning for the following calls, since they
+ %% are unambigous.
+ b(X) ->
+ erlang:size(X).
+
+ c(X) ->
+ ?MODULE:size(X).
+
+ size({N,_}) ->
+ N.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,{call_to_redefined_bif,{size,1}}}],[]}},
+
+ %% Verify that (some) warnings can be turned off.
+ {clash2,
+ <<"-export([t/1,size/1]).
+ t(X) ->
+ size(X).
+
+ size({N,_}) ->
+ N.
+
+ %% My own abs/1 function works on lists too.
+ %% Unfortunately, it is not exported, so there will
+ %% be a warning that can't be turned off.
+ abs([H|T]) when $a =< H, H =< $z -> [H-($a-$A)|abs(T)];
+ abs([H|T]) -> [H|abs(T)];
+ abs([]) -> [];
+ abs(X) -> erlang:abs(X).
+ ">>,
+ {[nowarn_bif_clash]},
+ {warnings,[{11,erl_lint,{redefine_bif,{abs,1}}},
+ {11,erl_lint,{unused_function,{abs,1}}}]}}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+behaviour_basic(doc) ->
+ "Basic tests with one behaviour.";
+behaviour_basic(suite) -> [];
+behaviour_basic(Config) when is_list(Config) ->
+ Ts = [{behaviour1,
+ <<"-behaviour(application).
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{undefined_behaviour_func,{start,2},application}},
+ {1,erl_lint,{undefined_behaviour_func,{stop,1},application}}]}},
+
+ {behaviour2,
+ <<"-behaviour(application).
+ -export([stop/1]).
+ stop(_) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{undefined_behaviour_func,{start,2},application}}]}},
+
+ {behaviour3,
+ <<"-behavior(application). %% Test American spelling.
+ -export([start/2,stop/1]).
+ start(_, _) -> ok.
+ stop(_) -> ok.
+ ">>,
+ [],
+ []}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+behaviour_multiple(doc) ->
+ "Basic tests with multiple behaviours.";
+behaviour_multiple(suite) -> [];
+behaviour_multiple(Config) when is_list(Config) ->
+ Ts = [{behaviour1,
+ <<"-behaviour(application).
+ -behaviour(supervisor).
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{undefined_behaviour_func,{start,2},application}},
+ {1,erl_lint,{undefined_behaviour_func,{stop,1},application}},
+ {2,erl_lint,{undefined_behaviour_func,{init,1},supervisor}}]}},
+
+ {behaviour2,
+ <<"-behaviour(application).
+ -behaviour(supervisor).
+ -export([start/2,stop/1,init/1]).
+ start(_, _) -> ok.
+ stop(_) -> ok.
+ init(_) -> ok.
+ ">>,
+ [],
+ []},
+
+ {american_behavior2,
+ <<"-behavior(application).
+ -behavior(supervisor).
+ -export([start/2,stop/1,init/1]).
+ start(_, _) -> ok.
+ stop(_) -> ok.
+ init(_) -> ok.
+ ">>,
+ [],
+ []},
+
+ {behaviour3,
+ <<"-behaviour(gen_server).
+ -behaviour(supervisor).
+ -export([handle_call/3,handle_cast/2,handle_info/2]).
+ handle_call(_, _, _) -> ok.
+ handle_cast(_, _) -> ok.
+ handle_info(_, _) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,
+ {undefined_behaviour_func,{code_change,3},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{init,1},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{terminate,2},gen_server}},
+ {2,erl_lint,{undefined_behaviour_func,{init,1},supervisor}},
+ {2,
+ erl_lint,
+ {conflicting_behaviours,{init,1},supervisor,1,gen_server}}]}},
+ {american_behavior3,
+ <<"-behavior(gen_server).
+ -behavior(supervisor).
+ -export([handle_call/3,handle_cast/2,handle_info/2]).
+ handle_call(_, _, _) -> ok.
+ handle_cast(_, _) -> ok.
+ handle_info(_, _) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,
+ {undefined_behaviour_func,{code_change,3},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{init,1},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{terminate,2},gen_server}},
+ {2,erl_lint,{undefined_behaviour_func,{init,1},supervisor}},
+ {2,
+ erl_lint,
+ {conflicting_behaviours,{init,1},supervisor,1,gen_server}}]}},
+
+ {behaviour4,
+ <<"-behaviour(gen_server).
+ -behaviour(gen_fsm).
+ -behaviour(supervisor).
+ -export([init/1,handle_call/3,handle_cast/2,
+ handle_info/2,handle_info/3,
+ handle_event/3,handle_sync_event/4,
+ code_change/3,code_change/4,
+ terminate/2,terminate/3,terminate/4]).
+ init(_) -> ok.
+ handle_call(_, _, _) -> ok.
+ handle_event(_, _, _) -> ok.
+ handle_sync_event(_, _, _, _) -> ok.
+ handle_cast(_, _) -> ok.
+ handle_info(_, _) -> ok.
+ handle_info(_, _, _) -> ok.
+ code_change(_, _, _) -> ok.
+ code_change(_, _, _, _) -> ok.
+ terminate(_, _) -> ok.
+ terminate(_, _, _) -> ok.
+ terminate(_, _, _, _) -> ok.
+ ">>,
+ [],
+ {warnings,[{2,
+ erl_lint,
+ {conflicting_behaviours,{init,1},gen_fsm,1,gen_server}},
+ {3,
+ erl_lint,
+ {conflicting_behaviours,{init,1},supervisor,1,gen_server}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_7550(doc) ->
+ "Test that the new utf8/utf16/utf32 types do not allow size or unit specifiers.";
+otp_7550(Config) when is_list(Config) ->
+ Ts = [{otp_7550,
+ <<"f8(A) ->
+ <<A:8/utf8>>.
+ g8(A) ->
+ <<A:8/utf8-unit:1>>.
+ h8(A) ->
+ <<A/utf8-unit:1>>.
+
+ f16(A) ->
+ <<A:8/utf16>>.
+ g16(A) ->
+ <<A:8/utf16-unit:1>>.
+ h16(A) ->
+ <<A/utf16-unit:1>>.
+
+ f32(A) ->
+ <<A:8/utf32>>.
+ g32(A) ->
+ <<A:8/utf32-unit:1>>.
+ h32(A) ->
+ <<A/utf32-unit:1>>.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,utf_bittype_size_or_unit},
+ {4,erl_lint,utf_bittype_size_or_unit},
+ {6,erl_lint,utf_bittype_size_or_unit},
+ {9,erl_lint,utf_bittype_size_or_unit},
+ {11,erl_lint,utf_bittype_size_or_unit},
+ {13,erl_lint,utf_bittype_size_or_unit},
+ {16,erl_lint,utf_bittype_size_or_unit},
+ {18,erl_lint,utf_bittype_size_or_unit},
+ {20,erl_lint,utf_bittype_size_or_unit}
+ ],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+
+otp_8051(doc) ->
+ "Bugfix: -opaque with invalid type.";
+otp_8051(Config) when is_list(Config) ->
+ Ts = [{otp_8051,
+ <<"-opaque foo() :: bar().
+ ">>,
+ [],
+ {error,[{1,erl_lint,{type_ref,{bar,0}}}],
+ [{1,erl_lint,{unused_type,{foo,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+format_warn(doc) ->
+ "Check that format warnings are generated.";
+format_warn(suite) -> [];
+format_warn(Config) when is_list(Config) ->
+ L1 = 14,
+ L2 = 4,
+ format_level(1, L1, Config),
+ format_level(2, L1+L2, Config),
+ format_level(3, L1+L2, Config), %there is no level 3
+ ok.
+
+format_level(Level, Count, Config) ->
+ ?line W = get_compilation_warnings(Config, "format",
+ [{warn_format, Level}]),
+ %% Pick out the 'format' warnings.
+ ?line FW = lists:filter(fun({_Line, erl_lint, {format_error, _}}) -> true;
+ (_) -> false
+ end,
+ W),
+ ?line case length(FW) of
+ Count ->
+ ok;
+ Other ->
+ ?t:format("Expected ~w warning(s); got ~w", [Count,Other]),
+ fail()
+ end,
+ ok.
+
+%% Test the -on_load(Name/0) directive.
+
+on_load(suite) ->
+ [on_load_successful, on_load_failing].
+
+on_load_successful(Config) when is_list(Config) ->
+ Ts = [{on_load_1,
+ %% Exported on_load function.
+ <<"-export([do_on_load/0]).
+ -on_load(do_on_load/0).
+ do_on_load() -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []},
+
+ {on_load_2,
+ %% Local on_load function.
+ <<"-on_load(do_on_load/0).
+ do_on_load() -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []},
+
+ {on_load_3,
+ %% Local on_load function, calling other local functions.
+ <<"-on_load(do_on_load/0).
+ do_on_load() -> foo().
+ foo() -> bar(5) + 42.
+ bar(N) -> 2*N.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+on_load_failing(Config) when is_list(Config) ->
+ Ts = [{on_load_1,
+ %% Badly formed.
+ <<"-on_load(atom).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{bad_on_load,atom}}],[]}},
+
+ {on_load_2,
+ %% Badly formed.
+ <<"-on_load({42,0}).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{bad_on_load,{42,0}}}],[]}},
+
+ {on_load_3,
+ %% Multiple on_load attributes.
+ <<"-on_load(foo/0).
+ -on_load(bar/0).
+ foo() -> ok.
+ bar() -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{2,erl_lint,multiple_on_loads}],[]}},
+
+ {on_load_4,
+ %% Wrong arity.
+ <<"-on_load(foo/1).
+ foo(_) -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{bad_on_load_arity,{foo,1}}}],[]}},
+
+ {on_load_5,
+ %% Non-existing function.
+ <<"-on_load(non_existing/0).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{undefined_on_load,{non_existing,0}}}],[]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+run(Config, Tests) ->
+ F = fun({N,P,Ws,E}, BadL) ->
+ case catch run_test(Config, P, Ws) of
+ E ->
+ BadL;
+ Bad ->
+ ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ "but got~n ~p~n", [N, E, Bad]),
+ fail()
+ end
+ end,
+ lists:foldl(F, [], Tests).
+
+%% Compiles a test file and returns the list of warnings.
+
+get_compilation_warnings(Conf, Filename, Warnings) ->
+ ?line DataDir = ?datadir,
+ ?line File = filename:join(DataDir, Filename),
+ {ok,Bin} = file:read_file(File++".erl"),
+ FileS = binary_to_list(Bin),
+ {match,[{Start,Length}|_]} = re:run(FileS, "-module.*\\n"),
+ Test = lists:nthtail(Start+Length, FileS),
+ {warnings, Ws} = run_test(Conf, Test, Warnings),
+ Ws.
+
+%% Compiles a test module and returns the list of errors and warnings.
+
+run_test(Conf, Test0, Warnings0) ->
+ Test = list_to_binary(["-module(lint_test). ", Test0]),
+ run_test2(Conf, Test, Warnings0).
+
+run_test2(Conf, Test, Warnings0) ->
+ Filename = 'lint_test.erl',
+ DataDir = ?privdir,
+ File = filename:join(DataDir, Filename),
+ Opts = case Warnings0 of
+ {Warnings} -> %Hairy trick to not add export_all.
+ [return|Warnings];
+ Warnings ->
+ [export_all,return|Warnings]
+ end,
+ ok = file:write_file(File, Test),
+
+ %% We will use the 'binary' option so that the compiler will not
+ %% compare the module name to the output file name. Also, there
+ %% is no reason to produce an output file since we are only
+ %% interested in the errors and warnings.
+
+ %% Print warnings, call erl_lint:format_error/1.
+ compile:file(File, [binary,report|Opts]),
+
+ case compile:file(File, [binary|Opts]) of
+ {ok, _M, Code, Ws} when is_binary(Code) -> warnings(File, Ws);
+ {error, [{File,Es}], []} -> {errors, Es, []};
+ {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws};
+ {error, [{File,Es1},{File,Es2}], []} -> {errors2, Es1, Es2}
+ end.
+
+warnings(File, Ws) ->
+ case lists:append([W || {F, W} <- Ws, F =:= File]) of
+ [] -> [];
+ L -> {warnings, L}
+ end.
+
+fail() ->
+ io:format("failed~n"),
+ ?t:fail().