diff options
Diffstat (limited to 'lib/stdlib/test/erl_pp_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/erl_pp_SUITE.erl | 196 |
1 files changed, 155 insertions, 41 deletions
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index a103f6dc53..c0cfd26925 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2016. All Rights Reserved. +%% Copyright Ericsson AB 2006-2019. 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. @@ -47,11 +47,12 @@ hook/1, neg_indent/1, maps_syntax/1, + quoted_atom_types/1, otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1, otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1, otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1, - otp_13662/1]). + otp_13662/1, otp_14285/1, otp_15592/1, otp_15751/1, otp_15755/1]). %% Internal export. -export([ehook/6]). @@ -74,13 +75,14 @@ groups() -> [{expr, [], [func, call, recs, try_catch, if_then, receive_after, bits, head_tail, cond1, block, case1, ops, - messages, maps_syntax + messages, maps_syntax, quoted_atom_types ]}, {attributes, [], [misc_attrs, import_export, dialyzer_attrs]}, {tickets, [], [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238, otp_8473, otp_8522, otp_8567, otp_8664, otp_9147, - otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662]}]. + otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662, + otp_14285, otp_15592, otp_15751, otp_15755]}]. init_per_suite(Config) -> Config. @@ -472,10 +474,10 @@ cond1(Config) when is_list(Config) -> [{tuple,5,[{atom,5,x},{atom,5,y}]}]}]}, CChars = flat_expr1(C), "cond\n" - " {foo,bar} ->\n" - " [a,b];\n" + " {foo, bar} ->\n" + " [a, b];\n" " true ->\n" - " {x,y}\n" + " {x, y}\n" "end" = CChars, ok. @@ -627,11 +629,6 @@ do_hook(HookFun) -> true = "{some,value}" =:= lists:flatten(erl_pp:expr({value,A0,{some,value}})), - %% Silly... - true = - "if true -> 0 end" =:= - flat_expr({'if',0,[{clause,0,[],[],[{atom,0,0}]}]}), - %% More compatibility: before R6 OldIf = {'if',A0,[{clause,A0,[],[{atom,A0,true}],[{atom,A0,b}]}]}, NewIf = {'if',A0,[{clause,A0,[],[[{atom,A0,true}]],[{atom,A0,b}]}]}, @@ -715,7 +712,7 @@ otp_6321(Config) when is_list(Config) -> Str = "S = hopp, {hej, S}. ", {done, {ok, Tokens, _EndLine}, ""} = erl_scan:tokens("", Str, _L=1), {ok, Exprs} = erl_parse:parse_exprs(Tokens), - "S = hopp, {hej,S}" = lists:flatten(erl_pp:exprs(Exprs)), + "S = hopp, {hej, S}" = lists:flatten(erl_pp:exprs(Exprs)), ok. %% OTP_6911. More newlines. @@ -825,13 +822,14 @@ type_examples() -> %% is_subtype(V, T) syntax, we need a few examples of the syntax. {ex31,<<"-spec t1(FooBar :: t99()) -> t99();" "(t2()) -> t2();" - "('\\'t::4'()) -> '\\'t::4'() when is_subtype('\\'t::4'(), t24);" - "(t23()) -> t23() when is_subtype(t23(), atom())," - " is_subtype(t23(), t14());" - "(t24()) -> t24() when is_subtype(t24(), atom())," - " is_subtype(t24(), t14())," - " is_subtype(t24(), '\\'t::4'()).">>}, - {ex32,<<"-spec mod:t2() -> any(). ">>}, + "('\\'t::4'()) -> {'\\'t::4'(), B}" + " when is_subtype(B, '\\'t::4'());" + "(t23()) -> C when is_subtype(C, atom())," + " is_subtype(C, t14());" + "(t24()) -> D when is_subtype(D, atom())," + " is_subtype(D, t14())," + " is_subtype(D, '\\'t::4'()).">>}, + {ex32,<<"-spec erl_pp_test:t2() -> any(). ">>}, {ex33,<<"-opaque attributes_data() :: " "[{'column', column()} | {'line', info_line()} |" " {'text', string()}] | {line(),column()}. ">>}, @@ -915,6 +913,21 @@ maps_syntax(Config) when is_list(Config) -> ok = pp_forms(F), ok. +quoted_atom_types(Config) when is_list(Config) -> + Q = [{quote_singleton_atom_types, true}], + U = [{encoding,unicode}], + L = [{encoding,latin1}], + F = "-type t() :: a | a().", + "-type t() :: 'a' | a().\n" = + lists:flatten(parse_and_pp_forms(F, Q ++ L)), + "-type t() :: 'a' | a().\n" = + lists:flatten(parse_and_pp_forms(F, Q ++ U)), + UF = "-type t() :: '\x{400}' | '\x{400}'().", + "-type t() :: '\\x{400}' | '\\x{400}'().\n" = + lists:flatten(parse_and_pp_forms(UF, Q ++ L)), + "-type t() :: '\x{400}' | '\x{400}'().\n" = + lists:flatten(parse_and_pp_forms(UF, Q ++ U)), + ok. %% OTP_8567. Avoid duplicated 'undefined' in record field types. otp_8567(Config) when is_list(Config) -> @@ -1067,9 +1080,6 @@ otp_11100(Config) when is_list(Config) -> %% There are a few places where the added code ("options(none)") %% doesn't make a difference (pp:bit_elem_type/1 is an example). - %% Cannot trigger the use of the hook function with export/import. - "-export([{fy,a}/b]).\n" = - pf({attribute,1,export,[{{fy,a},b}]}), A1 = erl_anno:new(1), "-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" = pf({attribute,A1,type,{foo,{type,A1,integer,[{foo,bar}]},[]}}), @@ -1099,10 +1109,11 @@ otp_11100(Config) when is_list(Config) -> %% OTP-11861. behaviour_info() and -callback. otp_11861(Config) when is_list(Config) -> + A3 = erl_anno:new(3), "-optional_callbacks([bar/0]).\n" = - pf({attribute,3,optional_callbacks,[{bar,0}]}), - "-optional_callbacks([{bar,1,bad}]).\n" = - pf({attribute,4,optional_callbacks,[{bar,1,bad}]}), + pf({attribute,A3,optional_callbacks,[{bar,0}]}), + "-optional_callbacks([{bar, 1, bad}]).\n" = + pf({attribute,A3,optional_callbacks,[{bar,1,bad}]}), ok. pf(Form) -> @@ -1144,6 +1155,112 @@ otp_13662(Config) -> ], compile(Config, Ts). +otp_14285(_Config) -> + pp_forms(<<"-export([t/0, '\\x{400}\\''/0]).">>), + pp_forms(<<"-import(lists, [append/2]).">>), + pp_forms(<<"-optional_callbacks([]).">>), + pp_forms(<<"-optional_callbacks(['\\x{400}\\''/1]).">>), + pp_forms(<<"-'\\x{400}\\''('\\x{400}\\'').">>), + pp_forms(<<"-type '\\x{400}\\''() :: '\\x{400}\\''.">>), + pp_forms(<<"-record('\\x{400}\\'', {'\\x{400}\\''}).">>), + pp_forms(<<"-callback '\\x{400}\\''(_) -> '\\x{400}\\''.">>), + pp_forms(<<"t() -> '\\x{400}\\''('\\x{400}\\'').">>), + pp_forms(<<"'\\x{400}\\''(_) -> '\\x{400}\\''.">>), + pp_forms(<<"-spec '\\x{400}'() -> " + "#'\\x{400}'{'\\x{400}' :: '\\x{400}'}.">>), + pp_forms(<<"'\\x{400}\\''() ->" + "R = #'\\x{400}\\''{}," + "#'\\x{400}\\''{'\\x{400}\\'' =" + "{'\\x{400}\\''," + "fun '\\x{400}\\''/0," + "R#'\\x{400}\\''.'\\x{400}\\''," + "#'\\x{400}\\''.'\\x{400}\\''}}.">>), + + %% Special... + true = + "{some,'\\x{400}\\''}" =:= + lists:flatten(erl_pp:expr({value,erl_anno:new(0),{some,'\x{400}\''}}, + [{encoding,latin1}])), + ok. + +otp_15592(_Config) -> + ok = pp_expr(<<"long12345678901234567890123456789012345678901234" + "56789012345678901234:f(<<>>)">>), + ok. + +otp_15751(_Config) -> + ok = pp_expr(<<"try foo:bar() + catch + Reason : Stacktrace -> + {Reason, Stacktrace} + end">>), + ok = pp_expr(<<"try foo:bar() + catch + throw: Reason : Stacktrace -> + {Reason, Stacktrace} + end">>), + ok = pp_expr(<<"try foo:bar() + catch + Reason : _ -> + Reason + end">>), + ok = pp_expr(<<"try foo:bar() + catch + throw: Reason : _ -> + Reason + end">>), + ok = pp_expr(<<"try foo:bar() + catch + Reason -> + Reason + end">>), + ok = pp_expr(<<"try foo:bar() + catch + throw: Reason -> + Reason + end">>), + ok. + +otp_15755(_Config) -> + "[{a, b}, c, {d, e} | t]" = + flat_parse_and_pp_expr("[{a, b}, c, {d, e} | t]", 0, []), + "[{a, b},\n c, d,\n {d, e},\n 1, 2.0,\n {d, e},\n <<>>, {},\n {d, e},\n" + " [], [],\n {d, e} |\n t]" = + flat_parse_and_pp_expr("[{a,b},c,d,{d,e},1,2.0,{d,e},<<>>," + "{},{d,e},[],[],{d,e}|t]", 0, []), + "[{a, b},\n c, d,\n {d, e},\n 1, 2.0,\n {d, e},\n <<>>, {},\n {d, e},\n" + " [], [], d, e | t]" = + flat_parse_and_pp_expr("[{a,b},c,d,{d,e},1,2.0,{d,e},<<>>," + "{},{d,e},[],[],d,e|t]", 0, []), + + "-type t() :: + a | b | c | a | b | a | b | a | b | a | b | a | b | a | b | + a | b | a | b | a | b.\n" = + lists:flatten(parse_and_pp_forms( + "-type t() :: a | b | c| a | b | a | b | a | b | a |" + " b | a | b | a | b | a | b | a | b |a | b.", [])), + + "-type t() :: + {dict, 0, 16, 16, 8, 80, 48, + {[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], + []}, + {{[], [], [], [], [], [], [], [], [], [], [], [], [], [], []}}}.\n" = + lists:flatten(parse_and_pp_forms( + "-type t() :: {dict,0,16,16,8,80,48," + "{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}," + "{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}.", [])), + + "-type t() :: + {{a}, + 0, 16, + {16}, + 8, 80, 48, a, b, e, f, 'sf s sdf', [], {}, + {[]}}.\n" = + lists:flatten(parse_and_pp_forms( + "-type t() :: {{a}, 0, 16, {16}, 8, 80, 48, a, b, e, f," + " 'sf s sdf', [], {}, {[]}}.", [])), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% compile(Config, Tests) -> @@ -1166,19 +1283,21 @@ compile(Config, Tests) -> lists:foldl(F, [], Tests). compile_file(Config, Test0) -> - case compile_file(Config, Test0, ['E']) of + Test = ["-module(erl_pp_test).\n", + "-compile(export_all).\n", + Test0], + case compile_file(Config, Test, ['E']) of {ok, RootFile} -> File = RootFile ++ ".E", {ok, Bin0} = file:read_file(File), - Bin = strip_module_info(Bin0), %% A very simple check: just try to compile the output. - case compile_file(Config, Bin, []) of + case compile_file(Config, Bin0, []) of {ok, RootFile2} -> File2 = RootFile2 ++ ".E", {ok, Bin1} = file:read_file(File2), case Bin0 =:= Bin1 of true -> - test_max_line(binary_to_list(Bin)); + test_max_line(binary_to_list(Bin0)); false -> {error, file_contents_modified, {Bin0, Bin1}} end; @@ -1189,11 +1308,8 @@ compile_file(Config, Test0) -> Error end. -compile_file(Config, Test0, Opts0) -> +compile_file(Config, Test, Opts0) -> FileName = filename('erl_pp_test.erl', Config), - Test = list_to_binary(["-module(erl_pp_test). " - "-compile(export_all). ", - Test0]), Opts = [export_all,return,nowarn_unused_record,{outdir,?privdir} | Opts0], ok = file:write_file(FileName, Test), case compile:file(FileName, Opts) of @@ -1202,11 +1318,6 @@ compile_file(Config, Test0, Opts0) -> Error -> Error end. -strip_module_info(Bin) -> - {match, [{Start,_Len}|_]} = re:run(Bin, "module_info"), - <<R:Start/binary,_/binary>> = Bin, - R. - flat_expr1(Expr0) -> Expr = erl_parse:new_anno(Expr0), lists:flatten(erl_pp:expr(Expr)). @@ -1245,7 +1356,7 @@ parse_forms(Chars) -> parse_forms2([], _Cont, _Line, Forms) -> lists:reverse(Forms); parse_forms2(String, Cont0, Line, Forms) -> - case erl_scan:tokens(Cont0, String, Line, [unicode]) of + case erl_scan:tokens(Cont0, String, Line) of {done, {ok, Tokens, EndLine}, Chars} -> {ok, Form} = erl_parse:parse_form(Tokens), parse_forms2(Chars, [], EndLine, [Form | Forms]); @@ -1281,12 +1392,15 @@ pp_expr(List, Options) when is_list(List) -> not_ok end. +flat_parse_and_pp_expr(String, Indent, Options) -> + lists:flatten(parse_and_pp_expr(String, Indent, Options)). + parse_and_pp_expr(String, Indent, Options) -> StringDot = lists:flatten(String) ++ ".", erl_pp:expr(parse_expr(StringDot), Indent, Options). parse_expr(Chars) -> - {ok, Tokens, _} = erl_scan:string(Chars, 1, [unicode]), + {ok, Tokens, _} = erl_scan:string(Chars, 1), {ok, [Expr]} = erl_parse:parse_exprs(Tokens), Expr. |