summaryrefslogtreecommitdiff
path: root/lib/stdlib/test/erl_lint_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/test/erl_lint_SUITE.erl')
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl472
1 files changed, 405 insertions, 67 deletions
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 770e12e3f0..81bc3e9a0d 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2022. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2023. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,7 +35,8 @@
-export([all/0, suite/0, groups/0]).
--export([unused_vars_warn_basic/1,
+-export([singleton_type_var_errors/1,
+ unused_vars_warn_basic/1,
unused_vars_warn_lc/1,
unused_vars_warn_rec/1,
unused_vars_warn_fun/1,
@@ -49,7 +50,8 @@
unsafe_vars_try/1,
unsized_binary_in_bin_gen_pattern/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_5362/1, otp_5371/1, otp_7227/1, binary_aliases/1,
+ otp_5494/1, otp_5644/1, otp_5878/1,
otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1,
otp_11772/1, otp_11771/1, otp_11872/1,
export_all/1,
@@ -78,7 +80,9 @@
underscore_match/1,
unused_record/1,
unused_type2/1,
- eep49/1]).
+ eep49/1,
+ redefined_builtin_type/1,
+ tilde_k/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -90,7 +94,7 @@ all() ->
unsafe_vars, unsafe_vars2, unsafe_vars_try, guard,
unsized_binary_in_bin_gen_pattern,
otp_4886, otp_4988, otp_5091, otp_5276, otp_5338,
- otp_5362, otp_5371, otp_7227, otp_5494, otp_5644,
+ otp_5362, otp_5371, otp_7227, binary_aliases, otp_5494, otp_5644,
otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, otp_11254,
otp_11772, otp_11771, otp_11872, export_all,
bif_clash, behaviour_basic, behaviour_multiple, otp_11861,
@@ -106,7 +110,10 @@ all() ->
no_load_nif,
inline_nifs, warn_missing_spec, otp_16824,
underscore_match, unused_record, unused_type2,
- eep49].
+ eep49,
+ redefined_builtin_type,
+ tilde_k,
+ singleton_type_var_errors].
groups() ->
[{unused_vars_warn, [],
@@ -166,7 +173,13 @@ c(A) ->
g({M, F}) -> (Z=M):(Z=F)();
g({M, F, Arg}) -> (Z=M):F(Z=Arg).
h(X, Y) -> (Z=X) + (Z=Y).">>,
- [warn_unused_vars], []}],
+ [warn_unused_vars], []},
+ {basic3,
+ <<"f(E) ->
+ X = Y = E.">>,
+ [warn_unused_vars],
+ {warnings,[{{2,19},erl_lint,{unused_var,'X'}},
+ {{2,23},erl_lint,{unused_var,'Y'}}]}}],
[] = run(Config, Ts),
ok.
@@ -297,7 +310,7 @@ unused_vars_warn_lc(Config) when is_list(Config) ->
j(X) ->
[foo || X <- X, % X shadowed.
X <- % X shadowed. X unused.
- X =
+ X =
Y = [[1,2,3]], % Y unused.
X <- [], % X shadowed.
X <- X]. % X shadowed. X unused.
@@ -892,6 +905,126 @@ unused_import(Config) when is_list(Config) ->
[] = run(Config, Ts),
ok.
+%% Test singleton type variables
+singleton_type_var_errors(Config) when is_list(Config) ->
+ Ts = [{singleton_error1,
+ <<"-spec test_singleton_typevars_in_union(Opts) -> term() when
+ Opts :: {ok, Unknown} | {error, Unknown}.
+ test_singleton_typevars_in_union(_) ->
+ error.
+ ">>,
+ [],
+ {warnings,[{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]}},
+
+ {singleton_error2,
+ <<"-spec test_singleton_list_typevars_in_union([Opts]) -> term() when
+ Opts :: {ok, Unknown} | {error, Unknown}.
+ test_singleton_list_typevars_in_union(_) ->
+ error.">>,
+ [],
+ {warnings,[{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]}},
+
+ {singleton_error3,
+ <<"-spec test_singleton_list_typevars_in_list([Opts]) -> term() when
+ Opts :: {ok, Unknown}.
+ test_singleton_list_typevars_in_list(_) ->
+ error.">>,
+ [],
+ {errors,
+ [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}],[]}},
+
+ {singleton_error4,
+ <<"-spec test_singleton_list_typevars_in_list_with_type_subst([{ok, Unknown}]) -> term().
+ test_singleton_list_typevars_in_list_with_type_subst(_) ->
+ error.">>,
+ [],
+ {errors,[{{1,86},erl_lint,{singleton_typevar,'Unknown'}}],[]}},
+
+ {singleton_error5,
+ <<"-spec test_singleton_buried_typevars_in_union(Opts) -> term() when
+ Opts :: {ok, Foo} | {error, Foo},
+ Foo :: {true, X} | {false, X}.
+ test_singleton_buried_typevars_in_union(_) ->
+ error.">>,
+ [],
+ {warnings,[{{3,38},erl_lint,{singleton_typevar,'X'}}]}},
+
+ {singleton_error6,
+ <<"-spec test_multiple_subtypes_to_same_typevar(Opts) -> term() when
+ Opts :: {Foo, Bar} | Y,
+ Foo :: X,
+ Bar :: X,
+ Y :: Z.
+ test_multiple_subtypes_to_same_typevar(_) ->
+ error.">>,
+ [],
+ {errors,[{{5,31},erl_lint,{singleton_typevar,'Z'}}],[]}},
+
+ {singleton_error7,
+ <<"-spec test_duplicate_non_terminal_var_in_union(Opts) -> term() when
+ Opts :: {ok, U, U} | {error, U, U},
+ U :: Foo.
+ test_duplicate_non_terminal_var_in_union(_) ->
+ error.">>,
+ [],
+ {errors,[{{3,31},erl_lint,{singleton_typevar,'Foo'}}],[]}},
+
+ {singleton_error8,
+ <<"-spec test_unused_outside_union(Opts) -> term() when
+ Unused :: Unknown,
+ A :: Unknown,
+ Opts :: {Unknown | A}.
+ test_unused_outside_union(_) ->
+ error.">>,
+ [],
+ {errors,[{{2,21},erl_lint,{singleton_typevar,'Unused'}}],[]}},
+
+ {singleton_disabled_warning,
+ <<"-spec test_singleton_typevars_in_union(Opts) -> term() when
+ Opts :: {ok, Unknown} | {error, Unknown}.
+ test_singleton_typevars_in_union(_) ->
+ error.
+ ">>,
+ [nowarn_singleton_typevar],
+ []},
+
+ {singleton_ok1,
+ <<"-spec test_multiple_occurrences_singleton(Opts) -> term() when
+ Opts :: {Foo, Foo}.
+ test_multiple_occurrences_singleton(_) ->
+ ok.">>,
+ [],
+ []},
+
+ {singleton_ok2,
+ <<"-spec id(X) -> X.
+ id(X) ->
+ X.">>,
+ [],
+ []},
+
+ {singleton_ok3,
+ <<"-spec ok(Opts) -> term() when
+ Opts :: {Unknown, {ok, Unknown} | {error, Unknown}}.
+ ok(_) ->
+ error.">>,
+ [],
+ []},
+
+ {singleton_ok4,
+ <<"-spec ok(Opts) -> term() when
+ Union :: {ok, Unknown} | {error, Unknown},
+ Opts :: {{tag, Unknown} | Union}.
+ ok(_) ->
+ error.">>,
+ [],
+ []}
+
+ ],
+
+ [] = run(Config, Ts),
+ ok.
+
%% Test warnings for unused functions.
unused_function(Config) when is_list(Config) ->
Ts = [{func1,
@@ -966,13 +1099,13 @@ binary_types(Config) when is_list(Config) ->
Ts = [{binary1,
<<"-type nonempty_binary() :: term().">>,
[nowarn_unused_type],
- {errors,[{{1,22},erl_lint,
- {builtin_type,{nonempty_binary,0}}}],[]}},
+ {warnings,[{{1,22},erl_lint,
+ {redefine_builtin_type,{nonempty_binary,0}}}]}},
{binary2,
<<"-type nonempty_bitstring() :: term().">>,
[nowarn_unused_type],
- {errors,[{{1,22},erl_lint,
- {builtin_type,{nonempty_bitstring,0}}}],[]}}],
+ {warnings,[{{1,22},erl_lint,
+ {redefine_builtin_type,{nonempty_bitstring,0}}}]}}],
[] = run(Config, Ts),
ok.
@@ -2296,22 +2429,22 @@ otp_15456(Config) when is_list(Config) ->
ok.
%% OTP-5371. Aliases for bit syntax expressions are no longer allowed.
+%% GH-6348/OTP-18297: Updated for OTP 26 to allow aliases.
otp_5371(Config) when is_list(Config) ->
Ts = [{otp_5371_1,
<<"t(<<A:8>> = <<B:8>>) ->
{A,B}.
">>,
[],
- {errors,[{{1,23},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,24},erl_lint,illegal_bin_pattern},
- {{3,20},erl_lint,illegal_bin_pattern}],[]}},
+ [],
+ {warnings,[{{3,15},v3_core,{nomatch,pattern}}]}},
{otp_5371_3,
<<"-record(foo, {a,b,c}).
-record(bar, {x,y,z}).
@@ -2328,11 +2461,10 @@ otp_5371(Config) when is_list(Config) ->
{X,Y}.
">>,
[],
- {errors,[{{4,26},erl_lint,illegal_bin_pattern},
- {{6,26},erl_lint,illegal_bin_pattern},
- {{8,26},erl_lint,illegal_bin_pattern},
- {{10,30},erl_lint,illegal_bin_pattern},
- {{12,30},erl_lint,illegal_bin_pattern}],[]}},
+ {warnings,[{{4,15},v3_core,{nomatch,pattern}},
+ {{8,15},v3_core,{nomatch,pattern}},
+ {{10,15},v3_core,{nomatch,pattern}},
+ {{12,15},v3_core,{nomatch,pattern}}]}},
{otp_5371_4,
<<"-record(foo, {a,b,c}).
-record(bar, {x,y,z}).
@@ -2352,42 +2484,41 @@ otp_5371(Config) when is_list(Config) ->
[] = run(Config, Ts),
ok.
-%% OTP_7227. Some aliases for bit syntax expressions were still allowed.
+%% OTP-7227. Some aliases for bit syntax expressions were still allowed.
+%% GH-6348/OTP-18297: Updated for OTP 26 to allow aliases.
otp_7227(Config) when is_list(Config) ->
Ts = [{otp_7227_1,
<<"t([<<A:8>> = {C,D} = <<B:8>>]) ->
{A,B,C,D}.
">>,
[],
- {errors,[{{1,42},erl_lint,illegal_bin_pattern}],[]}},
+ {warnings,[{{1,21},v3_core,{nomatch,pattern}}]}},
{otp_7227_2,
<<"t([(<<A:8>> = {C,D}) = <<B:8>>]) ->
{A,B,C,D}.
">>,
[],
- {errors,[{{1,25},erl_lint,illegal_bin_pattern}],[]}},
+ {warnings,[{{1,21},v3_core,{nomatch,pattern}}]}},
{otp_7227_3,
<<"t([(<<A:8>> = {C,D}) = (<<B:8>> = <<C:8>>)]) ->
{A,B,C,D}.
">>,
[],
- {errors,[{{1,45},erl_lint,illegal_bin_pattern},
- {{1,45},erl_lint,illegal_bin_pattern},
- {{1,55},erl_lint,illegal_bin_pattern}],[]}},
+ {warnings,[{{1,21},v3_core,{nomatch,pattern}}]}},
{otp_7227_4,
<<"t(Val) ->
<<A:8>> = <<B:8>> = Val,
{A,B}.
">>,
[],
- {errors,[{{2,19},erl_lint,illegal_bin_pattern}],[]}},
+ []},
{otp_7227_5,
<<"t(Val) ->
<<A:8>> = X = <<B:8>> = Val,
{A,B,X}.
">>,
[],
- {errors,[{{2,19},erl_lint,illegal_bin_pattern}],[]}},
+ []},
{otp_7227_6,
<<"t(X, Y) ->
<<A:8>> = <<X:4,Y:4>>,
@@ -2401,27 +2532,70 @@ otp_7227(Config) when is_list(Config) ->
{A,B,X}.
">>,
[],
- {errors,[{{2,36},erl_lint,illegal_bin_pattern},
- {{2,36},erl_lint,illegal_bin_pattern},
- {{2,46},erl_lint,illegal_bin_pattern}],[]}},
- {otp_7227_8,
+ []},
+ {otp_7227_8,
<<"t(Val) ->
(<<A:8>> = X) = (Y = <<B:8>>) = Val,
{A,B,X,Y}.
">>,
[],
- {errors,[{{2,40},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,44},erl_lint,illegal_bin_pattern}],[]}}
+ []}
],
[] = run(Config, Ts),
ok.
+%% GH-6348/OTP-18297: Allow aliases of binary patterns.
+binary_aliases(Config) when is_list(Config) ->
+ Ts = [{binary_aliases_1,
+ <<"t([<<Size:8,_/bits>> = <<_:8,Data:Size/bits>>]) ->
+ Data.
+ ">>,
+ [],
+ {errors,[{{1,55},erl_lint,{unbound_var,'Size'}}],[]}},
+ {binary_aliases_2,
+ <<"t(#{key := <<Size:8,_/bits>>} = #{key := <<_:8,Data:Size/bits>>}) ->
+ Data.
+ ">>,
+ [],
+ {errors,[{{1,73},erl_lint,{unbound_var,'Size'}}],[]}},
+ {binary_aliases_3,
+ <<"t(<<_:8,Data:Size/bits>> = <<Size:8,_/bits>>) ->
+ Data.
+ ">>,
+ [],
+ {errors,[{{1,34},erl_lint,{unbound_var,'Size'}}],[]}},
+ {binary_aliases_4,
+ <<"t([<<_:8,Data:Size/bits>> = <<Size:8,_/bits>>]) ->
+ Data.
+ ">>,
+ [],
+ {errors,[{{1,35},erl_lint,{unbound_var,'Size'}}],[]}},
+ {binary_aliases_5,
+ <<"t(Bin) ->
+ <<_:8,A:Size>> = <<_:8,B:Size/bits>> = <<Size:8,_/bits>> = Bin,
+ {A,B,Size}.
+ ">>,
+ [],
+ []},
+ {binary_aliases_6,
+ <<"t(<<_:8,A:Size>> = <<_:8,B:Size/bits>> = <<Size:8,_/bits>>) ->
+ {A,B,Size}.
+ ">>,
+ [],
+ {errors,[{{1,31},erl_lint,{unbound_var,'Size'}},
+ {{1,48},erl_lint,{unbound_var,'Size'}}],
+ []}}
+ ],
+ [] = run(Config, Ts),
+ ok.
+
%% OTP-5494. Warnings for functions exported more than once.
otp_5494(Config) when is_list(Config) ->
Ts = [{otp_5494_1,
@@ -2780,14 +2954,6 @@ otp_10436(Config) when is_list(Config) ->
{warnings,[{{4,14},erl_lint,{not_exported_opaque,{t2,0}}},
{{4,14},erl_lint,{unused_type,{t2,0}}}]} =
run_test2(Config, Ts, []),
- Ts2 = <<"-module(otp_10436_2).
- -export_type([t1/0, t2/0]).
- -opaque t1() :: term().
- -opaque t2() :: any().
- ">>,
- {warnings,[{{3,15},erl_lint,{underspecified_opaque,{t1,0}}},
- {{4,15},erl_lint,{underspecified_opaque,{t2,0}}}]} =
- run_test2(Config, Ts2, []),
ok.
%% OTP-11254. M:F/A could crash the linter.
@@ -2822,9 +2988,9 @@ otp_11772(Config) when is_list(Config) ->
t() ->
1.
">>,
- {errors,[{{7,14},erl_lint,{builtin_type,{node,0}}},
- {{8,14},erl_lint,{builtin_type,{mfa,0}}}],
- []} = run_test2(Config, Ts, []),
+ {warnings,[{{7,14},erl_lint,{redefine_builtin_type,{node,0}}},
+ {{8,14},erl_lint,{redefine_builtin_type,{mfa,0}}}]} =
+ run_test2(Config, Ts, []),
ok.
%% OTP-11771. Do not allow redefinition of the types arity(_) &c..
@@ -2847,11 +3013,11 @@ otp_11771(Config) when is_list(Config) ->
t() ->
1.
">>,
- {errors,[{{7,14},erl_lint,{builtin_type,{arity,0}}},
- {{8,14},erl_lint,{builtin_type,{bitstring,0}}},
- {{9,14},erl_lint,{builtin_type,{iodata,0}}},
- {{10,14},erl_lint,{builtin_type,{boolean,0}}}],
- []} = run_test2(Config, Ts, []),
+ {warnings,[{{7,14},erl_lint,{redefine_builtin_type,{arity,0}}},
+ {{8,14},erl_lint,{redefine_builtin_type,{bitstring,0}}},
+ {{9,14},erl_lint,{redefine_builtin_type,{iodata,0}}},
+ {{10,14},erl_lint,{redefine_builtin_type,{boolean,0}}}]} =
+ run_test2(Config, Ts, []),
ok.
%% OTP-11872. The type map() undefined when exported.
@@ -2863,15 +3029,16 @@ otp_11872(Config) when is_list(Config) ->
-export_type([map/0, product/0]).
- -opaque map() :: dict().
+ -opaque map() :: unknown_type().
-spec t() -> map().
t() ->
1.
">>,
- {errors,[{{6,14},erl_lint,{undefined_type,{product,0}}},
- {{8,14},erl_lint,{builtin_type,{map,0}}}], []} =
+ {error,[{{6,14},erl_lint,{undefined_type,{product,0}}},
+ {{8,30},erl_lint,{undefined_type,{unknown_type,0}}}],
+ [{{8,14},erl_lint,{redefine_builtin_type,{map,0}}}]} =
run_test2(Config, Ts, []),
ok.
@@ -3881,35 +4048,61 @@ maps_type(Config) when is_list(Config) ->
t(M) -> M.
">>,
[],
- {errors,[{{3,7},erl_lint,{builtin_type,{map,0}}}],[]}}],
+ {warnings,[{{3,7},erl_lint,{redefine_builtin_type,{map,0}}}]}}],
[] = run(Config, Ts),
ok.
+%% GH-6348/OTP-18297: In OTP 26 parallel matching of maps
+%% has been extended.
maps_parallel_match(Config) when is_list(Config) ->
- Ts = [{parallel_map_patterns_unbound1,
+ Ts = [{parallel_map_patterns_unbound,
<<"
t(#{} = M) ->
- #{K := V} = #{k := K} = M,
+ #{k := K} = #{K := V} = M,
V.
">>,
[],
- {errors,[{{3,18},erl_lint,{unbound_var,'K'}}],[]}},
- {parallel_map_patterns_unbound2,
+ {errors,[{{3,30},erl_lint,{unbound_var,'K'}}],[]}},
+ {parallel_map_patterns_not_toplevel1,
<<"
t(#{} = M) ->
+ [#{K1 := V1} =
+ #{K2 := V2} =
+ #{k1 := K1,k2 := K2}] = [M],
+ [V1,V2].
+ ">>,
+ [],
+ {errors,[{{3,19},erl_lint,{unbound_var,'K1'}},
+ {{4,19},erl_lint,{unbound_var,'K2'}}],[]}},
+ {parallel_map_patterns_unbound_not_toplevel2,
+ <<"
+ t(#{} = M) ->
+ [#{k := K} = #{K := V}] = [M],
+ V.
+ ">>,
+ [],
+ {errors,[{{3,31},erl_lint,{unbound_var,'K'}}],[]}},
+ {parallel_map_patterns_bound1,
+ <<"
+ t(#{} = M,K1,K2) ->
#{K1 := V1} =
#{K2 := V2} =
#{k1 := K1,k2 := K2} = M,
[V1,V2].
">>,
[],
- {errors,[{{3,18},erl_lint,{unbound_var,'K1'}},
- {{3,18},erl_lint,{unbound_var,'K1'}},
- {{4,18},erl_lint,{unbound_var,'K2'}},
- {{4,18},erl_lint,{unbound_var,'K2'}}],[]}},
- {parallel_map_patterns_bound,
+ []},
+ {parallel_map_patterns_bound2,
<<"
- t(#{} = M,K1,K2) ->
+ t(#{} = M) ->
+ #{K := V} = #{k := K} = M,
+ V.
+ ">>,
+ [],
+ []},
+ {parallel_map_patterns_bound3,
+ <<"
+ t(#{} = M) ->
#{K1 := V1} =
#{K2 := V2} =
#{k1 := K1,k2 := K2} = M,
@@ -4248,8 +4441,8 @@ otp_14323(Config) ->
-dialyzer(nowarn_function). % unknown option
-dialyzer(1). % badly formed
- -dialyzer(malformed). % unkonwn option
- -dialyzer({malformed,f/0}). % unkonwn option
+ -dialyzer(malformed). % unknown option
+ -dialyzer({malformed,f/0}). % unknown option
-dialyzer({nowarn_function,a/1}). % undefined function
-dialyzer({nowarn_function,{a,-1}}). % badly formed
@@ -4849,6 +5042,151 @@ eep49(Config) when is_list(Config) ->
[] = run(Config, Ts),
ok.
+%% GH-6132: Allow local redefinition of types.
+redefined_builtin_type(Config) ->
+ Ts = [{redef1,
+ <<"-type nonempty_binary() :: term().
+ -type map() :: {_,_}.">>,
+ [nowarn_unused_type,
+ nowarn_redefined_builtin_type],
+ []},
+ {redef2,
+ <<"-type nonempty_bitstring() :: term().
+ -type map() :: {_,_}.">>,
+ [nowarn_unused_type,
+ {nowarn_redefined_builtin_type,{map,0}}],
+ {warnings,[{{1,22},erl_lint,
+ {redefine_builtin_type,{nonempty_bitstring,0}}}]}},
+ {redef3,
+ <<"-compile({nowarn_redefined_builtin_type,{map,0}}).
+ -compile({nowarn_redefined_builtin_type,[{nonempty_bitstring,0}]}).
+ -type nonempty_bitstring() :: term().
+ -type map() :: {_,_}.
+ -type list() :: erlang:map().">>,
+ [nowarn_unused_type,
+ {nowarn_redefined_builtin_type,{map,0}}],
+ {warnings,[{{5,16},erl_lint,
+ {redefine_builtin_type,{list,0}}}]}},
+ {redef4,
+ <<"-type tuple() :: 'tuple'.
+ -type map() :: 'map'.
+ -type list() :: 'list'.
+ -spec t(tuple() | map()) -> list().
+ t(_) -> ok.
+ ">>,
+ [],
+ {warnings,[{{1,22},erl_lint,{redefine_builtin_type,{tuple,0}}},
+ {{2,16},erl_lint,{redefine_builtin_type,{map,0}}},
+ {{3,16},erl_lint,{redefine_builtin_type,{list,0}}}
+ ]}},
+ {redef5,
+ <<"-type atom() :: 'atom'.
+ -type integer() :: 'integer'.
+ -type reference() :: 'ref'.
+ -type pid() :: 'pid'.
+ -type port() :: 'port'.
+ -type float() :: 'float'.
+ -type iodata() :: 'iodata'.
+ -type ref_set() :: gb_sets:set(reference()).
+ -type pid_map() :: #{pid() => port()}.
+ -type atom_int_fun() :: fun((atom()) -> integer()).
+ -type collection(Type) :: {'collection', Type}.
+ -callback b1(I :: iodata()) -> atom().
+ -spec t(collection(float())) -> {pid_map(), ref_set(), atom_int_fun()}.
+ t(_) -> ok.
+ ">>,
+ [],
+ {warnings,[{{1,22},erl_lint,{redefine_builtin_type,{atom,0}}},
+ {{2,16},erl_lint,{redefine_builtin_type,{integer,0}}},
+ {{3,16},erl_lint,{redefine_builtin_type,{reference,0}}},
+ {{4,16},erl_lint,{redefine_builtin_type,{pid,0}}},
+ {{5,16},erl_lint,{redefine_builtin_type,{port,0}}},
+ {{6,16},erl_lint,{redefine_builtin_type,{float,0}}},
+ {{7,16},erl_lint,{redefine_builtin_type,{iodata,0}}}
+ ]}},
+ {redef6,
+ <<"-spec bar(function()) -> bar().
+ bar({function, F}) -> F().
+ -type function() :: {function, fun(() -> bar())}.
+ -type bar() :: {bar, binary()}.
+ ">>,
+ [],
+ {warnings,[{{3,16},erl_lint,
+ {redefine_builtin_type,{function,0}}}]}},
+ {redef7,
+ <<"-type function() :: {function, fun(() -> bar())}.
+ -type bar() :: {bar, binary()}.
+ -spec bar(function()) -> bar().
+ bar({function, F}) -> F().
+ ">>,
+ [],
+ {warnings,[{{1,22},erl_lint,
+ {redefine_builtin_type,{function,0}}}]}},
+ {redef8,
+ <<"-type function() :: {function, fun(() -> atom())}.
+ ">>,
+ [],
+ {warnings,[{{1,22},erl_lint,
+ {redefine_builtin_type,{function,0}}},
+ {{1,22},erl_lint,
+ {unused_type,{function,0}}}]}},
+ {redef9,
+ <<"-spec foo() -> fun().
+ foo() -> fun() -> ok end.
+ ">>,
+ [],
+ []}
+ ],
+ [] = run(Config, Ts),
+ ok.
+
+tilde_k(Config) ->
+ Ts = [{tilde_k_1,
+ <<"t(Map) ->
+ io:format(\"~kp\n\", [Map]),
+ io:format(\"~kP\n\", [Map,10]),
+ io:format(\"~kw\n\", [Map]),
+ io:format(\"~kW\n\", [Map,5]),
+ io:format(\"~tkp\n\", [Map]),
+ io:format(\"~klp\n\", [Map]),
+ RevCmpFun = fun erlang:'>='/2,
+ io:format(\"~Kp\n\", [RevCmpFun,Map]),
+ io:format(\"~KP\n\", [RevCmpFun,Map,10]),
+ io:format(\"~Kw\n\", [RevCmpFun,Map]),
+ io:format(\"~KW\n\", [RevCmpFun,Map,5]),
+ ok.">>,
+ [],
+ []},
+ {tilde_k_2,
+ <<"t(Map) ->
+ io:format(\"~kkp\n\", [Map]),
+ io:format(\"~kKp\n\", [Map]),
+ io:format(\"~ks\n\", [Map]),
+ ok.">>,
+ [],
+ {warnings,
+ [{{2,29},
+ erl_lint,
+ {format_error,{"format string invalid (~ts)",
+ ["repeated modifier k"]}}},
+ {{4,29},
+ erl_lint,
+ {format_error,{"format string invalid (~ts)",
+ ["conflicting modifiers ~Kkp"]}}},
+ {{6,29},
+ erl_lint,
+ {format_error,{"format string invalid (~ts)",
+ ["invalid modifier/control combination ~ks"]}}}]}
+ }
+ ],
+ [] = run(Config, Ts),
+
+ ok.
+
+%%%
+%%% Common utilities.
+%%%
+
format_error(E) ->
lists:flatten(erl_lint:format_error(E)).