diff options
Diffstat (limited to 'lib')
59 files changed, 989 insertions, 559 deletions
diff --git a/lib/asn1/doc/src/ref_man.xml b/lib/asn1/doc/src/ref_man.xml index d70e2bc05f..8f380b788c 100644 --- a/lib/asn1/doc/src/ref_man.xml +++ b/lib/asn1/doc/src/ref_man.xml @@ -34,6 +34,5 @@ contains modules with compile-time and runtime support for ASN.1.</p> </description> <xi:include href="asn1ct.xml"/> - <xi:include href="asn1rt.xml"/> </application> diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index d05b8a9530..aa2d224bb4 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -264,9 +264,9 @@ format_error({delete_temp,File,Error}) -> io_lib:format("failed to delete temporary file ~ts: ~ts", [File,file:format_error(Error)]); format_error({parse_transform,M,R}) -> - io_lib:format("error in parse transform '~s': ~tp", [M, R]); + io_lib:format("error in parse transform '~ts': ~tp", [M, R]); format_error({undef_parse_transform,M}) -> - io_lib:format("undefined parse transform '~s'", [M]); + io_lib:format("undefined parse transform '~ts'", [M]); format_error({core_transform,M,R}) -> io_lib:format("error in core transform '~s': ~tp", [M, R]); format_error({crash,Pass,Reason}) -> diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 30ee782fe9..164f43dcb0 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -809,8 +809,15 @@ do_generate({ecdh = Type, Curve, Priv, Pub}) -> ct:fail({{crypto, generate_key, [Type, Priv, Curve]}, {expected, Pub}, {got, Other}}) end; do_generate({rsa = Type, Mod, Exp}) -> - {Pub,Priv} = crypto:generate_key(Type, {Mod,Exp}), - do_sign_verify({rsa, sha256, Pub, Priv, rsa_plain()}). + case crypto:info_fips() of + enabled when Mod < 3072 -> + ct:log("SKIP do_generate ~p FIPS=~p, Mod=~p Exp=~p", [Type, enabled, Mod, Exp]), + {skip, "FIPS violation"}; + FIPS -> + ct:log("do_generate ~p FIPS=~p, Mod=~p Exp=~p", [Type, FIPS, Mod, Exp]), + {Pub,Priv} = crypto:generate_key(Type, {Mod,Exp}), + do_sign_verify({rsa, sha256, Pub, Priv, rsa_plain()}) + end. notsup(Fun, Args) -> Result = @@ -1159,7 +1166,7 @@ group_config(rsa = Type, Config) -> rsa_oaep(), no_padding() ], - Generate = [{rsa, 2048, 17}, {rsa, 3072, 65537}], + Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}], [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc}, {generate, Generate} | Config]; group_config(dss = Type, Config) -> Msg = dss_plain(), diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index ab137bd170..c319acb2fb 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -111,13 +111,13 @@ get_plt_info([PLT|PLTs]) -> String = case dialyzer_plt:included_files(PLT) of {ok, Files} -> - io_lib:format("The PLT ~s includes the following files:\n~p\n\n", + io_lib:format("The PLT ~ts includes the following files:\n~tp\n\n", [PLT, Files]); {error, read_error} -> - Msg = io_lib:format("Could not read the PLT file ~p\n\n", [PLT]), + Msg = io_lib:format("Could not read the PLT file ~tp\n\n", [PLT]), throw({dialyzer_error, Msg}); {error, no_such_file} -> - Msg = io_lib:format("The PLT file ~p does not exist\n\n", [PLT]), + Msg = io_lib:format("The PLT file ~tp does not exist\n\n", [PLT]), throw({dialyzer_error, Msg}) end, String ++ get_plt_info(PLTs); @@ -126,16 +126,16 @@ get_plt_info([]) -> "". do_print_plt_info(PLTInfo, OutputFile) -> case OutputFile =:= none of true -> - io:format("~s", [PLTInfo]), + io:format("~ts", [PLTInfo]), ?RET_NOTHING_SUSPICIOUS; false -> case file:open(OutputFile, [write]) of {ok, FileDesc} -> - io:format(FileDesc, "~s", [PLTInfo]), + io:format(FileDesc, "~ts", [PLTInfo]), ok = file:close(FileDesc), ?RET_NOTHING_SUSPICIOUS; {error, Reason} -> - Msg1 = io_lib:format("Could not open output file ~p, Reason: ~p\n", + Msg1 = io_lib:format("Could not open output file ~tp, Reason: ~p\n", [OutputFile, Reason]), throw({dialyzer_error, Msg1}) end @@ -264,7 +264,7 @@ cl_halt({ok, R = ?RET_DISCREPANCIES}, #options{output_file = Output}) -> halt(R); cl_halt({error, Msg1}, #options{output_file = Output}) -> %% Msg2 = "dialyzer: Internal problems were encountered in the analysis", - io:format("\ndialyzer: ~s\n", [Msg1]), + io:format("\ndialyzer: ~ts\n", [Msg1]), cl_check_log(Output), halt(?RET_INTERNAL_ERROR). @@ -273,7 +273,7 @@ cl_halt({error, Msg1}, #options{output_file = Output}) -> cl_check_log(none) -> ok; cl_check_log(Output) -> - io:format(" Check output file `~s' for details\n", [Output]). + io:format(" Check output file `~ts' for details\n", [Output]). -spec format_warning(raw_warning() | dial_warning()) -> string(). @@ -291,7 +291,7 @@ format_warning({_Tag, {File, Line}, Msg}, FOpt) when is_list(File), basename -> filename:basename(File) end, String = lists:flatten(message_to_string(Msg)), - lists:flatten(io_lib:format("~s:~w: ~s", [F, Line, String])). + lists:flatten(io_lib:format("~ts:~w: ~ts", [F, Line, String])). %%----------------------------------------------------------------------------- @@ -302,54 +302,55 @@ format_warning({_Tag, {File, Line}, Msg}, FOpt) when is_list(File), %%----- Warnings for general discrepancies ---------------- message_to_string({apply, [Args, ArgNs, FailReason, SigArgs, SigRet, Contract]}) -> - io_lib:format("Fun application with arguments ~s ", [Args]) ++ + io_lib:format("Fun application with arguments ~ts ", [Args]) ++ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract); message_to_string({app_call, [M, F, Args, Culprit, ExpectedType, FoundType]}) -> - io_lib:format("The call ~s:~s~s requires that ~s is of type ~s not ~s\n", + io_lib:format("The call ~s:~ts~ts requires that ~ts is of type ~ts not ~ts\n", [M, F, Args, Culprit, ExpectedType, FoundType]); message_to_string({bin_construction, [Culprit, Size, Seg, Type]}) -> io_lib:format("Binary construction will fail since the ~s field ~s in" " segment ~s has type ~s\n", [Culprit, Size, Seg, Type]); message_to_string({call, [M, F, Args, ArgNs, FailReason, SigArgs, SigRet, Contract]}) -> - io_lib:format("The call ~w:~w~s ", [M, F, Args]) ++ + io_lib:format("The call ~w:~tw~ts ", [M, F, Args]) ++ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract); message_to_string({call_to_missing, [M, F, A]}) -> - io_lib:format("Call to missing or unexported function ~w:~w/~w\n", [M, F, A]); + io_lib:format("Call to missing or unexported function ~w:~tw/~w\n", + [M, F, A]); message_to_string({exact_eq, [Type1, Op, Type2]}) -> - io_lib:format("The test ~s ~s ~s can never evaluate to 'true'\n", + io_lib:format("The test ~ts ~s ~ts can never evaluate to 'true'\n", [Type1, Op, Type2]); message_to_string({fun_app_args, [Args, Type]}) -> - io_lib:format("Fun application with arguments ~s will fail" - " since the function has type ~s\n", [Args, Type]); + io_lib:format("Fun application with arguments ~ts will fail" + " since the function has type ~ts\n", [Args, Type]); message_to_string({fun_app_no_fun, [Op, Type, Arity]}) -> - io_lib:format("Fun application will fail since ~s :: ~s" + io_lib:format("Fun application will fail since ~ts :: ~ts" " is not a function of arity ~w\n", [Op, Type, Arity]); message_to_string({guard_fail, []}) -> "Clause guard cannot succeed.\n"; message_to_string({guard_fail, [Arg1, Infix, Arg2]}) -> - io_lib:format("Guard test ~s ~s ~s can never succeed\n", [Arg1, Infix, Arg2]); + io_lib:format("Guard test ~ts ~s ~ts can never succeed\n", [Arg1, Infix, Arg2]); message_to_string({map_update, [Type, Key]}) -> - io_lib:format("A key of type ~s cannot exist " - "in a map of type ~s\n", [Key, Type]); + io_lib:format("A key of type ~ts cannot exist " + "in a map of type ~ts\n", [Key, Type]); message_to_string({neg_guard_fail, [Arg1, Infix, Arg2]}) -> - io_lib:format("Guard test not(~s ~s ~s) can never succeed\n", + io_lib:format("Guard test not(~ts ~s ~ts) can never succeed\n", [Arg1, Infix, Arg2]); message_to_string({guard_fail, [Guard, Args]}) -> - io_lib:format("Guard test ~w~s can never succeed\n", [Guard, Args]); + io_lib:format("Guard test ~w~ts can never succeed\n", [Guard, Args]); message_to_string({neg_guard_fail, [Guard, Args]}) -> - io_lib:format("Guard test not(~w~s) can never succeed\n", [Guard, Args]); + io_lib:format("Guard test not(~w~ts) can never succeed\n", [Guard, Args]); message_to_string({guard_fail_pat, [Pat, Type]}) -> - io_lib:format("Clause guard cannot succeed. The ~s was matched" - " against the type ~s\n", [Pat, Type]); + io_lib:format("Clause guard cannot succeed. The ~ts was matched" + " against the type ~ts\n", [Pat, Type]); message_to_string({improper_list_constr, [TlType]}) -> io_lib:format("Cons will produce an improper list" - " since its 2nd argument is ~s\n", [TlType]); + " since its 2nd argument is ~ts\n", [TlType]); message_to_string({no_return, [Type|Name]}) -> NameString = case Name of [] -> "The created fun "; - [F, A] -> io_lib:format("Function ~w/~w ", [F, A]) + [F, A] -> io_lib:format("Function ~tw/~w ", [F, A]) end, case Type of no_match -> NameString ++ "has no clauses that will ever match\n"; @@ -358,129 +359,129 @@ message_to_string({no_return, [Type|Name]}) -> both -> NameString ++ "has no local return\n" end; message_to_string({record_constr, [RecConstr, FieldDiffs]}) -> - io_lib:format("Record construction ~s violates the" - " declared type of field ~s\n", [RecConstr, FieldDiffs]); + io_lib:format("Record construction ~ts violates the" + " declared type of field ~ts\n", [RecConstr, FieldDiffs]); message_to_string({record_constr, [Name, Field, Type]}) -> - io_lib:format("Record construction violates the declared type for #~w{}" - " since ~s cannot be of type ~s\n", [Name, Field, Type]); + io_lib:format("Record construction violates the declared type for #~tw{}" + " since ~ts cannot be of type ~ts\n", [Name, Field, Type]); message_to_string({record_matching, [String, Name]}) -> - io_lib:format("The ~s violates the" - " declared type for #~w{}\n", [String, Name]); + io_lib:format("The ~ts violates the" + " declared type for #~tw{}\n", [String, Name]); message_to_string({record_match, [Pat, Type]}) -> - io_lib:format("Matching of ~s tagged with a record name violates the declared" - " type of ~s\n", [Pat, Type]); + io_lib:format("Matching of ~ts tagged with a record name violates" + " the declared type of ~ts\n", [Pat, Type]); message_to_string({pattern_match, [Pat, Type]}) -> - io_lib:format("The ~s can never match the type ~s\n", [Pat, Type]); + io_lib:format("The ~ts can never match the type ~ts\n", [Pat, Type]); message_to_string({pattern_match_cov, [Pat, Type]}) -> - io_lib:format("The ~s can never match since previous" - " clauses completely covered the type ~s\n", + io_lib:format("The ~ts can never match since previous" + " clauses completely covered the type ~ts\n", [Pat, Type]); message_to_string({unmatched_return, [Type]}) -> - io_lib:format("Expression produces a value of type ~s," + io_lib:format("Expression produces a value of type ~ts," " but this value is unmatched\n", [Type]); message_to_string({unused_fun, [F, A]}) -> - io_lib:format("Function ~w/~w will never be called\n", [F, A]); + io_lib:format("Function ~tw/~w will never be called\n", [F, A]); %%----- Warnings for specs and contracts ------------------- message_to_string({contract_diff, [M, F, _A, Contract, Sig]}) -> - io_lib:format("Type specification ~w:~w~s" - " is not equal to the success typing: ~w:~w~s\n", + io_lib:format("Type specification ~w:~tw~ts" + " is not equal to the success typing: ~w:~tw~ts\n", [M, F, Contract, M, F, Sig]); message_to_string({contract_subtype, [M, F, _A, Contract, Sig]}) -> - io_lib:format("Type specification ~w:~w~s" - " is a subtype of the success typing: ~w:~w~s\n", + io_lib:format("Type specification ~w:~tw~ts" + " is a subtype of the success typing: ~w:~tw~ts\n", [M, F, Contract, M, F, Sig]); message_to_string({contract_supertype, [M, F, _A, Contract, Sig]}) -> - io_lib:format("Type specification ~w:~w~s" - " is a supertype of the success typing: ~w:~w~s\n", + io_lib:format("Type specification ~w:~tw~ts" + " is a supertype of the success typing: ~w:~tw~ts\n", [M, F, Contract, M, F, Sig]); message_to_string({contract_range, [Contract, M, F, ArgStrings, Line, CRet]}) -> - io_lib:format("The contract ~w:~w~s cannot be right because the inferred" - " return for ~w~s on line ~w is ~s\n", + io_lib:format("The contract ~w:~tw~ts cannot be right because the inferred" + " return for ~tw~ts on line ~w is ~ts\n", [M, F, Contract, F, ArgStrings, Line, CRet]); message_to_string({invalid_contract, [M, F, A, Sig]}) -> - io_lib:format("Invalid type specification for function ~w:~w/~w." - " The success typing is ~s\n", [M, F, A, Sig]); + io_lib:format("Invalid type specification for function ~w:~tw/~w." + " The success typing is ~ts\n", [M, F, A, Sig]); message_to_string({contract_with_opaque, [M, F, A, OpaqueType, SigType]}) -> - io_lib:format("The specification for ~w:~w/~w" - " has an opaque subtype ~s which is violated by the" - " success typing ~s\n", [M, F, A, OpaqueType, SigType]); + io_lib:format("The specification for ~w:~tw/~w" + " has an opaque subtype ~ts which is violated by the" + " success typing ~ts\n", [M, F, A, OpaqueType, SigType]); message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) -> - io_lib:format("The specification for ~w:~w/~w states that the function" - " might also return ~s but the inferred return is ~s\n", + io_lib:format("The specification for ~w:~tw/~w states that the function" + " might also return ~ts but the inferred return is ~ts\n", [M, F, A, ExtraRanges, SigRange]); message_to_string({overlapping_contract, [M, F, A]}) -> - io_lib:format("Overloaded contract for ~w:~w/~w has overlapping domains;" + io_lib:format("Overloaded contract for ~w:~tw/~w has overlapping domains;" " such contracts are currently unsupported and are simply ignored\n", [M, F, A]); message_to_string({spec_missing_fun, [M, F, A]}) -> - io_lib:format("Contract for function that does not exist: ~w:~w/~w\n", + io_lib:format("Contract for function that does not exist: ~w:~tw/~w\n", [M, F, A]); %%----- Warnings for opaque type violations ------------------- message_to_string({call_with_opaque, [M, F, Args, ArgNs, ExpArgs]}) -> - io_lib:format("The call ~w:~w~s contains ~s when ~s\n", + io_lib:format("The call ~w:~tw~ts contains ~ts when ~ts\n", [M, F, Args, form_positions(ArgNs), form_expected(ExpArgs)]); message_to_string({call_without_opaque, [M, F, Args, ExpectedTriples]}) -> - io_lib:format("The call ~w:~w~s does not have ~s\n", + io_lib:format("The call ~w:~tw~ts does not have ~ts\n", [M, F, Args, form_expected_without_opaque(ExpectedTriples)]); message_to_string({opaque_eq, [Type, _Op, OpaqueType]}) -> - io_lib:format("Attempt to test for equality between a term of type ~s" - " and a term of opaque type ~s\n", [Type, OpaqueType]); + io_lib:format("Attempt to test for equality between a term of type ~ts" + " and a term of opaque type ~ts\n", [Type, OpaqueType]); message_to_string({opaque_guard, [Arg1, Infix, Arg2, ArgNs]}) -> - io_lib:format("Guard test ~s ~s ~s contains ~s\n", + io_lib:format("Guard test ~ts ~s ~ts contains ~s\n", [Arg1, Infix, Arg2, form_positions(ArgNs)]); message_to_string({opaque_guard, [Guard, Args]}) -> - io_lib:format("Guard test ~w~s breaks the opacity of its argument\n", + io_lib:format("Guard test ~w~ts breaks the opacity of its argument\n", [Guard, Args]); message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) -> Term = if OpaqueType =:= OpaqueTerm -> "the term"; true -> OpaqueTerm end, - io_lib:format("The attempt to match a term of type ~s against the ~s" - " breaks the opacity of ~s\n", [OpaqueType, Pat, Term]); + io_lib:format("The attempt to match a term of type ~s against the ~ts" + " breaks the opacity of ~ts\n", [OpaqueType, Pat, Term]); message_to_string({opaque_neq, [Type, _Op, OpaqueType]}) -> - io_lib:format("Attempt to test for inequality between a term of type ~s" - " and a term of opaque type ~s\n", [Type, OpaqueType]); + io_lib:format("Attempt to test for inequality between a term of type ~ts" + " and a term of opaque type ~ts\n", [Type, OpaqueType]); message_to_string({opaque_type_test, [Fun, Args, Arg, ArgType]}) -> - io_lib:format("The type test ~s~s breaks the opacity of the term ~s~s\n", + io_lib:format("The type test ~ts~ts breaks the opacity of the term ~ts~ts\n", [Fun, Args, Arg, ArgType]); message_to_string({opaque_size, [SizeType, Size]}) -> - io_lib:format("The size ~s breaks the opacity of ~s\n", + io_lib:format("The size ~ts breaks the opacity of ~ts\n", [SizeType, Size]); message_to_string({opaque_call, [M, F, Args, Culprit, OpaqueType]}) -> - io_lib:format("The call ~s:~s~s breaks the opacity of the term ~s :: ~s\n", + io_lib:format("The call ~s:~ts~ts breaks the opacity of the term ~ts :: ~ts\n", [M, F, Args, Culprit, OpaqueType]); %%----- Warnings for concurrency errors -------------------- message_to_string({race_condition, [M, F, Args, Reason]}) -> - io_lib:format("The call ~w:~w~s ~s\n", [M, F, Args, Reason]); + io_lib:format("The call ~w:~tw~ts ~ts\n", [M, F, Args, Reason]); %%----- Warnings for behaviour errors -------------------- message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}) -> - io_lib:format("The inferred return type of ~w/~w (~s) has nothing in common" - " with ~s, which is the expected return type for the callback of" - " ~w behaviour\n", [F, A, ST, CT, B]); + io_lib:format("The inferred return type of ~tw/~w (~ts) has nothing in" + " common with ~ts, which is the expected return type for" + " the callback of the ~w behaviour\n", [F, A, ST, CT, B]); message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}) -> - io_lib:format("The inferred type for the ~s argument of ~w/~w (~s) is" - " not a supertype of ~s, which is expected type for this" + io_lib:format("The inferred type for the ~s argument of ~tw/~w (~ts) is" + " not a supertype of ~ts, which is expected type for this" " argument in the callback of the ~w behaviour\n", [ordinal(N), F, A, ST, CT, B]); message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}) -> - io_lib:format("The return type ~s in the specification of ~w/~w is not a" - " subtype of ~s, which is the expected return type for the" - " callback of ~w behaviour\n", [ST, F, A, CT, B]); + io_lib:format("The return type ~ts in the specification of ~tw/~w is not a" + " subtype of ~ts, which is the expected return type for the" + " callback of the ~w behaviour\n", [ST, F, A, CT, B]); message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]}) -> - io_lib:format("The specified type for the ~s argument of ~w/~w (~s) is" - " not a supertype of ~s, which is expected type for this" + io_lib:format("The specified type for the ~ts argument of ~tw/~w (~ts) is" + " not a supertype of ~ts, which is expected type for this" " argument in the callback of the ~w behaviour\n", [ordinal(N), F, A, ST, CT, B]); message_to_string({callback_missing, [B, F, A]}) -> - io_lib:format("Undefined callback function ~w/~w (behaviour '~w')\n", + io_lib:format("Undefined callback function ~tw/~w (behaviour ~w)\n", [F, A, B]); message_to_string({callback_info_missing, [B]}) -> io_lib:format("Callback info about the ~w behaviour is not available\n", [B]); %%----- Warnings for unknown functions, types, and behaviours ------------- message_to_string({unknown_type, {M, F, A}}) -> - io_lib:format("Unknown type ~w:~w/~w", [M, F, A]); + io_lib:format("Unknown type ~w:~tw/~w", [M, F, A]); message_to_string({unknown_function, {M, F, A}}) -> - io_lib:format("Unknown function ~w:~w/~w", [M, F, A]); + io_lib:format("Unknown function ~w:~tw/~w", [M, F, A]); message_to_string({unknown_behaviour, B}) -> io_lib:format("Unknown behaviour ~w", [B]). diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index 29aa25b98e..2a2dcd55f0 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -287,7 +287,7 @@ compile_and_store(Files, #analysis_state{codeserver = CServer, dict:new(), Files), check_for_duplicate_modules(ModDict); false -> - Msg = io_lib:format("Could not scan the following file(s):~n~s", + Msg = io_lib:format("Could not scan the following file(s):~n~ts", [[Reason || {_Filename, Reason} <- Failed]]), exit({error, Msg}) end, @@ -683,12 +683,13 @@ dump_callgraph(CallGraph, _State, #analysis{callgraph_file = File}, ".ps") -> Args = "-Gratio=compress -Gsize=\"100,100\"", dialyzer_callgraph:to_ps(CallGraph, File, Args); dump_callgraph(CallGraph, State, #analysis{callgraph_file = File}, _Ext) -> + %% TODO: write the graph, not the ETS table identifiers. case file:open(File, [write]) of {ok, Fd} -> io:format(Fd, "~p", [CallGraph]), ok = file:close(Fd); {error, Reason} -> - Msg = io_lib:format("Could not open output file ~p, Reason: ~p\n", + Msg = io_lib:format("Could not open output file ~tp, Reason: ~p\n", [File, Reason]), send_log(State#analysis_state.parent, Msg) end. diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl index 6387f3d1e4..a83a0bda59 100644 --- a/lib/dialyzer/src/dialyzer_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_callgraph.erl @@ -755,6 +755,7 @@ put_behaviour_api_calls(Calls, -spec to_dot(callgraph(), file:filename()) -> 'ok'. to_dot(#callgraph{digraph = DG, esc = Esc} = CG, File) -> + %% TODO: handle Unicode names. Fun = fun(L) -> case lookup_name(L, CG) of error -> L; @@ -769,9 +770,10 @@ to_dot(#callgraph{digraph = DG, esc = Esc} = CG, File) -> -spec to_ps(callgraph(), file:filename(), string()) -> 'ok'. to_ps(#callgraph{} = CG, File, Args) -> + %% TODO: handle Unicode names. Dot_File = filename:rootname(File) ++ ".dot", to_dot(CG, Dot_File), - Command = io_lib:format("dot -Tps ~s -o ~s ~s", [Args, File, Dot_File]), + Command = io_lib:format("dot -Tps ~ts -o ~ts ~ts", [Args, File, Dot_File]), _ = os:cmd(Command), ok. diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index 8500c59ebe..d72ae1dc86 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -77,7 +77,7 @@ init_opts_for_build(Opts) -> [] -> Opts#options{output_plt = get_default_output_plt()}; [Plt] -> Opts#options{init_plts = [], output_plt = Plt}; Plts -> - Msg = io_lib:format("Could not build multiple PLT files: ~s\n", + Msg = io_lib:format("Could not build multiple PLT files: ~ts\n", [format_plts(Plts)]), cl_error(Msg) end; @@ -99,7 +99,7 @@ init_opts_for_add(Opts) -> init_plts = get_default_init_plt()}; [Plt] -> Opts#options{output_plt = Plt}; Plts -> - Msg = io_lib:format("Could not add to multiple PLT files: ~s\n", + Msg = io_lib:format("Could not add to multiple PLT files: ~ts\n", [format_plts(Plts)]), cl_error(Msg) end; @@ -165,7 +165,7 @@ init_opts_for_remove(Opts) -> init_plts = get_default_init_plt()}; [Plt] -> Opts#options{output_plt = Plt}; Plts -> - Msg = io_lib:format("Could not remove from multiple PLT files: ~s\n", + Msg = io_lib:format("Could not remove from multiple PLT files: ~ts\n", [format_plts(Plts)]), cl_error(Msg) end; @@ -212,19 +212,19 @@ plt_common(#options{init_plts = [InitPlt]} = Opts, RemoveFiles, AddFiles) -> do_analysis(AnalFiles, Opts, Plt, {Md5, ModDeps1}) end; {error, no_such_file} -> - Msg = io_lib:format("Could not find the PLT: ~s\n~s", + Msg = io_lib:format("Could not find the PLT: ~ts\n~s", [InitPlt, default_plt_error_msg()]), cl_error(Msg); {error, not_valid} -> - Msg = io_lib:format("The file: ~s is not a valid PLT file\n~s", + Msg = io_lib:format("The file: ~ts is not a valid PLT file\n~s", [InitPlt, default_plt_error_msg()]), cl_error(Msg); {error, read_error} -> - Msg = io_lib:format("Could not read the PLT: ~s\n~s", + Msg = io_lib:format("Could not read the PLT: ~ts\n~s", [InitPlt, default_plt_error_msg()]), cl_error(Msg); {error, {no_file_to_remove, F}} -> - Msg = io_lib:format("Could not remove the file ~s from the PLT: ~s\n", + Msg = io_lib:format("Could not remove the file ~ts from the PLT: ~ts\n", [F, InitPlt]), cl_error(Msg) end. @@ -264,7 +264,7 @@ report_check(#options{report_mode = ReportMode, init_plts = [InitPlt]}) -> case ReportMode of quiet -> ok; _ -> - io:format(" Checking whether the PLT ~s is up-to-date...", [InitPlt]) + io:format(" Checking whether the PLT ~ts is up-to-date...", [InitPlt]) end. report_old_version(#options{report_mode = ReportMode, init_plts = [InitPlt]}) -> @@ -272,7 +272,7 @@ report_old_version(#options{report_mode = ReportMode, init_plts = [InitPlt]}) -> quiet -> ok; _ -> io:put_chars(" no\n"), - io:format(" (the PLT ~s was built with an old version of Dialyzer)\n", + io:format(" (the PLT ~ts was built with an old version of Dialyzer)\n", [InitPlt]) end. @@ -300,19 +300,19 @@ report_analysis_start(#options{analysis_type = Type, plt_add -> [InitPlt] = InitPlts, case InitPlt =:= OutputPlt of - true -> io:format("Adding information to ~s...", [OutputPlt]); - false -> io:format("Adding information from ~s to ~s...", + true -> io:format("Adding information to ~ts...", [OutputPlt]); + false -> io:format("Adding information from ~ts to ~ts...", [InitPlt, OutputPlt]) end; plt_build -> - io:format("Creating PLT ~s ...", [OutputPlt]); + io:format("Creating PLT ~ts ...", [OutputPlt]); plt_check -> - io:format("Rebuilding the information in ~s...", [OutputPlt]); + io:format("Rebuilding the information in ~ts...", [OutputPlt]); plt_remove -> [InitPlt] = InitPlts, case InitPlt =:= OutputPlt of - true -> io:format("Removing information from ~s...", [OutputPlt]); - false -> io:format("Removing information from ~s to ~s...", + true -> io:format("Removing information from ~ts...", [OutputPlt]); + false -> io:format("Removing information from ~ts to ~ts...", [InitPlt, OutputPlt]) end; succ_typings -> io:format("Proceeding with analysis...") @@ -420,7 +420,7 @@ assert_writable(PltFile) -> case check_if_writable(PltFile) of true -> ok; false -> - Msg = io_lib:format(" The PLT file ~s is not writable", [PltFile]), + Msg = io_lib:format(" The PLT file ~ts is not writable", [PltFile]), cl_error(Msg) end. @@ -596,9 +596,11 @@ init_output(State0, #options{output_file = OutFile, false -> case file:open(OutFile, [write]) of {ok, File} -> + %% Warnings and errors can include Unicode characters. + ok = io:setopts(File, [{encoding, unicode}]), State#cl_state{output = File}; {error, Reason} -> - Msg = io_lib:format("Could not open output file ~p, Reason: ~p\n", + Msg = io_lib:format("Could not open output file ~tp, Reason: ~p\n", [OutFile, Reason]), cl_error(State, lists:flatten(Msg)) end @@ -687,7 +689,7 @@ cl_error(Msg) -> cl_error(State, Msg) -> case State#cl_state.output of standard_io -> ok; - Outfile -> io:format(Outfile, "\n~s\n", [Msg]) + Outfile -> io:format(Outfile, "\n~ts\n", [Msg]) end, maybe_close_output_file(State), throw({dialyzer_error, lists:flatten(Msg)}). @@ -792,7 +794,7 @@ print_ext_calls(#cl_state{output = Output, end. do_print_ext_calls(Output, [{M,F,A}|T], Before) -> - io:format(Output, "~s~p:~p/~p\n", [Before,M,F,A]), + io:format(Output, "~s~tp:~tp/~p\n", [Before,M,F,A]), do_print_ext_calls(Output, T, Before); do_print_ext_calls(_, [], _) -> ok. @@ -825,7 +827,7 @@ print_ext_types(#cl_state{output = Output, end. do_print_ext_types(Output, [{M,F,A}|T], Before) -> - io:format(Output, "~s~p:~p/~p\n", [Before,M,F,A]), + io:format(Output, "~s~tp:~tp/~p\n", [Before,M,F,A]), do_print_ext_types(Output, T, Before); do_print_ext_types(_, [], _) -> ok. @@ -844,10 +846,10 @@ print_warnings(#cl_state{output = Output, formatted -> [dialyzer:format_warning(W, FOpt) || W <- PrWarnings]; raw -> - [io_lib:format("~p. \n", + [io_lib:format("~tp. \n", [W]) || W <- set_warning_id(PrWarnings)] end, - io:format(Output, "\n~s", [S]) + io:format(Output, "\n~ts", [S]) end. -spec process_warnings([raw_warning()]) -> [raw_warning()]. diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl index baeffe99d8..a456d38e64 100644 --- a/lib/dialyzer/src/dialyzer_cl_parse.erl +++ b/lib/dialyzer/src/dialyzer_cl_parse.erl @@ -37,11 +37,12 @@ start() -> init(), Args = init:get_plain_arguments(), try - cl(Args) + Ret = cl(Args), + Ret catch throw:{dialyzer_cl_parse_error, Msg} -> {error, Msg}; _:R -> - Msg = io_lib:format("~p\n~p\n", [R, erlang:get_stacktrace()]), + Msg = io_lib:format("~tp\n~tp\n", [R, erlang:get_stacktrace()]), {error, lists:flatten(Msg)} end. diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index 5f24b5a668..300af7956d 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -293,7 +293,7 @@ check_extraneous_1(Contract, SuccType) -> CRng = erl_types:t_fun_range(Contract), CRngs = erl_types:t_elements(CRng), STRng = erl_types:t_fun_range(SuccType), - ?debug("CR = ~p\nSR = ~p\n", [CRngs, STRng]), + ?debug("CR = ~tp\nSR = ~tp\n", [CRngs, STRng]), case [CR || CR <- CRngs, erl_types:t_is_none(erl_types:t_inf(CR, STRng))] of [] -> @@ -360,7 +360,7 @@ process_contract({Contract, Constraints}, CallTypes0) -> CallTypesFun = erl_types:t_fun(CallTypes0, erl_types:t_any()), ContArgsFun = erl_types:t_fun(erl_types:t_fun_args(Contract), erl_types:t_any()), - ?debug("Instance: Contract: ~s\n Arguments: ~s\n", + ?debug("Instance: Contract: ~ts\n Arguments: ~ts\n", [erl_types:t_to_string(ContArgsFun), erl_types:t_to_string(CallTypesFun)]), case solve_constraints(ContArgsFun, CallTypesFun, Constraints) of @@ -427,7 +427,7 @@ insert_constraints([{subtype, Type1, Type2}|Left], Map) -> false -> %% A lot of things should change to add supertypes throw({error, io_lib:format("First argument of is_subtype constraint " - "must be a type variable: ~p\n", [Type1])}) + "must be a type variable: ~tp\n", [Type1])}) end; insert_constraints([], Map) -> Map. @@ -439,9 +439,9 @@ insert_constraints([], Map) -> Map. contracts(). store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecMap, RecordsDict) -> - %% io:format("contract from form: ~p\n", [TypeSpec]), + %% io:format("contract from form: ~tp\n", [TypeSpec]), TmpContract = contract_from_form(TypeSpec, MFA, RecordsDict, FileLine), - %% io:format("contract: ~p\n", [TmpContract]), + %% io:format("contract: ~tp\n", [TmpContract]), maps:put(MFA, {FileLine, TmpContract, Xtra}, SpecMap). contract_from_form(Forms, MFA, RecDict, FileLine) -> @@ -458,8 +458,8 @@ contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], MFA, RecDict, catch throw:{error, Msg} -> {File, Line} = FileLine, - NewMsg = io_lib:format("~s:~p: ~s", [filename:basename(File), - Line, Msg]), + NewMsg = io_lib:format("~ts:~p: ~ts", [filename:basename(File), + Line, Msg]), throw({error, NewMsg}) end, NewTypeNoVars = erl_types:subst_all_vars_to_any(NewType), @@ -514,7 +514,7 @@ initialize_constraints([Constr|Rest], MFA, RecDict, ExpTypes, RecordTable, {type, _, constraint, [{atom,_,Name}, List]} -> N = length(List), throw({error, - io_lib:format("Unsupported type guard ~w/~w\n", [Name, N])}) + io_lib:format("Unsupported type guard ~tw/~w\n", [Name, N])}) end. constraints_fixpoint(Constrs, MFA, RecDict, ExpTypes, RecordTable, Cache) -> @@ -686,7 +686,7 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left], {value, {Ret, Args}} -> Sig = erl_types:t_fun(Args, Ret), {M, _F, _A} = MFA, - %% io:format("MFA ~p~n", [MFA]), + %% io:format("MFA ~tp~n", [MFA]), Opaques = FindOpaques(M), {File, Line} = FileLine, WarningInfo = {File, Line, MFA}, diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 4c29b4f1eb..46a8f01360 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -191,19 +191,19 @@ analyze_loop(State) -> {ArgTypes, IsCalled} = state__get_args_and_status(Fun, NewState1), case not IsCalled of true -> - ?debug("Not handling (not called) ~w: ~s\n", + ?debug("Not handling (not called) ~w: ~ts\n", [NewState1#state.curr_fun, t_to_string(t_product(ArgTypes))]), analyze_loop(NewState1); false -> case state__fun_env(Fun, NewState1) of none -> - ?debug("Not handling (no env) ~w: ~s\n", + ?debug("Not handling (no env) ~w: ~ts\n", [NewState1#state.curr_fun, t_to_string(t_product(ArgTypes))]), analyze_loop(NewState1); Map -> - ?debug("Handling fun ~p: ~s\n", + ?debug("Handling fun ~p: ~ts\n", [NewState1#state.curr_fun, t_to_string(state__fun_type(Fun, NewState1))]), Vars = cerl:fun_vars(Fun), @@ -222,7 +222,7 @@ analyze_loop(State) -> end, {NewState4, _Map2, BodyType} = traverse(Body, Map1, NewState3), - ?debug("Done analyzing: ~w:~s\n", + ?debug("Done analyzing: ~w:~ts\n", [NewState1#state.curr_fun, t_to_string(t_fun(ArgTypes, BodyType))]), NewState5 = @@ -232,7 +232,7 @@ analyze_loop(State) -> end, NewState6 = state__update_fun_entry(Fun, ArgTypes, BodyType, NewState5), - ?debug("done adding stuff for ~w\n", + ?debug("done adding stuff for ~tw\n", [state__lookup_name(get_label(Fun), State)]), analyze_loop(NewState6) end @@ -487,23 +487,23 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], end, ?debug("--------------------------------------------------------\n", []), - ?debug("Fun: ~p\n", [state__lookup_name(Fun, State)]), + ?debug("Fun: ~tp\n", [state__lookup_name(Fun, State)]), ?debug("Module ~p\n", [State#state.module]), - ?debug("CArgs ~s\n", [erl_types:t_to_string(t_product(CArgs))]), - ?debug("ArgTypes ~s\n", [erl_types:t_to_string(t_product(ArgTypes))]), - ?debug("BifArgs ~p\n", [erl_types:t_to_string(t_product(BifArgs))]), + ?debug("CArgs ~ts\n", [erl_types:t_to_string(t_product(CArgs))]), + ?debug("ArgTypes ~ts\n", [erl_types:t_to_string(t_product(ArgTypes))]), + ?debug("BifArgs ~tp\n", [erl_types:t_to_string(t_product(BifArgs))]), NewArgsSig = t_inf_lists(SigArgs, ArgTypes, Opaques), - ?debug("SigArgs ~s\n", [erl_types:t_to_string(t_product(SigArgs))]), - ?debug("NewArgsSig: ~s\n", [erl_types:t_to_string(t_product(NewArgsSig))]), + ?debug("SigArgs ~ts\n", [erl_types:t_to_string(t_product(SigArgs))]), + ?debug("NewArgsSig: ~ts\n", [erl_types:t_to_string(t_product(NewArgsSig))]), NewArgsContract = t_inf_lists(CArgs, ArgTypes, Opaques), - ?debug("NewArgsContract: ~s\n", + ?debug("NewArgsContract: ~ts\n", [erl_types:t_to_string(t_product(NewArgsContract))]), NewArgsBif = t_inf_lists(BifArgs, ArgTypes, Opaques), - ?debug("NewArgsBif: ~s\n", [erl_types:t_to_string(t_product(NewArgsBif))]), + ?debug("NewArgsBif: ~ts\n", [erl_types:t_to_string(t_product(NewArgsBif))]), NewArgTypes0 = t_inf_lists(NewArgsSig, NewArgsContract), NewArgTypes = t_inf_lists(NewArgTypes0, NewArgsBif, Opaques), - ?debug("NewArgTypes ~s\n", [erl_types:t_to_string(t_product(NewArgTypes))]), + ?debug("NewArgTypes ~ts\n", [erl_types:t_to_string(t_product(NewArgTypes))]), ?debug("\n", []), BifRet = BifRange(NewArgTypes), @@ -511,12 +511,12 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], RetWithoutContr = t_inf(SigRange, BifRet), RetWithoutLocal = t_inf(ContrRet, RetWithoutContr), - ?debug("RetWithoutContr: ~s\n",[erl_types:t_to_string(RetWithoutContr)]), - ?debug("RetWithoutLocal: ~s\n", [erl_types:t_to_string(RetWithoutLocal)]), - ?debug("BifRet: ~s\n", [erl_types:t_to_string(BifRange(NewArgTypes))]), - ?debug("SigRange: ~s\n", [erl_types:t_to_string(SigRange)]), - ?debug("ContrRet: ~s\n", [erl_types:t_to_string(ContrRet)]), - ?debug("LocalRet: ~s\n", [erl_types:t_to_string(LocalRet)]), + ?debug("RetWithoutContr: ~ts\n",[erl_types:t_to_string(RetWithoutContr)]), + ?debug("RetWithoutLocal: ~ts\n", [erl_types:t_to_string(RetWithoutLocal)]), + ?debug("BifRet: ~ts\n", [erl_types:t_to_string(BifRange(NewArgTypes))]), + ?debug("SigRange: ~ts\n", [erl_types:t_to_string(SigRange)]), + ?debug("ContrRet: ~ts\n", [erl_types:t_to_string(ContrRet)]), + ?debug("LocalRet: ~ts\n", [erl_types:t_to_string(LocalRet)]), State1 = case is_race_analysis_enabled(State) of @@ -596,7 +596,7 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], false -> t_inf(RetWithoutLocal, LocalRet) end, NewAccRet = t_sup(AccRet, TotalRet), - ?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]), + ?debug("NewAccRet: ~ts\n", [t_to_string(NewAccRet)]), {NewWarnings, State4} = state__remove_added_warnings(State, State3), {HowMany, OldWarnings} = Warns, NewWarns = @@ -1335,7 +1335,7 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State, Warns) -> end, case BindRes of {error, ErrorType, NewPats, Type, OpaqueTerm} -> - ?debug("Failed binding pattern: ~s\nto ~s\n", + ?debug("Failed binding pattern: ~ts\nto ~ts\n", [cerl_prettypr:format(C), format_type(ArgType0, State1)]), case state__warning_mode(State1) of false -> @@ -1451,7 +1451,7 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State, Warns) -> end, case bind_guard(Guard, Map3, State1) of {error, Reason} -> - ?debug("Failed guard: ~s\n", + ?debug("Failed guard: ~ts\n", [cerl_prettypr:format(C, [{hook, cerl_typean:pp_hook()}])]), PatString = format_patterns(Pats), DefaultMsg = @@ -1532,7 +1532,7 @@ bind_pat_vars_reverse(Pats, Types, Acc, Map, State) -> end. bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) -> - ?debug("Binding pat: ~w to ~s\n", [cerl:type(Pat), format_type(Type, State)] + ?debug("Binding pat: ~tw to ~ts\n", [cerl:type(Pat), format_type(Type, State)] ), Opaques = State#state.opaques, {NewMap, TypeOut} = @@ -1830,7 +1830,7 @@ bind_guard(Guard, Map, State) -> end. bind_guard(Guard, Map, Env, Eval, State) -> - ?debug("Handling ~w guard: ~s\n", + ?debug("Handling ~tw guard: ~ts\n", [Eval, cerl_prettypr:format(Guard, [{noann, true}])]), case cerl:type(Guard) of binary -> @@ -2009,7 +2009,7 @@ handle_guard_type_test(Guard, F, Map, Env, Eval, State) -> ?debug("Type test: ~w failed\n", [F]), signal_guard_fail(Eval, Guard, [ArgType], State); {ok, NewArgType, Ret} -> - ?debug("Type test: ~w succeeded, NewType: ~s, Ret: ~s\n", + ?debug("Type test: ~w succeeded, NewType: ~ts, Ret: ~ts\n", [F, t_to_string(NewArgType), t_to_string(Ret)]), {enter_type(Arg, NewArgType, Map1), Ret} end. @@ -2295,8 +2295,8 @@ handle_guard_eqeq(Guard, Map, Env, Eval, State) -> bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) -> {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State), {Map2, Type2} = bind_guard(Arg2, Map1, Env, dont_know, State), - ?debug("Types are:~s =:= ~s\n", [t_to_string(Type1), - t_to_string(Type2)]), + ?debug("Types are:~ts =:= ~ts\n", [t_to_string(Type1), + t_to_string(Type2)]), Opaques = State#state.opaques, Inf = t_inf(Type1, Type2, Opaques), case t_is_none(Inf) of @@ -2840,7 +2840,7 @@ enter_type(Key, Val, MS) -> ?debug("Binding ~p to ~p\n", [KeyLabel, NewKey]), enter_type(NewKey, Val, MS); error -> - ?debug("Entering ~p :: ~s\n", [KeyLabel, t_to_string(Val)]), + ?debug("Entering ~p :: ~ts\n", [KeyLabel, t_to_string(Val)]), case maps:find(KeyLabel, Map) of {ok, Value} -> case erl_types:t_is_equal(Val, Value) of @@ -2940,7 +2940,7 @@ debug_pp_map(#map{map = Map}=MapRec) -> Keys = maps:keys(Map), io:format("Map:\n", []), lists:foreach(fun (Key) -> - io:format("\t~w :: ~s\n", + io:format("\t~w :: ~ts\n", [Key, t_to_string(lookup_type(Key, MapRec))]) end, Keys), ok. @@ -3095,7 +3095,7 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State, abs(get_line(Ann)), State#state.curr_fun}, Warn = {Tag, WarningInfo, Msg}, - ?debug("MSG ~s\n", [dialyzer:format_warning(Warn)]), + ?debug("MSG ~ts\n", [dialyzer:format_warning(Warn)]), State#state{warnings = [Warn|Warnings]}; false -> case is_compiler_generated(Ann) of @@ -3107,7 +3107,7 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State, Warn = {Tag, WarningInfo, Msg}, case Tag of ?WARN_CONTRACT_RANGE -> ok; - _ -> ?debug("MSG ~s\n", [dialyzer:format_warning(Warn)]) + _ -> ?debug("MSG ~ts\n", [dialyzer:format_warning(Warn)]) end, State#state{warnings = [Warn|Warnings]} end @@ -3351,14 +3351,14 @@ state__update_fun_entry(Tree, ArgTypes, Out0, SameOut = t_is_equal(OldOut, Out), if SameArgs, SameOut -> - ?debug("Fixpoint for ~w: ~s\n", + ?debug("Fixpoint for ~tw: ~ts\n", [state__lookup_name(Fun, State), t_to_string(t_fun(ArgTypes, Out))]), State; true -> %% Can only happen in self-recursive functions. NewEntry = {OldArgTypes, Out}, - ?debug("New Entry for ~w: ~s\n", + ?debug("New Entry for ~tw: ~ts\n", [state__lookup_name(Fun, State), t_to_string(t_fun(OldArgTypes, Out))]), NewFunTab = dict:store(Fun, NewEntry, FunTab), @@ -3380,7 +3380,7 @@ state__add_work_from_fun(Tree, #state{callgraph = Callgraph, || MFA <- MFAList], %% Must filter the result for results in this module. FilteredList = [L || {ok, L} <- LabelList, dict:is_key(L, TreeMap)], - ?debug("~w: Will try to add:~w\n", + ?debug("~tw: Will try to add:~tw\n", [state__lookup_name(Label, State), MFAList]), lists:foldl(fun(L, AccState) -> state__add_work(L, AccState) @@ -3427,7 +3427,7 @@ state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) -> {not_handled, {_Args, Ret}} -> Ret; {_Args, Ret} -> Ret end, - ?debug("LocalRet: ~s\n", [t_to_string(LocalRet)]), + ?debug("LocalRet: ~ts\n", [t_to_string(LocalRet)]), {Fun, Sig, Contract, LocalRet}. forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) -> @@ -3445,7 +3445,7 @@ forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) -> NewArgTypes = [t_sup(X, Y) || {X, Y} <- lists:zip(ArgTypes, OldArgTypes)], NewWork = add_work(Fun, Work), - ?debug("~w: forwarding args ~s\n", + ?debug("~tw: forwarding args ~ts\n", [state__lookup_name(Fun, State), t_to_string(t_product(NewArgTypes))]), NewFunTab = dict:store(Fun, {NewArgTypes, OldOut}, FunTab), diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl index d1b955044b..bcaeca4cdc 100644 --- a/lib/dialyzer/src/dialyzer_gui_wx.erl +++ b/lib/dialyzer/src/dialyzer_gui_wx.erl @@ -469,18 +469,18 @@ gui_loop(#gui_state{backend_pid = BackendPid, doc_plt = DocPlt, Msg = io_lib:format("The following functions are called " "but type information about them is not available.\n" "The analysis might get more precise by including " - "the modules containing these functions:\n\n\t~p\n", + "the modules containing these functions:\n\n\t~tp\n", [ExtCalls]), free_editor(State,"Analysis Done", Msg), gui_loop(State); {BackendPid, ext_types, ExtTypes} -> - Map = fun({M,F,A}) -> io_lib:format("~p:~p/~p",[M,F,A]) end, + Map = fun({M,F,A}) -> io_lib:format("~tp:~tp/~p",[M,F,A]) end, ExtTypeString = string:join(lists:map(Map, ExtTypes), "\n"), Msg = io_lib:format("The following remote types are being used " "but information about them is not available.\n" "The analysis might get more precise by including " "the modules containing these types and making sure " - "that they are exported:\n~s\n", [ExtTypeString]), + "that they are exported:\n~ts\n", [ExtTypeString]), free_editor(State, "Analysis done", Msg), gui_loop(State); {BackendPid, log, LogMsg} -> @@ -508,7 +508,7 @@ gui_loop(#gui_state{backend_pid = BackendPid, doc_plt = DocPlt, config_gui_stop(State), gui_loop(State); {'EXIT', BackendPid, Reason} when Reason =/= 'normal' -> - free_editor(State, ?DIALYZER_ERROR_TITLE, io_lib:format("~p", [Reason])), + free_editor(State, ?DIALYZER_ERROR_TITLE, io_lib:format("~tp", [Reason])), config_gui_stop(State), gui_loop(State) end. @@ -926,7 +926,7 @@ include_dialog(#gui_state{gui = Wx, frame = Frame, options = Options}) -> wxButton:connect(DeleteAllButton, command_button_clicked), wxButton:connect(Ok, command_button_clicked), wxButton:connect(Cancel, command_button_clicked), - Dirs = [io_lib:format("~s", [X]) || X <- Options#options.include_dirs], + Dirs = [io_lib:format("~ts", [X]) || X <- Options#options.include_dirs], wxListBox:set(Box, Dirs), Layout = wxBoxSizer:new(?wxVERTICAL), Buttons = wxBoxSizer:new(?wxHORIZONTAL), @@ -1118,13 +1118,13 @@ handle_help(State, Title, Txt) -> case file:open(FileName, [read]) of {error, Reason} -> error_sms(State, - io_lib:format("Could not find doc/~s file!\n\n ~p", + io_lib:format("Could not find doc/~ts file!\n\n ~tp", [Txt, Reason])); {ok, _Handle} -> case file:read_file(FileName) of {error, Reason} -> error_sms(State, - io_lib:format("Could not read doc/~s file!\n\n ~p", + io_lib:format("Could not read doc/~ts file!\n\n ~tp", [Txt, Reason])); {ok, Binary} -> Contents = binary_to_list(Binary), @@ -1223,7 +1223,7 @@ update_explanation(#gui_state{explanation_box = Box}, Explanation) -> wxTextCtrl:appendText(Box, ExplString). format_explanation({function_return, {M, F, A}, NewList}) -> - io_lib:format("The function ~p: ~p/~p returns ~p\n", + io_lib:format("The function ~w:~tw/~w returns ~ts\n", [M, F, A, erl_types:t_to_string(NewList)]); format_explanation(Explanation) -> io_lib:format("~p\n", [Explanation]). diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index ec3f41311d..03040f8e38 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -112,7 +112,7 @@ adapt_get_warnings(Opts = #options{analysis_type = Mode, -spec bad_option(string(), term()) -> no_return(). bad_option(String, Term) -> - Msg = io_lib:format("~s: ~P", [String, Term, 25]), + Msg = io_lib:format("~ts: ~tP", [String, Term, 25]), throw({dialyzer_options_error, lists:flatten(Msg)}). build_options([{OptName, undefined}|Rest], Options) when is_atom(OptName) -> diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 847faab2f4..f36a008739 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -253,7 +253,7 @@ from_file(FileName, ReturnInfo) -> {ok, Rec} -> case check_version(Rec) of error -> - Msg = io_lib:format("Old PLT file ~s\n", [FileName]), + Msg = io_lib:format("Old PLT file ~ts\n", [FileName]), plt_error(Msg); ok -> Types = [{Mod, maps:from_list(dict:to_list(Types))} || @@ -272,7 +272,7 @@ from_file(FileName, ReturnInfo) -> end end; {error, Reason} -> - Msg = io_lib:format("Could not read PLT file ~s: ~p\n", + Msg = io_lib:format("Could not read PLT file ~ts: ~p\n", [FileName, Reason]), plt_error(Msg) end. @@ -356,7 +356,7 @@ merge_plts_or_report_conflicts(PltFiles, Plts) -> ConfFiles = find_duplicates(IncFiles), Msg = io_lib:format("Could not merge PLTs since they are not disjoint\n" "The following files are included in more than one " - "PLTs:\n~p\n", [ConfFiles]), + "PLTs:\n~tp\n", [ConfFiles]), plt_error(Msg) end. @@ -391,7 +391,7 @@ to_file(FileName, case file:write_file(FileName, Bin) of ok -> ok; {error, Reason} -> - Msg = io_lib:format("Could not write PLT file ~s: ~w\n", + Msg = io_lib:format("Could not write PLT file ~ts: ~w\n", [FileName, Reason]), throw({dialyzer_error, Msg}) end. @@ -467,7 +467,7 @@ compute_md5_from_files(Files) -> compute_md5_from_file(File) -> case filelib:is_regular(File) of false -> - Msg = io_lib:format("Not a regular file: ~s\n", [File]), + Msg = io_lib:format("Not a regular file: ~ts\n", [File]), throw({dialyzer_error, Msg}); true -> case dialyzer_utils:get_core_from_beam(File) of @@ -635,7 +635,7 @@ get_specs(#plt{info = Info}, M, F, A) when is_atom(M), is_atom(F) -> end. create_specs([{{M, F, _A}, {Ret, Args}}|Left], M) -> - [io_lib:format("-spec ~w(~s) -> ~s\n", + [io_lib:format("-spec ~tw(~ts) -> ~ts\n", [F, expand_args(Args), erl_types:t_to_string(Ret)]) | create_specs(Left, M)]; create_specs(List = [{{M, _F, _A}, {_Ret, _Args}}| _], _M) -> @@ -802,7 +802,7 @@ pp_non_returning() -> io:format("= Loops =\n"), io:format("=========================================\n\n"), lists:foreach(fun({{M, F, _}, Type}) -> - io:format("~w:~w~s.\n", + io:format("~w:~tw~ts.\n", [M, F, dialyzer_utils:format_sig(Type)]) end, lists:sort(Unit)), io:format("\n"), @@ -824,7 +824,7 @@ pp_mod(Mod) when is_atom(Mod) -> lists:foreach(fun({{_, F, _}, Ret, Args}) -> T = erl_types:t_fun(Args, Ret), S = dialyzer_utils:format_sig(T), - io:format("-spec ~w~s.\n", [F, S]) + io:format("-spec ~tw~ts.\n", [F, S]) end, lists:sort(List)); none -> io:format("dialyzer: Found no module named '~s' in the PLT\n", [Mod]) diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index be685baf22..66c6c5e9ed 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -260,8 +260,8 @@ refine_one_module(M, {CodeServer, Callgraph, Plt, _Solvers}) -> FindOpaques = find_opaques_fun(Records), DecoratedFunTypes = decorate_succ_typings(Contracts, Callgraph, NewFunTypes, FindOpaques), - %% ?debug("NewFunTypes ~p\n ~n", [dict:to_list(NewFunTypes)]), - %% ?debug("refine DecoratedFunTypes ~p\n ~n", [dict:to_list(DecoratedFunTypes)]), + %% ?debug("NewFunTypes ~tp\n ~n", [dict:to_list(NewFunTypes)]), + %% ?debug("refine DecoratedFunTypes ~tp\n ~n", [dict:to_list(DecoratedFunTypes)]), debug_pp_functions("Refine", NewFunTypes, DecoratedFunTypes, Callgraph), case reached_fixpoint(FunTypes, DecoratedFunTypes) of @@ -314,7 +314,7 @@ compare_types_1([{X, Type1}|Left1], [{X, Type2}|Left2], Strict, NotFixpoint) -> case Res of true -> compare_types_1(Left1, Left2, Strict, NotFixpoint); false -> - ?debug("Failed fixpoint for ~w: ~s =/= ~s\n", + ?debug("Failed fixpoint for ~w: ~ts =/= ~ts\n", [X, erl_types:t_to_string(Type1), erl_types:t_to_string(Type2)]), compare_types_1(Left1, Left2, Strict, [{X, Type2}|NotFixpoint]) end; @@ -371,8 +371,8 @@ find_succ_types_for_scc(SCC0, {Codeserver, Callgraph, Plt, Solvers}) -> PltContracts = dialyzer_contracts:check_contracts(Contracts3, Callgraph, DecoratedFunTypes, FindOpaques), - %% ?debug("FilteredFunTypes ~p\n ~n", [dict:to_list(FilteredFunTypes)]), - %% ?debug("SCC DecoratedFunTypes ~p\n ~n", [dict:to_list(DecoratedFunTypes)]), + %% ?debug("FilteredFunTypes ~tp\n ~n", [dict:to_list(FilteredFunTypes)]), + %% ?debug("SCC DecoratedFunTypes ~tp\n ~n", [dict:to_list(DecoratedFunTypes)]), debug_pp_functions("SCC", FilteredFunTypes, DecoratedFunTypes, Callgraph), ContractFixpoint = lists:all(fun({MFA, _C}) -> @@ -388,7 +388,7 @@ find_succ_types_for_scc(SCC0, {Codeserver, Callgraph, Plt, Solvers}) -> reached_fixpoint_strict(PropTypes, DecoratedFunTypes)) of true -> []; false -> - ?debug("Not fixpoint for: ~w\n", [AllFuns]), + ?debug("Not fixpoint for: ~tw\n", [AllFuns]), [Fun || {Fun, _Arity} <- AllFuns] end. @@ -476,11 +476,11 @@ format_succ_types([], _Callgraph, Acc) -> -ifdef(DEBUG). debug_pp_succ_typings(SuccTypes) -> ?debug("Succ typings:\n", []), - [?debug(" ~w :: ~s\n", + [?debug(" ~tw :: ~ts\n", [MFA, erl_types:t_to_string(erl_types:t_fun(ArgT, RetT))]) || {MFA, {RetT, ArgT}} <- SuccTypes], ?debug("Contracts:\n", []), - [?debug(" ~w :: ~s\n", + [?debug(" ~tw :: ~ts\n", [MFA, erl_types:t_to_string(erl_types:t_fun(ArgT, RetFun(ArgT)))]) || {MFA, {contract, RetFun, ArgT}} <- SuccTypes], ?debug("\n", []), @@ -492,12 +492,12 @@ debug_pp_functions(Header, FunTypes, DecoratedFunTypes, Callgraph) -> DTypes = lists:keysort(1, dict:to_list(DecoratedFunTypes)), Fun = fun({{Label, Type},{Label, DecoratedType}}) -> Name = lookup_name(Label, Callgraph), - ?debug("~w (~w): ~s\n", + ?debug("~tw (~w): ~ts\n", [Name, Label, erl_types:t_to_string(Type)]), case erl_types:t_is_equal(Type, DecoratedType) of true -> ok; false -> - ?debug(" With opaque types: ~s\n", + ?debug(" With opaque types: ~ts\n", [erl_types:t_to_string(DecoratedType)]) end end, diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index c3ba44fde7..a0a69cb2ea 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -771,7 +771,7 @@ handle_call(Call, DefinedVars, State) -> {ok, Var} -> %% This is part of the SCC currently analyzed. %% Intercept and change this to an apply instead. - ?debug("Found the call to ~w\n", [MFA]), + ?debug("Found the call to ~tw\n", [MFA]), Label = cerl_trees:get_label(Call), Apply = cerl:ann_c_apply([{label, Label}], Var, Args), traverse(Apply, DefinedVars, State) @@ -1789,11 +1789,11 @@ get_bif_test_constr(Dst, Arg, Type, _State) -> %%============================================================================= solve([Fun], State) -> - ?debug("============ Analyzing Fun: ~w ===========\n", + ?debug("============ Analyzing Fun: ~tw ===========\n", [debug_lookup_name(Fun)]), solve_fun(Fun, map_new(), State); solve([_|_] = SCC, State) -> - ?debug("============ Analyzing SCC: ~w ===========\n", + ?debug("============ Analyzing SCC: ~tw ===========\n", [[debug_lookup_name(F) || F <- SCC]]), Users = comp_users(SCC, State), solve_scc(SCC, map_new(), State, Users, _ToSolve=SCC, false). @@ -1829,13 +1829,13 @@ solve_scc(SCC, Map, State, Users, ToSolve, TryingUnit) -> erase_type(t_var_name(Fun), AccFunMap) end, Map, ToSolve), Map1 = enter_type_lists(Vars, RecTypes, CleanMap), - ?debug("Checking SCC: ~w\n", [[debug_lookup_name(F) || F <- SCC]]), + ?debug("Checking SCC: ~tw\n", [[debug_lookup_name(F) || F <- SCC]]), SolveFun = fun(X, Y) -> scc_fold_fun(X, Y, State) end, Map2 = lists:foldl(SolveFun, Map1, ToSolve), Updated = updated_vars_only(Vars, Map, Map2), case Updated =:= [] of true -> - ?debug("SCC ~w reached fixpoint\n", [SCC]), + ?debug("SCC ~tw reached fixpoint\n", [SCC]), NewTypes = unsafe_lookup_type_list(Funs, Map2), case erl_types:any_none([t_fun_range(T) || T <- NewTypes]) andalso TryingUnit =:= false of @@ -1851,7 +1851,7 @@ solve_scc(SCC, Map, State, Users, ToSolve, TryingUnit) -> Map2 end; false -> - ?debug("SCC ~w did not reach fixpoint\n", [SCC]), + ?debug("SCC ~tw did not reach fixpoint\n", [SCC]), ToSolve1 = affected(Updated, Users), solve_scc(SCC, Map2, State, Users, ToSolve1, TryingUnit) end. @@ -1875,8 +1875,8 @@ scc_fold_fun(F, FunMap, State) -> error -> enter_type(F, NewType, FunMap) end, - ?debug("Done solving for function ~w :: ~s\n", [debug_lookup_name(F), - format_type(NewType)]), + ?debug("Done solving for function ~tw :: ~ts\n", [debug_lookup_name(F), + format_type(NewType)]), NewFunMap. solve(Fun, Cs, FunMap, State) -> @@ -1895,7 +1895,7 @@ solver(Solver, SolveFun) -> [Solver, _R, 60]), throw(error) catch E:R -> - io:format("Solver ~w failed: ~w:~p\n ~p\n", + io:format("Solver ~w failed: ~w:~p\n ~tp\n", [Solver, E, R, erlang:get_stacktrace()]), throw(error) end. @@ -1932,9 +1932,9 @@ sane_maps(Map1, Map2, Keys, _S1, _S2) -> true -> true; false -> ?debug("Constraint solvers do not agree on ~w\n", [Key]), - ?debug("~w: ~s\n", + ?debug("~w: ~ts\n", [_S1, format_type(unsafe_lookup_type(Key, Map1))]), - ?debug("~w: ~s\n", + ?debug("~w: ~ts\n", [_S2, format_type(unsafe_lookup_type(Key, Map2))]), false end @@ -1966,7 +1966,7 @@ v2_solve(#constraint_ref{id = Id}, Map, V2State) -> v2_solve_reference(Id, Map, V2State). v2_solve_reference(Id, Map, V2State0) -> - ?debug("Checking ref to fun: ~w\n", [debug_lookup_name(Id)]), + ?debug("Checking ref to fun: ~tw\n", [debug_lookup_name(Id)]), pp_map("Map", Map), pp_constr_data("solve_ref", V2State0), Map1 = restore_local_map(V2State0, Id, Map), @@ -1980,7 +1980,7 @@ v2_solve_reference(Id, Map, V2State0) -> {FunType, V2State} = case Res of {error, V2State1} -> - ?debug("Error solving for function ~p\n", [debug_lookup_name(Id)]), + ?debug("Error solving for function ~tp\n", [debug_lookup_name(Id)]), Arity = state__fun_arity(Id, State), FunType0 = case state__prop_domain(t_var_name(Id), State) of @@ -1989,12 +1989,12 @@ v2_solve_reference(Id, Map, V2State0) -> end, {FunType0, V2State1}; {ok, NewMap, V2State1, U} -> - ?debug("Done solving fun: ~p\n", [debug_lookup_name(Id)]), + ?debug("Done solving fun: ~tp\n", [debug_lookup_name(Id)]), FunType0 = lookup_type(Id, NewMap), V2State2 = save_local_map(V2State1, Id, U, NewMap), {FunType0, V2State2} end, - ?debug("ref Id=~w Assigned ~s\n", [Id, format_type(FunType)]), + ?debug("ref Id=~w Assigned ~ts\n", [Id, format_type(FunType)]), {NewMap1, U1} = enter_var_type(Id, FunType, Map), {NewMap2, U2} = case state__get_rec_var(Id, State) of @@ -2004,10 +2004,10 @@ v2_solve_reference(Id, Map, V2State0) -> {ok, NewMap2, V2State, lists:umerge(U1, U2)}. v2_solve_self_recursive(Cs, Map, Id, RecType0, V2State0) -> - ?debug("Solving self recursive ~w\n", [debug_lookup_name(Id)]), + ?debug("Solving self recursive ~tw\n", [debug_lookup_name(Id)]), State = V2State0#v2_state.state, {ok, RecVar} = state__get_rec_var(Id, State), - ?debug("OldRecType ~s\n", [format_type(RecType0)]), + ?debug("OldRecType ~ts\n", [format_type(RecType0)]), RecType = t_limit(RecType0, ?TYPE_LIMIT), {Map1, U0} = enter_var_type(RecVar, RecType, Map), V2State1 = save_updated_vars1(V2State0, Cs, U0), % Probably not necessary @@ -2319,7 +2319,7 @@ solve_ref_or_list(#constraint_ref{id = Id, deps = Deps}, error -> {map_new(), false}; {ok, M} -> {M, true} end, - ?debug("Checking ref to fun: ~w\n", [debug_lookup_name(Id)]), + ?debug("Checking ref to fun: ~tw\n", [debug_lookup_name(Id)]), %% Note: mk_constraint_ref() has already removed Id from Deps. The %% reason for doing it there is that it makes it easy for %% calculate_masks() to make the corresponding adjustment for @@ -2341,7 +2341,7 @@ solve_ref_or_list(#constraint_ref{id = Id, deps = Deps}, {NewMapDict, FunType} = case Res of {error, NewMapDict0} -> - ?debug("Error solving for function ~p\n", [debug_lookup_name(Id)]), + ?debug("Error solving for function ~tp\n", [debug_lookup_name(Id)]), Arity = state__fun_arity(Id, State), FunType0 = case state__prop_domain(t_var_name(Id), State) of @@ -2350,11 +2350,11 @@ solve_ref_or_list(#constraint_ref{id = Id, deps = Deps}, end, {NewMapDict0, FunType0}; {ok, NewMapDict0, NewMap} -> - ?debug("Done solving fun: ~p\n", [debug_lookup_name(Id)]), + ?debug("Done solving fun: ~tp\n", [debug_lookup_name(Id)]), FunType0 = lookup_type(Id, NewMap), {NewMapDict0, FunType0} end, - ?debug(" Id=~w Assigned ~s\n", [Id, format_type(FunType)]), + ?debug(" Id=~w Assigned ~ts\n", [Id, format_type(FunType)]), NewMap1 = enter_type(Id, FunType, Map), NewMap2 = case state__get_rec_var(Id, State) of @@ -2376,18 +2376,18 @@ solve_ref_or_list(#constraint_list{type=Type, list = Cs, deps = Deps, id = Id}, true -> case Check andalso maps_are_equal(OldLocalMap, Map, Deps) of true -> - ?debug("~w equal ~w\n", [Type, Id]), + ?debug("~tw equal ~w\n", [Type, Id]), {ok, MapDict, Map}; false -> - ?debug("~w not equal: ~w. Solving\n", [Type, Id]), + ?debug("~tw not equal: ~w. Solving\n", [Type, Id]), solve_clist(Cs, Type, Id, Deps, MapDict, Map, State) end end. solve_self_recursive(Cs, Map, MapDict, Id, RecType0, State) -> - ?debug("Solving self recursive ~w\n", [debug_lookup_name(Id)]), + ?debug("Solving self recursive ~tw\n", [debug_lookup_name(Id)]), {ok, RecVar} = state__get_rec_var(Id, State), - ?debug("OldRecType ~s\n", [format_type(RecType0)]), + ?debug("OldRecType ~ts\n", [format_type(RecType0)]), RecType = t_limit(RecType0, ?TYPE_LIMIT), Map1 = enter_type(RecVar, RecType, erase_type(t_var_name(Id), Map)), pp_map("Map1", Map1), @@ -2469,7 +2469,7 @@ solve_one_c(#constraint{lhs = Lhs, rhs = Rhs, op = Op}, Map) -> LhsType = lookup_type(Lhs, Map), RhsType = lookup_type(Rhs, Map), Inf = t_inf(LhsType, RhsType), - ?debug("Solving: ~s :: ~s ~w ~s :: ~s\n\tInf: ~s\n", + ?debug("Solving: ~ts :: ~ts ~w ~ts :: ~ts\n\tInf: ~ts\n", [format_type(Lhs), format_type(LhsType), Op, format_type(Rhs), format_type(RhsType), format_type(Inf)]), case t_is_none(Inf) of @@ -2501,14 +2501,14 @@ solve_subtype(Type, Inf, Map) -> {_, List} -> {ok, enter_type_list(List, Map)} catch throw:{mismatch, _T1, _T2} -> - ?debug("Mismatch between ~s and ~s\n", + ?debug("Mismatch between ~ts and ~ts\n", [format_type(_T1), format_type(_T2)]), error end. %% end. report_failed_constraint(_C, _Map) -> - ?debug("+++++++++++\nFailed: ~s :: ~s ~w ~s :: ~s\n+++++++++++\n", + ?debug("+++++++++++\nFailed: ~ts :: ~ts ~w ~ts :: ~ts\n+++++++++++\n", [format_type(_C#constraint.lhs), format_type(lookup_type(_C#constraint.lhs, _Map)), _C#constraint.op, @@ -2566,7 +2566,7 @@ maps_are_equal_1(Map1, Map2, [H|Tail]) -> case is_equal(T1, T2) of true -> maps_are_equal_1(Map1, Map2, Tail); false -> - ?debug("~w: ~s =/= ~s\n", [H, format_type(T1), format_type(T2)]), + ?debug("~w: ~ts =/= ~ts\n", [H, format_type(T1), format_type(T2)]), false end; maps_are_equal_1(_Map1, _Map2, []) -> @@ -2594,7 +2594,7 @@ prune_keys(Map1, Map2, Deps) -> end. enter_type(Key, Val, Map) when is_integer(Key) -> - ?debug("Entering ~s :: ~s\n", [format_type(t_var(Key)), format_type(Val)]), + ?debug("Entering ~ts :: ~ts\n", [format_type(t_var(Key)), format_type(Val)]), %% Keep any() in the map if it is opaque: case is_equal(Val, t_any()) of true -> @@ -2603,7 +2603,7 @@ enter_type(Key, Val, Map) when is_integer(Key) -> LimitedVal = t_limit(Val, ?INTERNAL_TYPE_LIMIT), case is_equal(LimitedVal, Val) of true -> ok; - false -> ?debug("LimitedVal ~s\n", [format_type(LimitedVal)]) + false -> ?debug("LimitedVal ~ts\n", [format_type(LimitedVal)]) end, case maps:find(Key, Map) of {ok, Value} -> @@ -2638,7 +2638,7 @@ enter_type2(Key, Val, Map) -> {Map1, [Key || not is_same(Key, Map, Map1)]}. map_store(Key, Val, Map) -> - ?debug("Storing ~w :: ~s\n", [Key, format_type(Val)]), + ?debug("Storing ~tw :: ~ts\n", [Key, format_type(Val)]), maps:put(Key, Val, Map). erase_type(Key, Map) -> @@ -2703,7 +2703,7 @@ is_equal(Type1, Type2) -> t_is_equal(Type1, Type2). pp_map(_S, _Map) -> - ?debug("\t~s: ~p\n", + ?debug("\t~s: ~tp\n", [_S, [{X, lists:flatten(format_type(Y))} || {X, Y} <- lists:keysort(1, maps:to_list(_Map))]]). @@ -2846,7 +2846,7 @@ state__add_prop_constrs(Tree, #state{prop_types = PropTypes} = State) -> case erl_types:any_none(ArgTypes) of true -> not_called; false -> - ?debug("Adding propagated constr: ~s for function ~w\n", + ?debug("Adding propagated constr: ~ts for function ~tw\n", [format_type(FunType), debug_lookup_name(mk_var(Tree))]), FunVar = mk_var(Tree), state__store_conj(FunVar, sub, FunType, State) @@ -3381,10 +3381,10 @@ family(L) -> -ifdef(DEBUG). format_type(#fun_var{deps = Deps, origin = Origin}) -> L = [format_type(t_var(X)) || X <- Deps], - io_lib:format("Fun@L~p(~s)", [Origin, join_chars(L, ",")]); + io_lib:format("Fun@L~p(~ts)", [Origin, join_chars(L, ",")]); format_type(Type) -> case cerl:is_literal(Type) of - true -> io_lib:format("~w", [cerl:concrete(Type)]); + true -> io_lib:format("~tw", [cerl:concrete(Type)]); false -> erl_types:t_to_string(Type) end. @@ -3426,7 +3426,7 @@ pp_constrs_scc(SCC, State) -> [pp_constrs(Fun, state__get_cs(Fun, State), State) || Fun <- SCC]. pp_constrs(Fun, Cs, State) -> - io:format("Constraints for fun: ~w", [debug_lookup_name(Fun)]), + io:format("Constraints for fun: ~tw", [debug_lookup_name(Fun)]), MaxDepth = pp_constraints(Cs, State), io:format("Depth: ~w\n", [MaxDepth]). @@ -3464,7 +3464,7 @@ pp_constraints([#constraint_list{type = Type, list = List, id = Id}|Tail], pp_op(#constraint{lhs = Lhs, op = Op, rhs = Rhs}, Level) -> pp_indent(Level), - io:format("~s ~w ~s", [format_type(Lhs), Op, format_type(Rhs)]). + io:format("~ts ~w ~ts", [format_type(Lhs), Op, format_type(Rhs)]). pp_indent(Level) -> io:format("\n~*s", [Level*2, ""]). @@ -3476,19 +3476,25 @@ pp_constrs_scc(_SCC, _State) -> -ifdef(TO_DOT). constraints_to_dot_scc(SCC, State) -> - io:format("SCC: ~p\n", [SCC]), - Name = lists:flatten([io_lib:format("'~w'", [debug_lookup_name(Fun)]) - || Fun <- SCC]), + %% TODO: handle Unicode names. + io:format("SCC: ~tp\n", [SCC]), + Name = lists:flatten([format_lookup_name(debug_lookup_name(Fun)) + || Fun <- SCC]), Cs = [state__get_cs(Fun, State) || Fun <- SCC], constraints_to_dot(Cs, Name, State). +format_lookup_name({FunName, Arity}) -> + TupleS = io_lib:format("{~ts,~w}", [atom_to_list(FunName), Arity]), + io_lib:format("~tw", [list_to_atom(lists:flatten(TupleS))]). + constraints_to_dot(Cs0, Name, State) -> NofCs = length(Cs0), Cs = lists:zip(lists:seq(1, NofCs), Cs0), {Graph, Opts, _N} = constraints_to_nodes(Cs, NofCs + 1, 1, [], [], State), hipe_dot:translate_list(Graph, "/tmp/cs.dot", "foo", Opts), + %% "-T ps" works for Latin-1. hipe_dot cannot handle UTF-8 either. Res = os:cmd("dot -o /tmp/"++ Name ++ ".ps -T ps /tmp/cs.dot"), - io:format("Res: ~p~n", [Res]), + io:format("Res: ~ts~n", [Res]), ok. constraints_to_nodes([{Name, #constraint_list{type = Type, list = List, id=Id}} @@ -3507,7 +3513,7 @@ constraints_to_nodes([{Name, #constraint_list{type = Type, list = List, id=Id}} constraints_to_nodes(Left, N2, Level, NewGraph, NewOpts, State); constraints_to_nodes([{Name, #constraint{lhs = Lhs, op = Op, rhs = Rhs}}|Left], N, Level, Graph, Opts, State) -> - Label = lists:flatten(io_lib:format("~s ~w ~s", + Label = lists:flatten(io_lib:format("~ts ~w ~ts", [format_type(Lhs), Op, format_type(Rhs)])), ThisNode = [{Name, Opt} || Opt <- [{label, Label}, {level, Level}]], diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index 75d6e3bc65..e5941d0ab8 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -56,15 +56,15 @@ print_types1([], _) -> ok; print_types1([{type, _Name, _NArgs} = Key|T], RecDict) -> {ok, {{_Mod, _FileLine, _Form, _Args}, Type}} = dict:find(Key, RecDict), - io:format("\n~w: ~w\n", [Key, Type]), + io:format("\n~tw: ~tw\n", [Key, Type]), print_types1(T, RecDict); print_types1([{opaque, _Name, _NArgs} = Key|T], RecDict) -> {ok, {{_Mod, _FileLine, _Form, _Args}, Type}} = dict:find(Key, RecDict), - io:format("\n~w: ~w\n", [Key, Type]), + io:format("\n~tw: ~tw\n", [Key, Type]), print_types1(T, RecDict); print_types1([{record, _Name} = Key|T], RecDict) -> {ok, {_FileLine, [{_Arity, _Fields} = AF]}} = dict:find(Key, RecDict), - io:format("~w: ~w\n\n", [Key, AF]), + io:format("~tw: ~tw\n\n", [Key, AF]), print_types1(T, RecDict). -define(debug(D_), print_types(D_)). -else. @@ -268,7 +268,7 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, FN, Arity = length(ArgForms), case erl_types:type_is_defined(TypeOrOpaque, Name, Arity, RecDict) of true -> - Msg = flat_format("Type ~s/~w already defined\n", [Name, Arity]), + Msg = flat_format("Type ~ts/~w already defined\n", [Name, Arity]), throw({error, Msg}); false -> try erl_types:t_var_names(ArgForms) of @@ -278,7 +278,7 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, FN, erl_types:t_any()}, RecDict) catch _:_ -> - throw({error, flat_format("Type declaration for ~w does not " + throw({error, flat_format("Type declaration for ~tw does not " "have variables as parameters", [Name])}) end end. @@ -433,7 +433,7 @@ msg_with_position(Fun, FileLine) -> throw:{error, Msg} -> {File, Line} = FileLine, BaseName = filename:basename(File), - NewMsg = io_lib:format("~s:~p: ~s", [BaseName, Line, Msg]), + NewMsg = io_lib:format("~ts:~p: ~ts", [BaseName, Line, Msg]), throw({error, NewMsg}) end. @@ -526,13 +526,13 @@ get_spec_info([{Contract, Ln, [{Id, TypeSpec}]}|Left], RecordsMap, ModName, OptCb, File); {ok, {{OtherFile, L}, _D}} -> {Mod, Fun, Arity} = MFA, - Msg = flat_format(" Contract/callback for function ~w:~w/~w " - "already defined in ~s:~w\n", + Msg = flat_format(" Contract/callback for function ~w:~tw/~w " + "already defined in ~ts:~w\n", [Mod, Fun, Arity, OtherFile, L]), throw({error, Msg}) catch throw:{error, Error} -> - {error, flat_format(" Error while parsing contract in line ~w: ~s\n", + {error, flat_format(" Error while parsing contract in line ~w: ~ts\n", [Ln, Error])} end; get_spec_info([{file, _, [{IncludeFile, _}]}|Left], @@ -635,7 +635,7 @@ get_options1([{Args, L, File}|Left], Warnings) -> get_options1(Left, NewWarnings) catch throw:{dialyzer_options_error, Msg} -> - Msg1 = flat_format(" ~s:~w: ~s", [File, L, Msg]), + Msg1 = flat_format(" ~ts:~w: ~ts", [File, L, Msg]), throw({error, Msg1}) end; get_options1([], Warnings) -> @@ -714,7 +714,7 @@ src_compiler_opts() -> format_errors([{Mod, Errors}|Left]) -> FormatedError = - [io_lib:format("~s:~w: ~s\n", [Mod, Line, M:format_error(Desc)]) + [io_lib:format("~ts:~w: ~ts\n", [Mod, Line, M:format_error(Desc)]) || {Line, M, Desc} <- Errors], [lists:flatten(FormatedError) | format_errors(Left)]; format_errors([]) -> @@ -759,14 +759,14 @@ check_fa_list1([{Args, L, File}|Left], Tag, Funcs) -> case lists:dropwhile(fun({_, T}) -> is_fa(T) end, TermsL) of [] -> ok; [{_, Bad}|_] -> - Msg1 = flat_format(" Bad function ~w in line ~s:~w", + Msg1 = flat_format(" Bad function ~tw in line ~ts:~w", [Bad, File, L]), throw({error, Msg1}) end, case lists:dropwhile(fun({_, FA}) -> is_known(FA, Funcs) end, TermsL) of [] -> ok; [{_, {F, A}}|_] -> - Msg2 = flat_format(" Unknown function ~w/~w in line ~s:~w", + Msg2 = flat_format(" Unknown function ~tw/~w in line ~ts:~w", [F, A, File, L]), throw({error, Msg2}) end, diff --git a/lib/dialyzer/src/typer.erl b/lib/dialyzer/src/typer.erl index 86c7c62f98..43e03be740 100644 --- a/lib/dialyzer/src/typer.erl +++ b/lib/dialyzer/src/typer.erl @@ -74,6 +74,7 @@ -spec start() -> no_return(). start() -> +_ = io:setopts(standard_error, [{encoding,unicode}]), {Args, Analysis} = process_cl_args(), %% io:format("Args: ~p\n", [Args]), %% io:format("Analysis: ~p\n", [Analysis]), @@ -81,7 +82,7 @@ start() -> TrustedFiles = filter_fd(Args#args.trusted, [], fun is_erl_file/1), Analysis2 = extract(Analysis, TrustedFiles), All_Files = get_all_files(Args), - %% io:format("All_Files: ~p\n", [All_Files]), + %% io:format("All_Files: ~tp\n", [All_Files]), Analysis3 = Analysis2#analysis{files = All_Files}, Analysis4 = collect_info(Analysis3), %% io:format("Final: ~p\n", [Analysis4#analysis.fms]), @@ -164,10 +165,10 @@ get_type_info(#analysis{callgraph = CallGraph, Analysis#analysis{callgraph = StrippedCallGraph, trust_plt = NewPlt} catch error:What -> - fatal_error(io_lib:format("Analysis failed with message: ~p", + fatal_error(io_lib:format("Analysis failed with message: ~tp", [{What, erlang:get_stacktrace()}])); throw:{dialyzer_succ_typing_error, Msg} -> - fatal_error(io_lib:format("Analysis failed with message: ~s", [Msg])) + fatal_error(io_lib:format("Analysis failed with message: ~ts", [Msg])) end. -spec remove_external(callgraph(), plt()) -> callgraph(). @@ -177,11 +178,11 @@ remove_external(CallGraph, PLT) -> case get_external(Ext, PLT) of [] -> ok; Externals -> - msg(io_lib:format(" Unknown functions: ~p\n", [lists:usort(Externals)])), + msg(io_lib:format(" Unknown functions: ~tp\n", [lists:usort(Externals)])), ExtTypes = rcv_ext_types(), case ExtTypes of [] -> ok; - _ -> msg(io_lib:format(" Unknown types: ~p\n", [ExtTypes])) + _ -> msg(io_lib:format(" Unknown types: ~tp\n", [ExtTypes])) end end, StrippedCG0. @@ -257,9 +258,9 @@ write_inc_files(Inc) -> records = maps:new(), %% Note we need to sort functions here! functions = lists:keysort(1, Functions)}, - %% io:format("Types ~p\n", [Info#info.types]), - %% io:format("Functions ~p\n", [Info#info.functions]), - %% io:format("Records ~p\n", [Info#info.records]), + %% io:format("Types ~tp\n", [Info#info.types]), + %% io:format("Functions ~tp\n", [Info#info.functions]), + %% io:format("Records ~tp\n", [Info#info.records]), write_typed_file(File, Info) end, lists:foreach(Fun, dict:fetch_keys(Inc#inc.map)). @@ -349,8 +350,8 @@ check_imported_functions({File, {Line, F, A}}, Inc, Types) -> end. inc_warning({F, A}, File) -> - io:format(" ***Warning: Skip function ~p/~p ", [F, A]), - io:format("in file ~p because of inconsistent type\n", [File]). + io:format(" ***Warning: Skip function ~tp/~p ", [F, A]), + io:format("in file ~tp because of inconsistent type\n", [File]). clean_inc(Inc) -> Inc1 = remove_yecc_generated_file(Inc), @@ -407,13 +408,13 @@ get_type({{M, F, A} = MFA, Range, Arg}, CodeServer, Records) -> {error, invalid_contract} -> CString = dialyzer_contracts:contract_to_string(Contract), SigString = dialyzer_utils:format_sig(Sig, Records), - Msg = io_lib:format("Error in contract of function ~w:~w/~w\n" + Msg = io_lib:format("Error in contract of function ~w:~tw/~w\n" "\t The contract is: " ++ CString ++ "\n" ++ - "\t but the inferred signature is: ~s", + "\t but the inferred signature is: ~ts", [M, F, A, SigString]), fatal_error(Msg); {error, ErrorStr} when is_list(ErrorStr) -> % ErrorStr is a string() - Msg = io_lib:format("Error in contract of function ~w:~w/~w: ~s", + Msg = io_lib:format("Error in contract of function ~w:~tw/~w: ~ts", [M, F, A, ErrorStr]), fatal_error(Msg) end @@ -448,7 +449,7 @@ remove_module_info(FunInfoList) -> lists:filter(F, FunInfoList). write_typed_file(File, Info) -> - io:format(" Processing file: ~p\n", [File]), + io:format(" Processing file: ~tp\n", [File]), Dir = filename:dirname(File), RootName = filename:basename(filename:rootname(File)), Ext = filename:extension(File), @@ -463,18 +464,18 @@ write_typed_file(File, Info) -> ok -> ok; {error, enoent} -> ok; {error, _} -> - Msg = io_lib:format("Error in deleting file ~s\n", [NewFileName]), + Msg = io_lib:format("Error in deleting file ~ts\n", [NewFileName]), fatal_error(Msg) end, write_typed_file(File, Info, NewFileName); enospc -> - Msg = io_lib:format("Not enough space in ~p\n", [Dir]), + Msg = io_lib:format("Not enough space in ~tp\n", [Dir]), fatal_error(Msg); eacces -> - Msg = io_lib:format("No write permission in ~p\n", [Dir]), + Msg = io_lib:format("No write permission in ~tp\n", [Dir]), fatal_error(Msg); _ -> - Msg = io_lib:format("Unhandled error ~s when writing ~p\n", + Msg = io_lib:format("Unhandled error ~ts when writing ~tp\n", [Reason, Dir]), fatal_error(Msg) end; @@ -486,7 +487,7 @@ write_typed_file(File, Info, NewFileName) -> {ok, Binary} = file:read_file(File), Chars = binary_to_list(Binary), write_typed_file(Chars, NewFileName, Info, 1, []), - io:format(" Saved as: ~p\n", [NewFileName]). + io:format(" Saved as: ~tp\n", [NewFileName]). write_typed_file(Chars, File, #info{functions = []}, _LNo, _Acc) -> ok = file:write_file(File, list_to_binary(Chars), [append]); @@ -546,12 +547,12 @@ get_type_string(F, A, Info, Mode) -> end. show_type_info(File, Info) -> - io:format("\n%% File: ~p\n%% ", [File]), + io:format("\n%% File: ~tp\n%% ", [File]), OutputString = lists:concat(["~.", length(File)+8, "c~n"]), io:fwrite(OutputString, [$-]), Fun = fun ({_LineNo, F, A}) -> TypeInfo = get_type_string(F, A, Info, show), - io:format("~s\n", [TypeInfo]) + io:format("~ts\n", [TypeInfo]) end, lists:foreach(Fun, Info#info.functions). @@ -561,7 +562,7 @@ get_type_info(Func, Types) -> %% Note: Typeinfo of any function should exist in %% the result offered by dialyzer, otherwise there %% *must* be something wrong with the analysis - Msg = io_lib:format("No type info for function: ~p\n", [Func]), + Msg = io_lib:format("No type info for function: ~tp\n", [Func]), fatal_error(Msg); {contract, _Fun} = C -> C; {_RetType, _ArgType} = RA -> RA @@ -575,7 +576,7 @@ get_type_info(Func, Types) -> process_cl_args() -> ArgList = init:get_plain_arguments(), - %% io:format("Args is ~p\n", [ArgList]), + %% io:format("Args is ~tp\n", [ArgList]), {Args, Analysis} = analyze_args(ArgList, #args{}, #analysis{}), %% if the mode has not been set, set it to the default mode (show) {Args, case Analysis#analysis.mode of @@ -848,7 +849,7 @@ collect_one_file_info(File, Analysis) -> Options = dialyzer_utils:src_compiler_opts() ++ Is ++ Ds, case dialyzer_utils:get_core_from_src(File, Options) of {error, Reason} -> - %% io:format("File=~p\n,Options=~p\n,Error=~p\n", [File,Options,Reason]), + %% io:format("File=~tp\n,Options=~p\n,Error=~p\n", [File,Options,Reason]), compile_error(Reason); {ok, Core} -> case dialyzer_utils:get_record_and_type_info(Core) of @@ -922,7 +923,7 @@ analyze_one_function({Var, FunBody} = Function, Acc) -> {FuncAcc, IncFuncAcc} = case (FileName =:= OriginalName) orelse (BaseName =:= OriginalName) of true -> %% Coming from original file - %% io:format("Added function ~p\n", [{LineNo, F, A}]), + %% io:format("Added function ~tp\n", [{LineNo, F, A}]), {Acc#tmpAcc.funcAcc ++ [FuncInfo], Acc#tmpAcc.incFuncAcc}; false -> %% Coming from other sourses, including: @@ -972,7 +973,7 @@ get_exported_types_from_core(Core) -> -spec fatal_error(string()) -> no_return(). fatal_error(Slogan) -> - msg(io_lib:format("typer: ~s\n", [Slogan])), + msg(io_lib:format("typer: ~ts\n", [Slogan])), erlang:halt(1). -spec mode_error(mode(), mode()) -> no_return(). @@ -993,7 +994,7 @@ compile_error(Reason) -> -spec msg(string()) -> 'ok'. msg(Msg) -> - io:format(standard_error, "~s", [Msg]). + io:format(standard_error, "~ts", [Msg]). %%-------------------------------------------------------------------- %% Version and help messages. diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs index 38999e8919..843d26ee59 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs @@ -1,5 +1,5 @@ -my_callbacks_wrong.erl:26: The return type #state{parent::pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()} in the specification of callback_init/1 is not a subtype of {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour -my_callbacks_wrong.erl:28: The inferred return type of callback_init/1 (#state{parent::pid(),status::'init',subscribe::[],counter::1}) has nothing in common with {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour -my_callbacks_wrong.erl:30: The return type {'reply',#state{parent::pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} in the specification of callback_cast/3 is not a subtype of {'noreply',_}, which is the expected return type for the callback of my_behaviour behaviour +my_callbacks_wrong.erl:26: The return type #state{parent::pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()} in the specification of callback_init/1 is not a subtype of {'ok',_}, which is the expected return type for the callback of the my_behaviour behaviour +my_callbacks_wrong.erl:28: The inferred return type of callback_init/1 (#state{parent::pid(),status::'init',subscribe::[],counter::1}) has nothing in common with {'ok',_}, which is the expected return type for the callback of the my_behaviour behaviour +my_callbacks_wrong.erl:30: The return type {'reply',#state{parent::pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} in the specification of callback_cast/3 is not a subtype of {'noreply',_}, which is the expected return type for the callback of the my_behaviour behaviour my_callbacks_wrong.erl:39: The specified type for the 2nd argument of callback_call/3 (atom()) is not a supertype of pid(), which is expected type for this argument in the callback of the my_behaviour behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return index e646eea383..c3ebee05da 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return @@ -1,2 +1,2 @@ -gen_event_incorrect_return.erl:16: The inferred return type of init/1 ('error') has nothing in common with {'error',_} | {'ok',_} | {'ok',_,'hibernate'}, which is the expected return type for the callback of gen_event behaviour +gen_event_incorrect_return.erl:16: The inferred return type of init/1 ('error') has nothing in common with {'error',_} | {'ok',_} | {'ok',_,'hibernate'}, which is the expected return type for the callback of the gen_event behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args index 2f504d3c72..1eb8cd455b 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args @@ -1,5 +1,5 @@ -gen_server_incorrect_args.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server') -gen_server_incorrect_args.erl:3: Undefined callback function init/1 (behaviour 'gen_server') -gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of gen_server behaviour +gen_server_incorrect_args.erl:3: Undefined callback function handle_cast/2 (behaviour gen_server) +gen_server_incorrect_args.erl:3: Undefined callback function init/1 (behaviour gen_server) +gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of the gen_server behaviour gen_server_incorrect_args.erl:7: The inferred type for the 2nd argument of handle_call/3 ('boo' | 'foo') is not a supertype of {pid(),_}, which is expected type for this argument in the callback of the gen_server behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks index 0a7642a9b5..188f7822fa 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks @@ -1,2 +1,2 @@ -gen_server_missing_callbacks.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server') +gen_server_missing_callbacks.erl:3: Undefined callback function handle_cast/2 (behaviour gen_server) diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour index 8cecabccaa..68adf4cfa0 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour @@ -1,9 +1,9 @@ -sample_callback_wrong.erl:16: The inferred return type of sample_callback_2/0 (42) has nothing in common with atom(), which is the expected return type for the callback of sample_behaviour behaviour -sample_callback_wrong.erl:17: The inferred return type of sample_callback_3/0 ('fair') has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour -sample_callback_wrong.erl:18: The inferred return type of sample_callback_4/1 ('fail') has nothing in common with 'ok', which is the expected return type for the callback of sample_behaviour behaviour -sample_callback_wrong.erl:20: The inferred return type of sample_callback_5/1 (string()) has nothing in common with 'fail' | 'ok', which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:16: The inferred return type of sample_callback_2/0 (42) has nothing in common with atom(), which is the expected return type for the callback of the sample_behaviour behaviour +sample_callback_wrong.erl:17: The inferred return type of sample_callback_3/0 ('fair') has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of the sample_behaviour behaviour +sample_callback_wrong.erl:18: The inferred return type of sample_callback_4/1 ('fail') has nothing in common with 'ok', which is the expected return type for the callback of the sample_behaviour behaviour +sample_callback_wrong.erl:20: The inferred return type of sample_callback_5/1 (string()) has nothing in common with 'fail' | 'ok', which is the expected return type for the callback of the sample_behaviour behaviour sample_callback_wrong.erl:20: The inferred type for the 1st argument of sample_callback_5/1 (atom()) is not a supertype of 1..255, which is expected type for this argument in the callback of the sample_behaviour behaviour -sample_callback_wrong.erl:22: The inferred return type of sample_callback_6/3 ({'okk',number()}) has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour +sample_callback_wrong.erl:22: The inferred return type of sample_callback_6/3 ({'okk',number()}) has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of the sample_behaviour behaviour sample_callback_wrong.erl:22: The inferred type for the 3rd argument of sample_callback_6/3 (atom()) is not a supertype of string(), which is expected type for this argument in the callback of the sample_behaviour behaviour -sample_callback_wrong.erl:4: Undefined callback function sample_callback_1/0 (behaviour 'sample_behaviour') +sample_callback_wrong.erl:4: Undefined callback function sample_callback_1/0 (behaviour sample_behaviour) diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old index f0181bb59c..67aa872984 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old @@ -1,4 +1,4 @@ incorrect_args_callback.erl:12: The inferred type for the 2nd argument of bar/2 ('yes') is not a supertype of [any()], which is expected type for this argument in the callback of the correct_behaviour behaviour -incorrect_return_callback.erl:9: The inferred return type of foo/0 ('error') has nothing in common with 'no' | 'yes', which is the expected return type for the callback of correct_behaviour behaviour -missing_callback.erl:5: Undefined callback function foo/0 (behaviour 'correct_behaviour') +incorrect_return_callback.erl:9: The inferred return type of foo/0 ('error') has nothing in common with 'no' | 'yes', which is the expected return type for the callback of the correct_behaviour behaviour +missing_callback.erl:5: Undefined callback function foo/0 (behaviour correct_behaviour) diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return index 638d031923..5a063a12b8 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return @@ -1,2 +1,2 @@ -supervisor_incorrect_return.erl:14: The inferred return type of init/1 ({'ok',{{'one_against_one',0,1},[{_,_,_,_,_,_},...]}}) has nothing in common with 'ignore' | {'ok',{{'one_for_all',non_neg_integer(),pos_integer()} | {'one_for_one',non_neg_integer(),pos_integer()} | {'rest_for_one',non_neg_integer(),pos_integer()} | {'simple_one_for_one',non_neg_integer(),pos_integer()} | #{'intensity'=>non_neg_integer(), 'period'=>pos_integer(), 'strategy'=>'one_for_all' | 'one_for_one' | 'rest_for_one' | 'simple_one_for_one'},[{_,{atom(),atom(),'undefined' | [any()]},'permanent' | 'temporary' | 'transient','brutal_kill' | 'infinity' | non_neg_integer(),'supervisor' | 'worker','dynamic' | [atom()]} | #{'id':=_, 'start':={atom(),atom(),'undefined' | [any()]}, 'modules'=>'dynamic' | [atom()], 'restart'=>'permanent' | 'temporary' | 'transient', 'shutdown'=>'brutal_kill' | 'infinity' | non_neg_integer(), 'type'=>'supervisor' | 'worker'}]}}, which is the expected return type for the callback of supervisor behaviour +supervisor_incorrect_return.erl:14: The inferred return type of init/1 ({'ok',{{'one_against_one',0,1},[{_,_,_,_,_,_},...]}}) has nothing in common with 'ignore' | {'ok',{{'one_for_all',non_neg_integer(),pos_integer()} | {'one_for_one',non_neg_integer(),pos_integer()} | {'rest_for_one',non_neg_integer(),pos_integer()} | {'simple_one_for_one',non_neg_integer(),pos_integer()} | #{'intensity'=>non_neg_integer(), 'period'=>pos_integer(), 'strategy'=>'one_for_all' | 'one_for_one' | 'rest_for_one' | 'simple_one_for_one'},[{_,{atom(),atom(),'undefined' | [any()]},'permanent' | 'temporary' | 'transient','brutal_kill' | 'infinity' | non_neg_integer(),'supervisor' | 'worker','dynamic' | [atom()]} | #{'id':=_, 'start':={atom(),atom(),'undefined' | [any()]}, 'modules'=>'dynamic' | [atom()], 'restart'=>'permanent' | 'temporary' | 'transient', 'shutdown'=>'brutal_kill' | 'infinity' | non_neg_integer(), 'type'=>'supervisor' | 'worker'}]}}, which is the expected return type for the callback of the supervisor behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec b/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec index 512dcdd758..f313c24420 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec @@ -1,4 +1,4 @@ -vars_in_beh_spec.erl:3: Undefined callback function handle_call/3 (behaviour 'gen_server') -vars_in_beh_spec.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server') -vars_in_beh_spec.erl:3: Undefined callback function init/1 (behaviour 'gen_server') +vars_in_beh_spec.erl:3: Undefined callback function handle_call/3 (behaviour gen_server) +vars_in_beh_spec.erl:3: Undefined callback function handle_cast/2 (behaviour gen_server) +vars_in_beh_spec.erl:3: Undefined callback function init/1 (behaviour gen_server) diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 4cfa80f153..4d7f1be513 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -4249,8 +4249,8 @@ t_to_string(?opaque(Set), RecDict) -> <- set_to_list(Set)], " | "); t_to_string(?matchstate(Pres, Slots), RecDict) -> - flat_format("ms(~s,~s)", [t_to_string(Pres, RecDict), - t_to_string(Slots,RecDict)]); + flat_format("ms(~ts,~ts)", [t_to_string(Pres, RecDict), + t_to_string(Slots,RecDict)]); t_to_string(?nil, _RecDict) -> "[]"; t_to_string(?nonempty_list(Contents, Termination), RecDict) -> @@ -4428,10 +4428,10 @@ opaque_type(Mod, Name, Args, _S, RecDict) -> opaque_name(Mod, Name, Extra) -> S = mod_name(Mod, Name), - flat_format("~s(~s)", [S, Extra]). + flat_format("~ts(~ts)", [S, Extra]). mod_name(Mod, Name) -> - flat_format("~w:~w", [Mod, Name]). + flat_format("~w:~tw", [Mod, Name]). %%============================================================================= %% @@ -4800,7 +4800,7 @@ type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) -> {NewType, L3, C4} end; error -> - Msg = io_lib:format("Unable to find type ~w/~w\n", + Msg = io_lib:format("Unable to find type ~tw/~w\n", [Name, ArgsLen]), throw({error, Msg}) end. @@ -4872,7 +4872,7 @@ remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames, {NewType, L3, C4} end; error -> - Msg = io_lib:format("Unable to find remote type ~w:~w()\n", + Msg = io_lib:format("Unable to find remote type ~w:~tw()\n", [RemMod, Name]), throw({error, Msg}) end. @@ -4917,7 +4917,7 @@ record_from_form({atom, _, Name}, ModFields, S, D0, L0, C) -> case GetModRec of {error, FieldName} -> throw({error, - io_lib:format("Illegal declaration of #~w{~w}\n", + io_lib:format("Illegal declaration of #~tw{~tw}\n", [Name, FieldName])}); {ok, NewFields} -> S2 = S1#from_form{vtab = var_table__new()}, @@ -4931,7 +4931,7 @@ record_from_form({atom, _, Name}, ModFields, S, D0, L0, C) -> end, recur_limit(Fun, D0, L0, RecordType, TypeNames); error -> - throw({error, io_lib:format("Unknown record #~w{}\n", [Name])}) + throw({error, io_lib:format("Unknown record #~tw{}\n", [Name])}) end; false -> {t_any(), L0, C} @@ -5105,8 +5105,8 @@ check_record({atom, _, Name}, ModFields, S, C) -> {ok, DeclFields} = lookup_record(Name, R), case check_fields(Name, ModFields, DeclFields, S, C1) of {error, FieldName} -> - throw({error, io_lib:format("Illegal declaration of #~w{~w}\n", - [Name, FieldName])}); + throw({error, io_lib:format("Illegal declaration of #~tw{~tw}\n", + [Name, FieldName])}); C2 -> C2 end. @@ -5199,10 +5199,10 @@ t_form_to_string({op, _L, _Op, _Arg1, _Arg2} = Op) -> t_form_to_string({ann_type, _L, [Var, Type]}) -> t_form_to_string(Var) ++ "::" ++ t_form_to_string(Type); t_form_to_string({paren_type, _L, [Type]}) -> - flat_format("(~s)", [t_form_to_string(Type)]); + flat_format("(~ts)", [t_form_to_string(Type)]); t_form_to_string({remote_type, _L, [{atom, _, Mod}, {atom, _, Name}, Args]}) -> ArgString = "(" ++ string:join(t_form_to_string_list(Args), ",") ++ ")", - flat_format("~w:~w", [Mod, Name]) ++ ArgString; + flat_format("~w:~tw", [Mod, Name]) ++ ArgString; t_form_to_string({type, _L, arity, []}) -> "arity()"; t_form_to_string({type, _L, binary, []}) -> "binary()"; t_form_to_string({type, _L, binary, [Base, Unit]} = Type) -> @@ -5252,12 +5252,12 @@ t_form_to_string({type, _L, range, [From, To]} = Type) -> _ -> flat_format("Badly formed type ~w",[Type]) end; t_form_to_string({type, _L, record, [{atom, _, Name}]}) -> - flat_format("#~w{}", [Name]); + flat_format("#~tw{}", [Name]); t_form_to_string({type, _L, record, [{atom, _, Name}|Fields]}) -> FieldString = string:join(t_form_to_string_list(Fields), ","), - flat_format("#~w{~s}", [Name, FieldString]); + flat_format("#~tw{~ts}", [Name, FieldString]); t_form_to_string({type, _L, field_type, [{atom, _, Name}, Type]}) -> - flat_format("~w::~s", [Name, t_form_to_string(Type)]); + flat_format("~tw::~ts", [Name, t_form_to_string(Type)]); t_form_to_string({type, _L, term, []}) -> "term()"; t_form_to_string({type, _L, timeout, []}) -> "timeout()"; t_form_to_string({type, _L, tuple, any}) -> "tuple()"; @@ -5281,7 +5281,7 @@ t_form_to_string({type, _L, Name, []} = T) -> catch throw:{error, _} -> atom_to_string(Name) ++ "()" end; t_form_to_string({user_type, _L, Name, List}) -> - flat_format("~w(~s)", + flat_format("~tw(~ts)", [Name, string:join(t_form_to_string_list(List), ",")]); t_form_to_string({type, L, Name, List}) -> %% Compatibility: modules compiled before Erlang/OTP 18.0. @@ -5298,7 +5298,7 @@ t_form_to_string_list([], Acc) -> -spec atom_to_string(atom()) -> string(). atom_to_string(Atom) -> - flat_format("~w", [Atom]). + flat_format("~tw", [Atom]). %%============================================================================= %% @@ -5551,7 +5551,7 @@ set_size(Set) -> set_to_string(Set) -> L = [case is_atom(X) of true -> io_lib:write_string(atom_to_list(X), $'); % stupid emacs ' - false -> flat_format("~w", [X]) + false -> flat_format("~tw", [X]) end || X <- set_to_list(Set)], string:join(L, " | "). diff --git a/lib/kernel/src/group_history.erl b/lib/kernel/src/group_history.erl index 5ca5e2d1dd..91f3663cc5 100644 --- a/lib/kernel/src/group_history.erl +++ b/lib/kernel/src/group_history.erl @@ -218,7 +218,7 @@ handle_open_error({invalid_header, Term}) -> [Term]); handle_open_error({file_error, FileName, Reason}) -> show('$#erlang-history-file-error', - "Error handling File ~s. Reason: ~p~n" + "Error handling File ~ts. Reason: ~p~n" "History logging will be disabled.~n", [FileName, Reason]); handle_open_error(Err) -> @@ -309,7 +309,7 @@ show_rename_warning() -> show_invalid_file_warning(FileName) -> show('$#erlang-history-invalid-file', - "Shell history expects to be able to use the file ~s " + "Shell history expects to be able to use the file ~ts " "which currently exists and is not a file usable for " "history logging purposes. History logging will be " "disabled.~n", [FileName]). diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl index 8c8fe86811..e3fdb1bb22 100644 --- a/lib/kernel/src/inet_tcp_dist.erl +++ b/lib/kernel/src/inet_tcp_dist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2017. 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. @@ -390,14 +390,14 @@ splitnode(Driver, Node, LongOrShortNames) -> error_msg("** System running to use " "fully qualified " "hostnames **~n" - "** Hostname ~s is illegal **~n", + "** Hostname ~ts is illegal **~n", [Host]), ?shutdown(Node) end; L when length(L) > 1, LongOrShortNames =:= shortnames -> error_msg("** System NOT running to use fully qualified " "hostnames **~n" - "** Hostname ~s is illegal **~n", + "** Hostname ~ts is illegal **~n", [Host]), ?shutdown(Node); _ -> diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl index fe958e9738..91d6cd49a6 100644 --- a/lib/parsetools/include/yeccpre.hrl +++ b/lib/parsetools/include/yeccpre.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. 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. @@ -151,21 +151,20 @@ yecctoken_location(Token) -> end. -compile({nowarn_unused_function, yecctoken2string/1}). -yecctoken2string({atom, _, A}) -> io_lib:write(A); +yecctoken2string({atom, _, A}) -> io_lib:write_atom(A); yecctoken2string({integer,_,N}) -> io_lib:write(N); yecctoken2string({float,_,F}) -> io_lib:write(F); yecctoken2string({char,_,C}) -> io_lib:write_char(C); yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]); yecctoken2string({string,_,S}) -> io_lib:write_string(S); yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A); -yecctoken2string({_Cat, _, Val}) -> io_lib:format("~p",[Val]); +yecctoken2string({_Cat, _, Val}) -> io_lib:format("~tp", [Val]); yecctoken2string({dot, _}) -> "'.'"; -yecctoken2string({'$end', _}) -> - []; +yecctoken2string({'$end', _}) -> []; yecctoken2string({Other, _}) when is_atom(Other) -> - io_lib:write(Other); + io_lib:write_atom(Other); yecctoken2string(Other) -> - io_lib:write(Other). + io_lib:format("~tp", [Other]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index 48559ec402..36e33b52a4 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -2597,18 +2597,18 @@ format_symbol(Symbol) -> String = concat([Symbol]), case erl_scan:string(String) of {ok, [{atom, _, _}], _} -> - io_lib:fwrite(<<"~w">>, [Symbol]); + io_lib:fwrite(<<"~tw">>, [Symbol]); {ok, [{Word, _}], _} when Word =/= ':', Word =/= '->' -> case erl_scan:reserved_word(Word) of true -> String; false -> - io_lib:fwrite(<<"~w">>, [Symbol]) + io_lib:fwrite(<<"~tw">>, [Symbol]) end; {ok, [{var, _, _}], _} -> String; _ -> - io_lib:fwrite(<<"~w">>, [Symbol]) + io_lib:fwrite(<<"~tw">>, [Symbol]) end. inverse(L) -> diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index f17aa528ed..9989cf5c07 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. 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. @@ -50,7 +50,7 @@ fun2ms(ShellFun) when is_function(ShellFun) -> case ms_transform:transform_from_shell( ?MODULE,Clauses,ImportList) of {error,[{_,[{_,_,Code}|_]}|_],_} -> - io:format("Error: ~s~n", + io:format("Error: ~ts~n", [ms_transform:format_error(Code)]), {error,transform_error}; Else -> diff --git a/lib/sasl/test/sasl_report_SUITE.erl b/lib/sasl/test/sasl_report_SUITE.erl index aa229726ae..eb0a877c45 100644 --- a/lib/sasl/test/sasl_report_SUITE.erl +++ b/lib/sasl/test/sasl_report_SUITE.erl @@ -79,7 +79,7 @@ do_gen_server_crash(Config) -> error_logger:logfile(close), check_file(KernelLog, 70000, 150000), - check_file(SaslLog, 50000, 100000), + check_file(SaslLog, 100000, 150000), ok. diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 5c9ce3d5fb..ea7e975ef5 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -320,6 +320,29 @@ attempted.</p> </item> + <!--tag><c><![CDATA[{send_ext_info, boolean()}]]></c></tag> + <item> + <p>Send a list of extensions to the server if the server has asked for it. See + <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details. + </p> + <p>Currently the client do not react on any extensions. + </p> + <p>Default value is <c>true</c>. + </p> + </item--> + + <tag><c><![CDATA[{recv_ext_info, boolean()}]]></c></tag> + <item> + <p>Tell the server that the client accepts extension negotiation. See + <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details. + </p> + <p>Currently implemented extension is <c>server-sig-algs</c> which is the list of the server's preferred + user's public key algorithms. + </p> + <p>Default value is <c>true</c>. + </p> + </item> + <tag><c><![CDATA[{key_cb, key_cb()}]]></c></tag> <item> <p>Module implementing the behaviour <seealso @@ -685,6 +708,27 @@ </p> </item> + <tag><c><![CDATA[{send_ext_info, boolean()}]]></c></tag> + <item> + <p>Send a list of extensions to the client if the client has asked for it. See + <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details. + </p> + <p>Currently implemented extension is sending <c>server-sig-algs</c> which is the list of the server's preferred + user's public key algorithms. + </p> + <p>Default value is <c>true</c>. + </p> + </item> + + <!--tag><c><![CDATA[{recv_ext_info, boolean()}]]></c></tag> + <item> + <p>Tell the client that the server accepts extension negotiation. See + <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details. + </p> + <p>Default value is <c>true</c>. + </p> + </item--> + <tag><c><![CDATA[{key_cb, key_cb()}]]></c></tag> <item> <p>Module implementing the behaviour <seealso diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml index 74c4111338..33ec7aaee0 100644 --- a/lib/ssh/doc/src/ssh_app.xml +++ b/lib/ssh/doc/src/ssh_app.xml @@ -161,6 +161,8 @@ <item>ecdsa-sha2-nistp521</item> <item>ssh-rsa</item> <item>ssh-dss</item> + <item>rsa-sha2-256</item> + <item>rsa-sha2-512</item> </list> </item> @@ -176,21 +178,23 @@ <tag>Encryption algorithms (ciphers)</tag> <item> <list type="bulleted"> - <item>[email protected] (AEAD_AES_128_GCM)</item> - <item>[email protected] (AEAD_AES_256_GCM)</item> + <item>[email protected]</item> + <item>[email protected]</item> <item>aes128-ctr</item> <item>aes192-ctr</item> <item>aes256-ctr</item> <item>aes128-cbc</item> <item>3des-cbc</item> + <item>(AEAD_AES_128_GCM, not enabled per default)</item> + <item>(AEAD_AES_256_GCM, not enabled per default)</item> </list> + <p>See the text at the description of <seealso marker="#rfc5647_note">the rfc 5647 further down</seealso> + for more information regarding AEAD_AES_*_GCM. + </p> <p>Following the internet de-facto standard, the cipher and mac algorithm AEAD_AES_128_GCM is selected when the cipher [email protected] is negotiated. The cipher and mac algorithm AEAD_AES_256_GCM is selected when the cipher [email protected] is negotiated. </p> - <p>See the text at the description of <seealso marker="#rfc5647_note">the rfc 5647 further down</seealso> - for more information. - </p> </item> <tag>Compression algorithms</tag> @@ -235,7 +239,11 @@ </item> <item><url href="https://tools.ietf.org/html/rfc4253">RFC 4253</url>, The Secure Shell (SSH) Transport Layer Protocol. - <p></p> + <p>Except</p> + <list type="bulleted"> + <item>8.1. diffie-hellman-group1-sha1. Disabled by default, can be enabled with the <c>preferred_algorithms</c> option.</item> + </list> + <p/> </item> <item><url href="https://tools.ietf.org/html/rfc4254">RFC 4254</url>, The Secure Shell (SSH) Connection Protocol. @@ -310,7 +318,29 @@ </p> </item> - <item>Work in progress: <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-kex-sha2">https://tools.ietf.org/html/draft-ietf-curdle-ssh-kex-sha2-05</url>, Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH)</item> + <item><url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-kex-sha2">Draft-ietf-curdle-ssh-kex-sha2 (work in progress)</url>, Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH). + <p>Deviations:</p> + <list type="bulleted"> + <item>The <c>diffie-hellman-group1-sha1</c> is not enabled by default, but is still supported and can be enabled + with the option <c>preferred-algorithms</c></item> + <item>The questionable sha1-based algorithms <c>diffie-hellman-group-exchange-sha1</c> and + <c>diffie-hellman-group14-sha1</c> are still enabled by default for compatibility with ancient clients and servers. + They can be disabled with the option <c>preferred-algorithms</c></item> + </list> + <p/> + </item> + + <item><url href="https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2">Draft-ietf-curdle-rsa-sha2 (work in progress)</url>, Use of RSA Keys with SHA-2 256 and 512 in Secure Shell (SSH). + </item> + + <item><url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url>, Extension Negotiation in Secure Shell (SSH). + <p>Implemented are:</p> + <list type="bulleted"> + <item>The Extension Negotiation Mechanism</item> + <item>The extension <c>server-sig-algs</c></item> + </list> + <p/> + </item> </list> diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index eb6f43d417..2822bf808f 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -558,8 +558,14 @@ <taglist> <tag><c><![CDATA[{timeout, timeout()}]]></c></tag> <item> - <p>The time-out is passed to the <c>ssh_channel</c> start function, - and defaults to <c>infinity</c>.</p> + <p>There are two ways to set a timeout for the underlying ssh connection:</p> + <list> + <item>If the connection timeout option <c>connect_timeout</c> is set, that value + is used also for the negotiation timeout and this option (<c>timeout</c>) is ignored.</item> + <item>Otherwise, this option (<c>timeout</c>) is used as the negotiation timeout + only and there is no connection timeout set</item> + </list> + <p>The value defaults to <c>infinity</c>.</p> </item> <tag> <c><![CDATA[{sftp_vsn, integer()}]]></c> diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl index b710ca8fb7..8b454ffe5d 100644 --- a/lib/ssh/test/ssh_options_SUITE.erl +++ b/lib/ssh/test/ssh_options_SUITE.erl @@ -555,14 +555,14 @@ connectfun_disconnectfun_server(Config) -> {disconnect,Ref,R} -> ct:log("Disconnect result: ~p",[R]), ssh:stop_daemon(Pid) - after 5000 -> + after 10000 -> receive X -> ct:log("received ~p",[X]) after 0 -> ok end, {fail, "No disconnectfun action"} end - after 5000 -> + after 10000 -> receive X -> ct:log("received ~p",[X]) after 0 -> ok diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl index 0385e30ad1..0837fe7eaf 100644 --- a/lib/ssh/test/ssh_protocol_SUITE.erl +++ b/lib/ssh/test/ssh_protocol_SUITE.erl @@ -466,7 +466,7 @@ bad_long_service_name(Config) -> bad_very_long_service_name(Config) -> bad_service_name(Config, - lists:duplicate(4*?SSH_MAX_PACKET_SIZE, $a)). + lists:duplicate(?SSH_MAX_PACKET_SIZE+5, $a)). empty_service_name(Config) -> bad_service_name(Config, ""). diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 2940ccb1e7..ca2dcbb761 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -189,6 +189,11 @@ <taglist> + <tag><c>{protocol, tls | dtls}</c></tag> + <item><p>Choose TLS or DTLS protocol for the transport layer security. + Defaults to <c>tls</c> Introduced in OTP 20, DTLS support is considered + experimental in this release. DTLS over other transports than UDP are not yet supported.</p></item> + <tag><c>{cert, public_key:der_encoded()}</c></tag> <item><p>The DER-encoded users certificate. If this option is supplied, it overrides option <c>certfile</c>.</p></item> diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl index 2a746d97f0..fbbd479428 100644 --- a/lib/ssl/src/dtls_socket.erl +++ b/lib/ssl/src/dtls_socket.erl @@ -79,30 +79,31 @@ socket(Pid, Transport, Socket, ConnectionCb) -> #sslsocket{pid = Pid, %% "The name "fd" is keept for backwards compatibility fd = {Transport, Socket, ConnectionCb}}. -%% Vad göra med emulerade -setopts(gen_udp, #sslsocket{pid = {Socket, _}}, Options) -> - {SockOpts, _} = tls_socket:split_options(Options), - inet:setopts(Socket, SockOpts); -setopts(_, #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}, Options) -> - {SockOpts, _} = tls_socket:split_options(Options), - Transport:setopts(ListenSocket, SockOpts); +setopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) -> + SplitOpts = tls_socket:split_options(Options), + dtls_udp_listener:set_sock_opts(ListenPid, SplitOpts); %%% Following clauses will not be called for emulated options, they are handled in the connection process setopts(gen_udp, Socket, Options) -> inet:setopts(Socket, Options); setopts(Transport, Socket, Options) -> Transport:setopts(Socket, Options). +getopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) -> + SplitOpts = tls_socket:split_options(Options), + dtls_udp_listener:get_sock_opts(ListenPid, SplitOpts); getopts(gen_udp, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) -> {SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options), EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames), SocketOpts = tls_socket:get_socket_opts(Socket, SockOptNames, inet), {ok, EmulatedOpts ++ SocketOpts}; -getopts(Transport, #sslsocket{pid = {ListenSocket, #config{emulated = EmOpts}}}, Options) -> +getopts(_Transport, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) -> {SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options), EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames), - SocketOpts = tls_socket:get_socket_opts(ListenSocket, SockOptNames, Transport), + SocketOpts = tls_socket:get_socket_opts(Socket, SockOptNames, inet), {ok, EmulatedOpts ++ SocketOpts}; %%% Following clauses will not be called for emulated options, they are handled in the connection process +getopts(gen_udp, {_,{{_, _},Socket}}, Options) -> + inet:getopts(Socket, Options); getopts(gen_udp, {_,Socket}, Options) -> inet:getopts(Socket, Options); getopts(Transport, Socket, Options) -> diff --git a/lib/ssl/src/dtls_udp_listener.erl b/lib/ssl/src/dtls_udp_listener.erl index 29380e3008..c789a32087 100644 --- a/lib/ssl/src/dtls_udp_listener.erl +++ b/lib/ssl/src/dtls_udp_listener.erl @@ -23,9 +23,11 @@ -behaviour(gen_server). +-include("ssl_internal.hrl"). + %% API -export([start_link/4, active_once/3, accept/2, sockname/1, close/1, - get_all_opts/1]). + get_all_opts/1, get_sock_opts/2, set_sock_opts/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -61,8 +63,12 @@ sockname(UDPConnection) -> call(UDPConnection, sockname). close(UDPConnection) -> call(UDPConnection, close). +get_sock_opts(UDPConnection, SplitSockOpts) -> + call(UDPConnection, {get_sock_opts, SplitSockOpts}). get_all_opts(UDPConnection) -> call(UDPConnection, get_all_opts). +set_sock_opts(UDPConnection, Opts) -> + call(UDPConnection, {set_sock_opts, Opts}). %%%=================================================================== %%% gen_server callbacks @@ -108,9 +114,21 @@ handle_call(close, _, #state{dtls_processes = Processes, end, queue:to_list(Accepters)), {reply, ok, State#state{close = true, accepters = queue:new()}} end; +handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listner = Socket, + emulated_options = EmOpts} = State) -> + case get_socket_opts(Socket, SocketOptNames) of + {ok, Opts} -> + {reply, {ok, emulated_opts_list(EmOpts, EmOptNames, []) ++ Opts}, State}; + {error, Reason} -> + {reply, {error, Reason}, State} + end; handle_call(get_all_opts, _, #state{dtls_options = DTLSOptions, emulated_options = EmOpts} = State) -> - {reply, {ok, EmOpts, DTLSOptions}, State}. + {reply, {ok, EmOpts, DTLSOptions}, State}; +handle_call({set_sock_opts, {SocketOpts, NewEmOpts}}, _, #state{listner = Socket, emulated_options = EmOpts0} = State) -> + set_socket_opts(Socket, SocketOpts), + EmOpts = do_set_emulated_opts(NewEmOpts, EmOpts0), + {reply, ok, State#state{emulated_options = EmOpts}}. handle_cast({active_once, Client, Pid}, State0) -> State = handle_active_once(Client, Pid, State0), @@ -259,3 +277,28 @@ call(Server, Msg) -> exit:{{shutdown, _},_} -> {error, closed} end. + +set_socket_opts(_, []) -> + ok; +set_socket_opts(Socket, SocketOpts) -> + inet:setopts(Socket, SocketOpts). + +get_socket_opts(_, []) -> + {ok, []}; +get_socket_opts(Socket, SocketOpts) -> + inet:getopts(Socket, SocketOpts). + +do_set_emulated_opts([], Opts) -> + Opts; +do_set_emulated_opts([{mode, Value} | Rest], Opts) -> + do_set_emulated_opts(Rest, Opts#socket_options{mode = Value}); +do_set_emulated_opts([{active, Value} | Rest], Opts) -> + do_set_emulated_opts(Rest, Opts#socket_options{active = Value}). + +emulated_opts_list(_,[], Acc) -> + Acc; +emulated_opts_list( Opts, [mode | Rest], Acc) -> + emulated_opts_list(Opts, Rest, [{mode, Opts#socket_options.mode} | Acc]); +emulated_opts_list(Opts, [active | Rest], Acc) -> + emulated_opts_list(Opts, Rest, [{active, Opts#socket_options.active} | Acc]). + diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 5421bdef99..75eb308ba5 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -427,6 +427,16 @@ eccs_filter_supported(Curves) -> %%-------------------------------------------------------------------- getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) -> ssl_connection:get_opts(Pid, OptionTags); +getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) -> + try dtls_socket:getopts(Transport, ListenSocket, OptionTags) of + {ok, _} = Result -> + Result; + {error, InetError} -> + {error, {options, {socket_options, OptionTags, InetError}}} + catch + _:Error -> + {error, {options, {socket_options, OptionTags, Error}}} + end; getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) -> try tls_socket:getopts(Transport, ListenSocket, OptionTags) of @@ -455,7 +465,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) -> _:_ -> {error, {options, {not_a_proplist, Options0}}} end; -setopts(#sslsocket{pid = {{udp, _}, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) -> +setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) -> try dtls_socket:setopts(Transport, ListenSocket, Options) of ok -> ok; diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index d13b1b3f2a..407152aa75 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -119,7 +119,6 @@ options_tests() -> [der_input, ssl_options_not_proplist, raw_ssl_option, - socket_options, invalid_inet_get_option, invalid_inet_get_option_not_list, invalid_inet_get_option_improper_list, @@ -163,7 +162,8 @@ api_tests() -> ssl_recv_timeout, server_name_indication_option, accept_pool, - prf + prf, + socket_options ]. api_tests_tls() -> @@ -178,6 +178,7 @@ api_tests_tls() -> tls_shutdown_error, peername, sockname, + tls_socket_options, new_options_in_accept ]. @@ -1286,10 +1287,10 @@ cipher_suites_mix(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -socket_options() -> +tls_socket_options() -> [{doc,"Test API function getopts/2 and setopts/2"}]. -socket_options(Config) when is_list(Config) -> +tls_socket_options(Config) when is_list(Config) -> ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -1304,14 +1305,14 @@ socket_options(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, socket_options_result, + {mfa, {?MODULE, tls_socket_options_result, [Options, Values, NewOptions, NewValues]}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, - {mfa, {?MODULE, socket_options_result, + {mfa, {?MODULE, tls_socket_options_result, [Options, Values, NewOptions, NewValues]}}, {options, ClientOpts}]), @@ -1326,7 +1327,7 @@ socket_options(Config) when is_list(Config) -> {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]), ssl:close(Listen). -socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> +tls_socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> %% Test get/set emulated opts {ok, DefaultValues} = ssl:getopts(Socket, Options), ssl:setopts(Socket, NewValues), @@ -1341,6 +1342,59 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> %%-------------------------------------------------------------------- +socket_options() -> + [{doc,"Test API function getopts/2 and setopts/2"}]. + +socket_options(Config) when is_list(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_opts, Config), + ServerOpts = ssl_test_lib:ssl_options(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Values = [{mode, list}, {active, true}], + %% Shall be the reverse order of Values! + Options = [active, mode], + + NewValues = [{mode, binary}, {active, once}], + %% Shall be the reverse order of NewValues! + NewOptions = [active, mode], + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, socket_options_result, + [Options, Values, NewOptions, NewValues]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, socket_options_result, + [Options, Values, NewOptions, NewValues]}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + + {ok, Listen} = ssl:listen(0, ServerOpts), + {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]), + ok = ssl:setopts(Listen, [{mode, binary}]), + {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]), + {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]), + ssl:close(Listen). + + +socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> + %% Test get/set emulated opts + {ok, DefaultValues} = ssl:getopts(Socket, Options), + ssl:setopts(Socket, NewValues), + {ok, NewValues} = ssl:getopts(Socket, NewOptions), + %% Test get/set inet opts + {ok,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]), + {ok, All} = ssl:getopts(Socket, []), + ct:log("All opts ~p~n", [All]), + ok. + + +%%-------------------------------------------------------------------- invalid_inet_get_option() -> [{doc,"Test handling of invalid inet options in getopts"}]. diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl index bb7b485490..4ab9234b81 100644 --- a/lib/stdlib/src/c.erl +++ b/lib/stdlib/src/c.erl @@ -144,7 +144,7 @@ c(SrcFile, NewOpts, Filter, BeamFile, Info) -> F = fun (Opt) -> not is_outdir_opt(Opt) andalso Filter(Opt) end, Options = (NewOpts ++ [{outdir,filename:dirname(BeamFile)}] ++ lists:filter(F, old_options(Info))), - format("Recompiling ~s\n", [SrcFile]), + format("Recompiling ~ts\n", [SrcFile]), safe_recompile(SrcFile, Options, BeamFile). old_options(Info) -> @@ -548,7 +548,7 @@ mfa_string(Fun) when is_function(Fun) -> {arity,A} = erlang:fun_info(Fun, arity), mfa_string({M,F,A}); mfa_string({M,F,A}) -> - io_lib:format("~w:~w/~w", [M,F,A]); + io_lib:format("~w:~tw/~w", [M,F,A]); mfa_string(X) -> w(X). @@ -572,7 +572,7 @@ display_info(Pid) -> w(Reds), w(LM)), iformat(case fetch(registered_name, Info) of 0 -> ""; - X -> w(X) + X -> io_lib:format("~tw", [X]) end, mfa_string(Curr), w(SS), @@ -594,7 +594,7 @@ initial_call(Info) -> end. iformat(A1, A2, A3, A4, A5) -> - format("~-21s ~-33s ~8s ~8s ~4s~n", [A1,A2,A3,A4,A5]). + format("~-21ts ~-33ts ~8s ~8s ~4s~n", [A1,A2,A3,A4,A5]). all_procs() -> case is_alive() of @@ -767,7 +767,7 @@ print_exports(X) when length(X) > 16 -> split_print_exports(X); print_exports([]) -> ok; print_exports([{F, A} |Tail]) -> - format(" ~w/~w~n",[F, A]), + format(" ~tw/~w~n",[F, A]), print_exports(Tail). split_print_exports(L) -> @@ -779,11 +779,11 @@ split_print_exports(L) -> split_print_exports([], [{F, A}|T]) -> Str = " ", - format("~-30s~w/~w~n", [Str, F, A]), + format("~-30ts~tw/~w~n", [Str, F, A]), split_print_exports([], T); split_print_exports([{F1, A1}|T1], [{F2, A2} | T2]) -> - Str = flatten(io_lib:format("~w/~w", [F1, A1])), - format("~-30s~w/~w~n", [Str, F2, A2]), + Str = flatten(io_lib:format("~tw/~w", [F1, A1])), + format("~-30ts~tw/~w~n", [Str, F2, A2]), split_print_exports(T1, T2); split_print_exports([], []) -> ok. @@ -883,22 +883,22 @@ procline(Name, Info, Pid) -> Call = initial_call(Info), Reds = fetch(reductions, Info), LM = length(fetch(messages, Info)), - procformat(io_lib:format("~w",[Name]), + procformat(io_lib:format("~tw",[Name]), io_lib:format("~w",[Pid]), - io_lib:format("~s",[mfa_string(Call)]), + io_lib:format("~ts",[mfa_string(Call)]), integer_to_list(Reds), integer_to_list(LM)). procformat(Name, Pid, Call, Reds, LM) -> - format("~-21s ~-12s ~-25s ~12s ~4s~n", [Name,Pid,Call,Reds,LM]). + format("~-21ts ~-12s ~-25ts ~12s ~4s~n", [Name,Pid,Call,Reds,LM]). portline(Name, Info, Id) -> Cmd = fetch(name, Info), - portformat(io_lib:format("~w",[Name]), + portformat(io_lib:format("~tw",[Name]), erlang:port_to_list(Id), Cmd). portformat(Name, Id, Cmd) -> - format("~-21s ~-15s ~-40s~n", [Name,Id,Cmd]). + format("~-21ts ~-15s ~-40ts~n", [Name,Id,Cmd]). %% pwd() %% cd(Directory) diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index b35e9575a4..31d0d499e3 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -194,27 +194,27 @@ format_error(missing_parenthesis) -> format_error(premature_end) -> "premature end"; format_error({call,What}) -> - io_lib:format("illegal macro call '~s'",[What]); + io_lib:format("illegal macro call '~ts'",[What]); format_error({undefined,M,none}) -> - io_lib:format("undefined macro '~s'", [M]); + io_lib:format("undefined macro '~ts'", [M]); format_error({undefined,M,A}) -> - io_lib:format("undefined macro '~s/~p'", [M,A]); + io_lib:format("undefined macro '~ts/~p'", [M,A]); format_error({depth,What}) -> io_lib:format("~s too deep",[What]); format_error({mismatch,M}) -> - io_lib:format("argument mismatch for macro '~s'", [M]); + io_lib:format("argument mismatch for macro '~ts'", [M]); format_error({arg_error,M}) -> - io_lib:format("badly formed argument for macro '~s'", [M]); + io_lib:format("badly formed argument for macro '~ts'", [M]); format_error({redefine,M}) -> - io_lib:format("redefining macro '~s'", [M]); + io_lib:format("redefining macro '~ts'", [M]); format_error({redefine_predef,M}) -> io_lib:format("redefining predefined macro '~s'", [M]); format_error({circular,M,none}) -> - io_lib:format("circular macro '~s'", [M]); + io_lib:format("circular macro '~ts'", [M]); format_error({circular,M,A}) -> - io_lib:format("circular macro '~s/~p'", [M,A]); + io_lib:format("circular macro '~ts/~p'", [M,A]); format_error({include,W,F}) -> - io_lib:format("can't find include ~s \"~s\"", [W,F]); + io_lib:format("can't find include ~s \"~ts\"", [W,F]); format_error({illegal,How,What}) -> io_lib:format("~s '-~s'", [How,What]); format_error({illegal_function,Macro}) -> @@ -224,9 +224,9 @@ format_error({illegal_function_usage,Macro}) -> format_error({'NYI',What}) -> io_lib:format("not yet implemented '~s'", [What]); format_error({error,Term}) -> - io_lib:format("-error(~p).", [Term]); + io_lib:format("-error(~tp).", [Term]); format_error({warning,Term}) -> - io_lib:format("-warning(~p).", [Term]); + io_lib:format("-warning(~tp).", [Term]); format_error(E) -> file:format_error(E). -spec parse_file(FileName, IncludePath, PredefMacros) -> @@ -1307,7 +1307,7 @@ expand_macros([{'?',_Lq},Token|_Toks], _St) -> Text; undefined -> Symbol = erl_scan:symbol(Token), - io_lib:write(Symbol) + io_lib:fwrite(<<"~tp">>, [Symbol]) end, throw({error,loc(Token),{call,[$?|T]}}); expand_macros([T|Ts], St) -> diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl index 76db2eeacd..18d7548fdc 100644 --- a/lib/stdlib/src/erl_compile.erl +++ b/lib/stdlib/src/erl_compile.erl @@ -181,7 +181,7 @@ parse_generic_option("P", T, #options{specific=Spec}=Opts) -> parse_generic_option("S", T, #options{specific=Spec}=Opts) -> compile1(T, Opts#options{specific=['S'|Spec]}); parse_generic_option(Option, _T, _Opts) -> - io:format(?STDERR, "Unknown option: -~s\n", [Option]), + io:format(?STDERR, "Unknown option: -~ts\n", [Option]), usage(). parse_dep_option("", T) -> @@ -202,7 +202,7 @@ parse_dep_option("T"++Opt, T0) -> {Target,T} = get_option("MT", Opt, T0), {[{makedep_target,Target}],T}; parse_dep_option(Opt, _T) -> - io:format(?STDERR, "Unknown option: -M~s\n", [Opt]), + io:format(?STDERR, "Unknown option: -M~ts\n", [Opt]), usage(). usage() -> diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index d53a31db0d..fcfd0d8493 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -175,49 +175,50 @@ format_error(invalid_record) -> "invalid record expression"; format_error({attribute,A}) -> - io_lib:format("attribute '~w' after function definitions", [A]); + io_lib:format("attribute ~tw after function definitions", [A]); format_error({missing_qlc_hrl,A}) -> io_lib:format("qlc:q/~w called, but \"qlc.hrl\" not included", [A]); format_error({redefine_import,{{F,A},M}}) -> - io_lib:format("function ~w/~w already imported from ~w", [F,A,M]); + io_lib:format("function ~tw/~w already imported from ~w", [F,A,M]); format_error({bad_inline,{F,A}}) -> - io_lib:format("inlined function ~w/~w undefined", [F,A]); + io_lib:format("inlined function ~tw/~w undefined", [F,A]); format_error({invalid_deprecated,D}) -> - io_lib:format("badly formed deprecated attribute ~w", [D]); + io_lib:format("badly formed deprecated attribute ~tw", [D]); format_error({bad_deprecated,{F,A}}) -> - io_lib:format("deprecated function ~w/~w undefined or not exported", [F,A]); + io_lib:format("deprecated function ~tw/~w undefined or not exported", + [F,A]); format_error({bad_nowarn_unused_function,{F,A}}) -> - io_lib:format("function ~w/~w undefined", [F,A]); + io_lib:format("function ~tw/~w undefined", [F,A]); format_error({bad_nowarn_bif_clash,{F,A}}) -> - io_lib:format("function ~w/~w undefined", [F,A]); + io_lib:format("function ~tw/~w undefined", [F,A]); format_error(disallowed_nowarn_bif_clash) -> io_lib:format("compile directive nowarn_bif_clash is no longer allowed,~n" " - use explicit module names or -compile({no_auto_import, [F/A]})", []); format_error({bad_nowarn_deprecated_function,{M,F,A}}) -> - io_lib:format("~w:~w/~w is not a deprecated function", [M,F,A]); + io_lib:format("~tw:~tw/~w is not a deprecated function", [M,F,A]); format_error({bad_on_load,Term}) -> - io_lib:format("badly formed on_load attribute: ~w", [Term]); + io_lib:format("badly formed on_load attribute: ~tw", [Term]); format_error(multiple_on_loads) -> "more than one on_load attribute"; format_error({bad_on_load_arity,{F,A}}) -> - io_lib:format("function ~w/~w has wrong arity (must be 0)", [F,A]); + io_lib:format("function ~tw/~w has wrong arity (must be 0)", [F,A]); format_error({undefined_on_load,{F,A}}) -> - io_lib:format("function ~w/~w undefined", [F,A]); + io_lib:format("function ~tw/~w undefined", [F,A]); format_error(export_all) -> "export_all flag enabled - all functions will be exported"; format_error({duplicated_export, {F,A}}) -> - io_lib:format("function ~w/~w already exported", [F,A]); + io_lib:format("function ~tw/~w already exported", [F,A]); format_error({unused_import,{{F,A},M}}) -> - io_lib:format("import ~w:~w/~w is unused", [M,F,A]); + io_lib:format("import ~w:~tw/~w is unused", [M,F,A]); format_error({undefined_function,{F,A}}) -> - io_lib:format("function ~w/~w undefined", [F,A]); + io_lib:format("function ~tw/~w undefined", [F,A]); format_error({redefine_function,{F,A}}) -> - io_lib:format("function ~w/~w already defined", [F,A]); + io_lib:format("function ~tw/~w already defined", [F,A]); format_error({define_import,{F,A}}) -> - io_lib:format("defining imported function ~w/~w", [F,A]); + io_lib:format("defining imported function ~tw/~w", [F,A]); format_error({unused_function,{F,A}}) -> - io_lib:format("function ~w/~w is unused", [F,A]); + io_lib:format("function ~tw/~w is unused", [F,A]); format_error({call_to_redefined_bif,{F,A}}) -> io_lib:format("ambiguous call of overridden auto-imported BIF ~w/~w~n" " - use erlang:~w/~w or \"-compile({no_auto_import,[~w/~w]}).\" " @@ -273,7 +274,7 @@ format_error(illegal_bin_pattern) -> "binary patterns cannot be matched in parallel using '='"; format_error(illegal_expr) -> "illegal expression"; format_error({illegal_guard_local_call, {F,A}}) -> - io_lib:format("call to local/imported function ~w/~w is illegal in guard", + io_lib:format("call to local/imported function ~tw/~w is illegal in guard", [F,A]); format_error(illegal_guard_expr) -> "illegal guard expression"; %% --- maps --- @@ -281,23 +282,23 @@ format_error(illegal_map_construction) -> "only association operators '=>' are allowed in map construction"; %% --- records --- format_error({undefined_record,T}) -> - io_lib:format("record ~w undefined", [T]); + io_lib:format("record ~tw undefined", [T]); format_error({redefine_record,T}) -> - io_lib:format("record ~w already defined", [T]); + io_lib:format("record ~tw already defined", [T]); format_error({redefine_field,T,F}) -> - io_lib:format("field ~w already defined in record ~w", [F,T]); + io_lib:format("field ~tw already defined in record ~tw", [F,T]); format_error({undefined_field,T,F}) -> - io_lib:format("field ~w undefined in record ~w", [F,T]); + io_lib:format("field ~tw undefined in record ~tw", [F,T]); format_error(illegal_record_info) -> "illegal record info"; format_error({field_name_is_variable,T,F}) -> - io_lib:format("field ~w is not an atom or _ in record ~w", [F,T]); + io_lib:format("field ~tw is not an atom or _ in record ~tw", [F,T]); format_error({wildcard_in_update,T}) -> - io_lib:format("meaningless use of _ in update of record ~w", [T]); + io_lib:format("meaningless use of _ in update of record ~tw", [T]); format_error({unused_record,T}) -> - io_lib:format("record ~w is unused", [T]); + io_lib:format("record ~tw is unused", [T]); format_error({untyped_record,T}) -> - io_lib:format("record ~w has field(s) without type information", [T]); + io_lib:format("record ~tw has field(s) without type information", [T]); %% --- variables ---- format_error({unbound_var,V}) -> io_lib:format("variable ~w is unbound", [V]); @@ -315,7 +316,7 @@ format_error({variable_in_record_def,V}) -> io_lib:format("variable ~w in record definition", [V]); %% --- binaries --- format_error({undefined_bittype,Type}) -> - io_lib:format("bit type ~w undefined", [Type]); + io_lib:format("bit type ~tw undefined", [Type]); format_error({bittype_mismatch,Val1,Val2,What}) -> io_lib:format("conflict in ~s specification for bit field: '~p' and '~p'", [What,Val1,Val2]); @@ -335,13 +336,13 @@ format_error(unsized_binary_in_bin_gen_pattern) -> "binary fields without size are not allowed in patterns of bit string generators"; %% --- behaviours --- format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) -> - io_lib:format("conflicting behaviours - callback ~w/~w required by both '~p' " + io_lib:format("conflicting behaviours - callback ~tw/~w required by both '~p' " "and '~p' ~s", [Name,Arity,B,FirstB,format_where(FirstL)]); format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}) -> - io_lib:format("undefined callback function ~w/~w (behaviour '~w')", + io_lib:format("undefined callback function ~tw/~w (behaviour '~w')", [Func,Arity,Behaviour]); format_error({undefined_behaviour,Behaviour}) -> - io_lib:format("behaviour ~w undefined", [Behaviour]); + io_lib:format("behaviour ~tw undefined", [Behaviour]); format_error({undefined_behaviour_callbacks,Behaviour}) -> io_lib:format("behaviour ~w callback functions are undefined", [Behaviour]); @@ -352,23 +353,23 @@ format_error({ill_defined_optional_callbacks,Behaviour}) -> io_lib:format("behaviour ~w optional callback functions erroneously defined", [Behaviour]); format_error({behaviour_info, {_M,F,A}}) -> - io_lib:format("cannot define callback attibute for ~w/~w when " + io_lib:format("cannot define callback attibute for ~tw/~w when " "behaviour_info is defined",[F,A]); format_error({redefine_optional_callback, {F, A}}) -> - io_lib:format("optional callback ~w/~w duplicated", [F, A]); + io_lib:format("optional callback ~tw/~w duplicated", [F, A]); format_error({undefined_callback, {_M, F, A}}) -> - io_lib:format("callback ~w/~w is undefined", [F, A]); + io_lib:format("callback ~tw/~w is undefined", [F, A]); %% --- types and specs --- format_error({singleton_typevar, Name}) -> io_lib:format("type variable ~w is only used once (is unbound)", [Name]); format_error({bad_export_type, _ETs}) -> io_lib:format("bad export_type declaration", []); format_error({duplicated_export_type, {T, A}}) -> - io_lib:format("type ~w/~w already exported", [T, A]); + io_lib:format("type ~tw/~w already exported", [T, A]); format_error({undefined_type, {TypeName, Arity}}) -> - io_lib:format("type ~w~s undefined", [TypeName, gen_type_paren(Arity)]); + io_lib:format("type ~tw~s undefined", [TypeName, gen_type_paren(Arity)]); format_error({unused_type, {TypeName, Arity}}) -> - io_lib:format("type ~w~s is unused", [TypeName, gen_type_paren(Arity)]); + io_lib:format("type ~tw~s is unused", [TypeName, gen_type_paren(Arity)]); format_error({new_builtin_type, {TypeName, Arity}}) -> io_lib:format("type ~w~s is a new builtin type; " "its (re)definition is allowed only until the next release", @@ -380,25 +381,26 @@ format_error({renamed_type, OldName, NewName}) -> io_lib:format("type ~w() is now called ~w(); " "please use the new name instead", [OldName, NewName]); format_error({redefine_type, {TypeName, Arity}}) -> - io_lib:format("type ~w~s already defined", + io_lib:format("type ~tw~s already defined", [TypeName, gen_type_paren(Arity)]); format_error({type_syntax, Constr}) -> - io_lib:format("bad ~w type", [Constr]); + io_lib:format("bad ~tw type", [Constr]); format_error(old_abstract_code) -> io_lib:format("abstract code generated before Erlang/OTP 19.0 and " "having typed record fields cannot be compiled", []); format_error({redefine_spec, {M, F, A}}) -> - io_lib:format("spec for ~w:~w/~w already defined", [M, F, A]); + io_lib:format("spec for ~tw:~tw/~w already defined", [M, F, A]); format_error({redefine_spec, {F, A}}) -> - io_lib:format("spec for ~w/~w already defined", [F, A]); + io_lib:format("spec for ~tw/~w already defined", [F, A]); format_error({redefine_callback, {F, A}}) -> - io_lib:format("callback ~w/~w already defined", [F, A]); + io_lib:format("callback ~tw/~w already defined", [F, A]); format_error({bad_callback, {M, F, A}}) -> - io_lib:format("explicit module not allowed for callback ~w:~w/~w ", [M, F, A]); + io_lib:format("explicit module not allowed for callback ~tw:~tw/~w", + [M, F, A]); format_error({spec_fun_undefined, {F, A}}) -> - io_lib:format("spec for undefined function ~w/~w", [F, A]); + io_lib:format("spec for undefined function ~tw/~w", [F, A]); format_error({missing_spec, {F,A}}) -> - io_lib:format("missing specification for function ~w/~w", [F, A]); + io_lib:format("missing specification for function ~tw/~w", [F, A]); format_error(spec_wrong_arity) -> "spec has wrong arity"; format_error(callback_wrong_arity) -> @@ -417,15 +419,15 @@ format_error({deprecated_builtin_type, {Name, Arity}, "removed in ~s; use ~s", [Name, Arity, Rel, UseS]); format_error({not_exported_opaque, {TypeName, Arity}}) -> - io_lib:format("opaque type ~w~s is not exported", + io_lib:format("opaque type ~tw~s is not exported", [TypeName, gen_type_paren(Arity)]); format_error({underspecified_opaque, {TypeName, Arity}}) -> - io_lib:format("opaque type ~w~s is underspecified and therefore meaningless", + io_lib:format("opaque type ~tw~s is underspecified and therefore meaningless", [TypeName, gen_type_paren(Arity)]); format_error({bad_dialyzer_attribute,Term}) -> - io_lib:format("badly formed dialyzer attribute: ~w", [Term]); + io_lib:format("badly formed dialyzer attribute: ~tw", [Term]); format_error({bad_dialyzer_option,Term}) -> - io_lib:format("unknown dialyzer warning option: ~w", [Term]); + io_lib:format("unknown dialyzer warning option: ~tw", [Term]); %% --- obsolete? unused? --- format_error({format_error, {Fmt, Args}}) -> io_lib:format(Fmt, Args). @@ -763,12 +765,7 @@ start_state({attribute,Line,module,{_,_}}=Form, St0) -> start_state({attribute,Line,module,M}, St0) -> St1 = St0#lint{module=M}, St2 = St1#lint{state=attribute}, - case is_non_latin1_name(M) of - true -> - add_error(Line, non_latin1_module_unsupported, St2); - false -> - St2 - end; + check_module_name(M, Line, St2); start_state(Form, St) -> Anno = case Form of {eof, L} -> erl_anno:new(L); @@ -778,9 +775,6 @@ start_state(Form, St) -> St1 = add_error(Anno, undefined_module, St), attribute_state(Form, St1#lint{state=attribute}). -is_non_latin1_name(Name) -> - lists:any(fun(C) -> C > 255 end, atom_to_list(Name)). - %% attribute_state(Form, State) -> %% State' @@ -865,7 +859,11 @@ not_deprecated(Forms, St0) -> Bad = [MFAL || {{M,F,A},_L}=MFAL <- MFAsL, otp_internal:obsolete(M, F, A) =:= no], St1 = func_line_warning(bad_nowarn_deprecated_function, Bad, St0), - St1#lint{not_deprecated = ordsets:from_list(Nowarn)}. + ML = [{M,L} || {{M,_F,_A},L} <- MFAsL, is_atom(M)], + St3 = foldl(fun ({M,L}, St2) -> + check_module_name(M, L, St2) + end, St1, ML), + St3#lint{not_deprecated = ordsets:from_list(Nowarn)}. %% The nowarn_bif_clash directive is not only deprecated, it's actually an error from R14A disallowed_compile_flags(Forms, St0) -> @@ -972,7 +970,8 @@ behaviour_callbacks(Line, B, St0) -> catch _:_ -> St1 = add_warning(Line, {undefined_behaviour, B}, St0), - {[], [], St1} + St2 = check_module_name(B, Line, St1), + {[], [], St2} end. behaviour_missing_callbacks([{{Line,B},Bfs0,OBfs}|T], St0) -> @@ -1310,7 +1309,8 @@ exports(#lint{compile = Opts, defined = Defs, exports = Es}) -> -type import() :: {module(), [fa()]} | module(). -spec import(line(), import(), lint_state()) -> lint_state(). -import(Line, {Mod,Fs}, St) -> +import(Line, {Mod,Fs}, St00) -> + St = check_module_name(Mod, Line, St00), Mfs = ordsets:from_list(Fs), case check_imports(Line, Mfs, St#lint.imports) of [] -> @@ -2294,11 +2294,18 @@ expr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,is_record}]},As}, Vt, St) -> expr({call,Line,{remote,_Lr,{atom,_Lm,M},{atom,Lf,F}},As}, Vt, St0) -> St1 = keyword_warning(Lf, F, St0), St2 = check_remote_function(Line, M, F, As, St1), - expr_list(As, Vt, St2); + St3 = check_module_name(M, Line, St2), + expr_list(As, Vt, St3); expr({call,Line,{remote,_Lr,M,F},As}, Vt, St0) -> St1 = keyword_warning(Line, M, St0), St2 = keyword_warning(Line, F, St1), - expr_list([M,F|As], Vt, St2); + St3 = case M of + {atom,Lm,Mod} -> + check_module_name(Mod, Lm, St2); + _ -> + St2 + end, + expr_list([M,F|As], Vt, St3); expr({call,Line,{atom,La,F},As}, Vt, St0) -> St1 = keyword_warning(La, F, St0), {Asvt,St2} = expr_list(As, Vt, St1), @@ -2814,7 +2821,8 @@ check_type(Types, St) -> check_type({ann_type, _L, [_Var, Type]}, SeenVars, St) -> check_type(Type, SeenVars, St); check_type({remote_type, L, [{atom, _, Mod}, {atom, _, Name}, Args]}, - SeenVars, St0) -> + SeenVars, St00) -> + St0 = check_module_name(Mod, L, St00), St = deprecated_type(L, Mod, Name, Args, St0), CurrentMod = St#lint.module, case Mod =:= CurrentMod of @@ -2973,11 +2981,12 @@ obsolete_builtin_type({Name, A}) when is_atom(Name), is_integer(A) -> no. %% spec_decl(Line, Fun, Types, State) -> State. -spec_decl(Line, MFA0, TypeSpecs, St0 = #lint{specs = Specs, module = Mod}) -> +spec_decl(Line, MFA0, TypeSpecs, St00 = #lint{specs = Specs, module = Mod}) -> MFA = case MFA0 of {F, Arity} -> {Mod, F, Arity}; {_M, _F, Arity} -> MFA0 end, + St0 = check_module_name(element(1, MFA), Line, St00), St1 = St0#lint{specs = dict:store(MFA, Line, Specs)}, case dict:is_key(MFA, Specs) of true -> add_error(Line, {redefine_spec, MFA0}, St1); @@ -2989,7 +2998,9 @@ spec_decl(Line, MFA0, TypeSpecs, St0 = #lint{specs = Specs, module = Mod}) -> callback_decl(Line, MFA0, TypeSpecs, St0 = #lint{callbacks = Callbacks, module = Mod}) -> case MFA0 of - {_M, _F, _A} -> add_error(Line, {bad_callback, MFA0}, St0); + {M, _F, _A} -> + St1 = check_module_name(M, Line, St0), + add_error(Line, {bad_callback, MFA0}, St1); {F, Arity} -> MFA = {Mod, F, Arity}, St1 = St0#lint{callbacks = dict:store(MFA, Line, Callbacks)}, @@ -3033,6 +3044,16 @@ is_fa({FuncName, Arity}) when is_atom(FuncName), is_integer(Arity), Arity >= 0 -> true; is_fa(_) -> false. +check_module_name(M, Line, St) -> + case is_latin1_name(M) of + true -> St; + false -> + add_error(Line, non_latin1_module_unsupported, St) + end. + +is_latin1_name(Name) -> + io_lib:latin1_char_list(atom_to_list(Name)). + check_specs([FunType|Left], ETag, Arity, St0) -> {FunType1, CTypes} = case FunType of diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 733932e711..6e72d64acc 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -1097,12 +1097,12 @@ build_compat_constraint({atom, _, is_subtype}, [{var, _, _}=LHS, Type]) -> build_compat_constraint({atom, _, is_subtype}, [LHS, _Type]) -> ret_err(?anno(LHS), "bad type variable"); build_compat_constraint({atom, A, Atom}, _Types) -> - ret_err(A, io_lib:format("unsupported constraint ~w", [Atom])). + ret_err(A, io_lib:format("unsupported constraint ~tw", [Atom])). build_constraint({atom, _, is_subtype}, [{var, _, _}=LHS, Type]) -> build_constraint(LHS, Type); build_constraint({atom, A, Atom}, _Foo) -> - ret_err(A, io_lib:format("unsupported constraint ~w", [Atom])); + ret_err(A, io_lib:format("unsupported constraint ~tw", [Atom])); build_constraint({var, A, '_'}, _Types) -> ret_err(A, "bad type variable"); build_constraint(LHS, Type) -> @@ -1220,7 +1220,7 @@ attribute_farity_map(Args) -> -spec error_bad_decl(erl_anno:anno(), attributes()) -> no_return(). error_bad_decl(Anno, S) -> - ret_err(Anno, io_lib:format("bad ~w declaration", [S])). + ret_err(Anno, io_lib:format("bad ~tw declaration", [S])). farity_list({cons,_Ac,{op,_Ao,'/',{atom,_Aa,A},{integer,_Ai,I}},Tail}) -> [{A,I}|farity_list(Tail)]; diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index f2629a47c2..2093916a7c 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -281,12 +281,12 @@ start(EscriptOptions) -> end catch throw:Str -> - io:format("escript: ~s\n", [Str]), + io:format("escript: ~ts\n", [Str]), my_halt(127); _:Reason -> Stk = erlang:get_stacktrace(), - io:format("escript: Internal error: ~p\n", [Reason]), - io:format("~p\n", [Stk]), + io:format("escript: Internal error: ~tp\n", [Reason]), + io:format("~tp\n", [Stk]), my_halt(127) end. diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl index 14d925bacf..4b2d15c8b3 100644 --- a/lib/stdlib/src/io_lib_format.erl +++ b/lib/stdlib/src/io_lib_format.erl @@ -335,7 +335,7 @@ base(B) when is_integer(B) -> term(T, none, _Adj, none, _Pad) -> T; term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad); term(T, F, Adj, P0, Pad) -> - L = lists:flatlength(T), + L = string:length(T), P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end), if L > P -> @@ -675,11 +675,11 @@ cdata_to_chars(B) when is_binary(B) -> string(S, none, _Adj, none, _Pad) -> S; string(S, F, Adj, none, Pad) -> - string_field(S, F, Adj, lists:flatlength(S), Pad); + string_field(S, F, Adj, string:length(S), Pad); string(S, none, _Adj, P, Pad) -> - string_field(S, P, left, lists:flatlength(S), Pad); + string_field(S, P, left, string:length(S), Pad); string(S, F, Adj, P, Pad) when F >= P -> - N = lists:flatlength(S), + N = string:length(S), if F > P -> if N > P -> adjust(flat_trunc(S, P), chars(Pad, F-P), Adj); @@ -749,18 +749,7 @@ adjust(Data, Pad, right) -> [Pad|Data]. %% Flatten and truncate a deep list to at most N elements. flat_trunc(List, N) when is_integer(N), N >= 0 -> - flat_trunc(List, N, [], []). - -flat_trunc(L, 0, _, R) when is_list(L) -> - lists:reverse(R); -flat_trunc([H|T], N, S, R) when is_list(H) -> - flat_trunc(H, N, [T|S], R); -flat_trunc([H|T], N, S, R) -> - flat_trunc(T, N-1, S, [H|R]); -flat_trunc([], N, [H|S], R) -> - flat_trunc(H, N, S, R); -flat_trunc([], _, [], R) -> - lists:reverse(R). + string:slice(List, 0, N). %% A deep version of string:chars/2,3 diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl index ff368d02da..505613b80e 100644 --- a/lib/stdlib/src/io_lib_pretty.erl +++ b/lib/stdlib/src/io_lib_pretty.erl @@ -473,7 +473,7 @@ print_length(<<_/bitstring>>=Bin, D, _RF, Enc, Str) -> print_length(Term, _D, _RF, _Enc, _Str) -> S = io_lib:write(Term), %% S can contain unicode, so iolist_size(S) cannot be used here - {S, lists:flatlength(S)}. + {S, string:length(S)}. print_length_map(_Map, 1, _RF, _Enc, _Str) -> {"#{...}", 6}; diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl index aa6797bce6..c6eb0d7915 100644 --- a/lib/stdlib/src/lib.erl +++ b/lib/stdlib/src/lib.erl @@ -27,7 +27,7 @@ -export([format_exception/6, format_exception/7, format_stacktrace/4, format_stacktrace/5, - format_call/4, format_call/5, format_fun/1]). + format_call/4, format_call/5, format_fun/1, format_fun/2]). -spec flush_receive() -> 'ok'. @@ -400,7 +400,11 @@ format_call(I, ForMForFun, As, FormatFun, Enc) format_call("", n_spaces(I-1), ForMForFun, As, FormatFun, Enc). %% -> iolist() (no \n at end) -format_fun(Fun) when is_function(Fun) -> +format_fun(Fun) -> + format_fun(Fun, latin1). + +%% -> iolist() (no \n at end) +format_fun(Fun, Enc) when is_function(Fun) -> {module, M} = erlang:fun_info(Fun, module), {name, F} = erlang:fun_info(Fun, name), {arity, A} = erlang:fun_info(Fun, arity), @@ -410,9 +414,9 @@ format_fun(Fun) when is_function(Fun) -> {type, local} when M =:= erl_eval -> io_lib:fwrite(<<"interpreted function with arity ~w">>, [A]); {type, local} -> - mfa_to_string(M, F, A); + mfa_to_string(M, F, A, Enc); {type, external} -> - mfa_to_string(M, F, A) + mfa_to_string(M, F, A, Enc) end. analyze_exception(error, Term, Stack) -> @@ -454,11 +458,11 @@ explain_reason({badarg,V}, error=Cl, [], PF, S, _Enc) -> % orelse, andalso format_value(V, <<"bad argument: ">>, Cl, PF, S); explain_reason(badarith, error, [], _PF, _S, _Enc) -> <<"an error occurred when evaluating an arithmetic expression">>; -explain_reason({badarity,{Fun,As}}, error, [], _PF, _S, _Enc) +explain_reason({badarity,{Fun,As}}, error, [], _PF, _S, Enc) when is_function(Fun) -> %% Only the arity is displayed, not the arguments As. - io_lib:fwrite(<<"~s called with ~s">>, - [format_fun(Fun), argss(length(As))]); + io_lib:fwrite(<<"~ts called with ~s">>, + [format_fun(Fun, Enc), argss(length(As))]); explain_reason({badfun,Term}, error=Cl, [], PF, S, _Enc) -> format_value(Term, <<"bad function ">>, Cl, PF, S); explain_reason({badmatch,Term}, error=Cl, [], PF, S, _Enc) -> @@ -489,14 +493,15 @@ explain_reason({try_clause,V}, error=Cl, [], PF, S, _Enc) -> %% "there is no try clause with a true guard sequence and a %% pattern matching..." format_value(V, <<"no try clause matching ">>, Cl, PF, S); -explain_reason(undef, error, [{M,F,A,_}], _PF, _S, _Enc) -> +explain_reason(undef, error, [{M,F,A,_}], _PF, _S, Enc) -> %% Only the arity is displayed, not the arguments, if there are any. - io_lib:fwrite(<<"undefined function ~s">>, - [mfa_to_string(M, F, n_args(A))]); -explain_reason({shell_undef,F,A,_}, error, [], _PF, _S, _Enc) -> + io_lib:fwrite(<<"undefined function ~ts">>, + [mfa_to_string(M, F, n_args(A), Enc)]); +explain_reason({shell_undef,F,A,_}, error, [], _PF, _S, Enc) -> %% Give nicer reports for undefined shell functions %% (but not when the user actively calls shell_default:F(...)). - io_lib:fwrite(<<"undefined shell command ~s/~w">>, [F, n_args(A)]); + FS = to_string(F, Enc), + io_lib:fwrite(<<"undefined shell command ~ts/~w">>, [FS, n_args(A)]); %% Exit codes returned by erl_eval only: explain_reason({argument_limit,_Fun}, error, [], _PF, _S, _Enc) -> io_lib:fwrite(<<"limit of number of arguments to interpreted function" @@ -546,17 +551,18 @@ format_stacktrace1(S0, Stack0, PF, SF, Enc) -> format_stacktrace2(S, Stack, 1, PF, Enc). format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF, Enc) when is_integer(A) -> - [io_lib:fwrite(<<"~s~s ~s ~s">>, + [io_lib:fwrite(<<"~s~s ~ts ~s">>, [sep(N, S), origin(N, M, F, A), - mfa_to_string(M, F, A), + mfa_to_string(M, F, A, Enc), location(L)]) | format_stacktrace2(S, Fs, N + 1, PF, Enc)]; format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF, Enc) when is_list(As) -> A = length(As), CalledAs = [S,<<" called as ">>], C = format_call("", CalledAs, {M,F}, As, PF, Enc), - [io_lib:fwrite(<<"~s~s ~s\n~s~ts">>, - [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A), + [io_lib:fwrite(<<"~s~s ~ts\n~s~ts">>, + [sep(N, S), origin(N, M, F, A), + mfa_to_string(M, F, A, Enc), CalledAs, C]) | format_stacktrace2(S, Fs, N + 1, PF, Enc)]; format_stacktrace2(_S, [], _N, _PF, _Enc) -> @@ -594,10 +600,10 @@ format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc) -> {yes,Op} -> format_op(ErrStr, Pre1, Op, As, PF, Enc); no -> - MFs = mf_to_string(ForMForFun, Arity), - I1 = iolist_size([Pre1,ErrStr|MFs]), + MFs = mf_to_string(ForMForFun, Arity, Enc), + I1 = string:length([Pre1,ErrStr|MFs]), S1 = pp_arguments(PF, As, I1, Enc), - S2 = pp_arguments(PF, As, iolist_size([Pre1|MFs]), Enc), + S2 = pp_arguments(PF, As, string:length([Pre1|MFs]), Enc), Long = count_nl(pp_arguments(PF, [a2345,b2345], I1, Enc)) > 0, case Long or (count_nl(S2) < count_nl(S1)) of true -> @@ -656,10 +662,10 @@ printable_list(latin1, As) -> printable_list(_, As) -> io_lib:printable_list(As). -mfa_to_string(M, F, A) -> - io_lib:fwrite(<<"~s/~w">>, [mf_to_string({M, F}, A), A]). +mfa_to_string(M, F, A, Enc) -> + io_lib:fwrite(<<"~ts/~w">>, [mf_to_string({M, F}, A, Enc), A]). -mf_to_string({M, F}, A) -> +mf_to_string({M, F}, A, Enc) -> case erl_internal:bif(M, F, A) of true -> io_lib:fwrite(<<"~w">>, [F]); @@ -670,13 +676,15 @@ mf_to_string({M, F}, A) -> {yes, F} -> atom_to_list(F); no -> - io_lib:fwrite(<<"~w:~w">>, [M, F]) + FS = to_string(F, Enc), + io_lib:fwrite(<<"~w:~ts">>, [M, FS]) end end; -mf_to_string(Fun, _A) when is_function(Fun) -> - format_fun(Fun); -mf_to_string(F, _A) -> - io_lib:fwrite(<<"~w">>, [F]). +mf_to_string(Fun, _A, Enc) when is_function(Fun) -> + format_fun(Fun, Enc); +mf_to_string(F, _A, Enc) -> + FS = to_string(F, Enc), + io_lib:fwrite(<<"~ts">>, [FS]). format_value(V, ErrStr, Class, PF, S) -> Pre1Sz = exited_size(Class), @@ -725,9 +733,14 @@ exited(exit) -> exited(throw) -> <<"exception throw: ">>. +to_string(A, latin1) -> + io_lib:write_atom_as_latin1(A); +to_string(A, _) -> + io_lib:write_atom(A). + size(latin1, S) -> {iolist_size(S),S}; size(_, S0) -> S = unicode:characters_to_list(S0, unicode), true = is_list(S), - {length(S),S}. + {string:length(S),S}. diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index 98745b13f3..6616e957c0 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2016. All Rights Reserved. +%% Copyright Ericsson AB 2002-2017. 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. @@ -91,12 +91,12 @@ format_error(?ERR_GUARDMATCH) -> "fun with guard matching ('=' in guard) is illegal as match_spec as well"; format_error({?ERR_GUARDLOCALCALL, Name, Arithy}) -> lists:flatten(io_lib:format("fun containing the local function call " - "'~w/~w' (called in guard) " + "'~tw/~w' (called in guard) " "cannot be translated into match_spec", [Name, Arithy])); format_error({?ERR_GUARDREMOTECALL, Module, Name, Arithy}) -> lists:flatten(io_lib:format("fun containing the remote function call " - "'~w:~w/~w' (called in guard) " + "'~w:~tw/~w' (called in guard) " "cannot be translated into match_spec", [Module,Name,Arithy])); format_error({?ERR_GUARDELEMENT, Str}) -> @@ -117,12 +117,12 @@ format_error(?ERR_BODYMATCH) -> "fun with body matching ('=' in body) is illegal as match_spec"; format_error({?ERR_BODYLOCALCALL, Name, Arithy}) -> lists:flatten(io_lib:format("fun containing the local function " - "call '~w/~w' (called in body) " + "call '~tw/~w' (called in body) " "cannot be translated into match_spec", [Name,Arithy])); format_error({?ERR_BODYREMOTECALL, Module, Name, Arithy}) -> lists:flatten(io_lib:format("fun containing the remote function call " - "'~w:~w/~w' (called in body) " + "'~w:~tw/~w' (called in body) " "cannot be translated into match_spec", [Module,Name,Arithy])); format_error({?ERR_BODYELEMENT, Str}) -> @@ -147,15 +147,15 @@ format_error({?ERR_UNBOUND_VARIABLE, Str}) -> "into match_spec", [Str])); format_error({?ERR_HEADBADREC,Name}) -> lists:flatten( - io_lib:format("fun head contains unknown record type ~w",[Name])); + io_lib:format("fun head contains unknown record type ~tw",[Name])); format_error({?ERR_HEADBADFIELD,RName,FName}) -> lists:flatten( - io_lib:format("fun head contains reference to unknown field ~w in " - "record type ~w",[FName, RName])); + io_lib:format("fun head contains reference to unknown field ~tw in " + "record type ~tw",[FName, RName])); format_error({?ERR_HEADMULTIFIELD,RName,FName}) -> lists:flatten( - io_lib:format("fun head contains already defined field ~w in " - "record type ~w",[FName, RName])); + io_lib:format("fun head contains already defined field ~tw in " + "record type ~tw",[FName, RName])); format_error({?ERR_HEADDOLLARATOM,Atom}) -> lists:flatten( io_lib:format("fun head contains atom ~w, which conflics with reserved " @@ -166,28 +166,28 @@ format_error({?ERR_HEADBINMATCH,Atom}) -> "which cannot be translated into match_spec", [Atom])); format_error({?ERR_GUARDBADREC,Name}) -> lists:flatten( - io_lib:format("fun guard contains unknown record type ~w",[Name])); + io_lib:format("fun guard contains unknown record type ~tw",[Name])); format_error({?ERR_GUARDBADFIELD,RName,FName}) -> lists:flatten( - io_lib:format("fun guard contains reference to unknown field ~w in " - "record type ~w",[FName, RName])); + io_lib:format("fun guard contains reference to unknown field ~tw in " + "record type ~tw",[FName, RName])); format_error({?ERR_GUARDMULTIFIELD,RName,FName}) -> lists:flatten( - io_lib:format("fun guard contains already defined field ~w in " - "record type ~w",[FName, RName])); + io_lib:format("fun guard contains already defined field ~tw in " + "record type ~tw",[FName, RName])); format_error({?ERR_BODYBADREC,Name}) -> lists:flatten( - io_lib:format("fun body contains unknown record type ~w",[Name])); + io_lib:format("fun body contains unknown record type ~tw",[Name])); format_error({?ERR_BODYBADFIELD,RName,FName}) -> lists:flatten( - io_lib:format("fun body contains reference to unknown field ~w in " - "record type ~w",[FName, RName])); + io_lib:format("fun body contains reference to unknown field ~tw in " + "record type ~tw",[FName, RName])); format_error({?ERR_BODYMULTIFIELD,RName,FName}) -> lists:flatten( - io_lib:format("fun body contains already defined field ~w in " - "record type ~w",[FName, RName])); + io_lib:format("fun body contains already defined field ~tw in " + "record type ~tw",[FName, RName])); format_error(Else) -> - lists:flatten(io_lib:format("Unknown error code ~w",[Else])). + lists:flatten(io_lib:format("Unknown error code ~tw",[Else])). %% %% Called when translating in shell @@ -501,10 +501,20 @@ tg0(Line,[H|T],B) -> tg({match,Line,_,_},B) -> throw({error,Line,?ERR_GENMATCH+B#tgd.eb}); -tg({op, Line, Operator, O1, O2}, B) -> - {tuple, Line, [{atom, Line, Operator}, tg(O1,B), tg(O2,B)]}; -tg({op, Line, Operator, O1}, B) -> - {tuple, Line, [{atom, Line, Operator}, tg(O1,B)]}; +tg({op, Line, Operator, O1, O2}=Expr, B) -> + case erl_eval:partial_eval(Expr) of + Expr -> + {tuple, Line, [{atom, Line, Operator}, tg(O1, B), tg(O2, B)]}; + Value -> + Value + end; +tg({op, Line, Operator, O1}=Expr, B) -> + case erl_eval:partial_eval(Expr) of + Expr -> + {tuple, Line, [{atom, Line, Operator}, tg(O1, B)]}; + Value -> + Value + end; tg({call, _Line, {atom, Line2, bindings},[]},_B) -> {atom, Line2, '$*'}; tg({call, _Line, {atom, Line2, object},[]},_B) -> @@ -723,7 +733,7 @@ tg(T,B) when is_tuple(T), tuple_size(T) >= 2 -> throw({error,Line,{?ERR_GENELEMENT+B#tgd.eb, translate_language_element(Element)}}); tg(Other,B) -> - Element = io_lib:format("unknown element ~w", [Other]), + Element = io_lib:format("unknown element ~tw", [Other]), throw({error,unknown,{?ERR_GENELEMENT+B#tgd.eb,Element}}). transform_head([V],OuterBound) -> diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl index 3fa54cd0d5..9ce8e7d60e 100644 --- a/lib/stdlib/src/proc_lib.erl +++ b/lib/stdlib/src/proc_lib.erl @@ -805,16 +805,21 @@ format_exception(Class, Reason, StackTrace, {Enc,_}=Extra) -> [EI, lib:format_exception(1+length(EI), Class, Reason, StackTrace, StackFun, PF, Enc), "\n"]. -format_mfa(Indent, {M,F,Args}=StartF, Extra) -> +format_mfa(Indent, {M,F,Args}=StartF, {Enc,_}=Extra) -> try A = length(Args), - [Indent,"initial call: ",atom_to_list(M),$:,atom_to_list(F),$/, + [Indent,"initial call: ",atom_to_list(M),$:,to_string(F, Enc),$/, integer_to_list(A),"\n"] catch error:_ -> format_tag(Indent, initial_call, StartF, Extra) end. +to_string(A, latin1) -> + io_lib:write_atom_as_latin1(A); +to_string(A, _) -> + io_lib:write_atom(A). + pp_fun({Enc,Depth}) -> {Letter,Tl} = case Depth of unlimited -> {"p",[]}; diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index 76a2789406..6eafc7b209 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -1238,22 +1238,22 @@ read_file_records(File, Opts) -> end. %% This is how the debugger searches for source files. See int.erl. -try_source(Beam, CB) -> - Os = case lists:keyfind(options, 1, binary_to_term(CB)) of - false -> []; - {_, Os0} -> Os0 - end, +try_source(Beam, RawCB) -> + EbinDir = filename:dirname(Beam), + CB = binary_to_term(RawCB), + Os = proplists:get_value(options,CB, []), Src0 = filename:rootname(Beam) ++ ".erl", - case is_file(Src0) of - true -> parse_file(Src0, Os); - false -> - EbinDir = filename:dirname(Beam), - Src = filename:join([filename:dirname(EbinDir), "src", - filename:basename(Src0)]), - case is_file(Src) of - true -> parse_file(Src, Os); - false -> {error, nofile} - end + Src1 = filename:join([filename:dirname(EbinDir), "src", + filename:basename(Src0)]), + Src2 = proplists:get_value(source, CB, []), + try_sources([Src0,Src1,Src2], Os). + +try_sources([], _) -> + {error, nofile}; +try_sources([Src|Rest], Os) -> + case is_file(Src) of + true -> parse_file(Src, Os); + false -> try_sources(Rest, Os) end. is_file(Name) -> diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 71d6820c47..915f478dfa 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2017. 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. @@ -28,7 +28,7 @@ otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1, otp_11728/1, encoding/1, extends/1, function_macro/1, - test_error/1, test_warning/1]). + test_error/1, test_warning/1, otp_14285/1]). -export([epp_parse_erl_form/2]). @@ -68,7 +68,8 @@ all() -> not_circular, skip_header, otp_6277, otp_7702, otp_8130, overload_mac, otp_8388, otp_8470, otp_8562, otp_8665, otp_8911, otp_10302, otp_10820, otp_11728, - encoding, extends, function_macro, test_error, test_warning]. + encoding, extends, function_macro, test_error, test_warning, + otp_14285]. groups() -> [{upcase_mac, [], [upcase_mac_1, upcase_mac_2]}, @@ -677,7 +678,7 @@ otp_8130(Config) when is_list(Config) -> {otp_8130_c6, <<"-define(M3(), A).\n" "t() -> A = 1, ?3.14159}.\n">>, - {errors,[{{2,16},epp,{call,"?3.14159"}}],[]}}, + {errors,[{{2,16},epp,{call,[$?,"3.14159"]}}],[]}}, {otp_8130_c7, <<"\nt() -> ?A.\n">>, @@ -1384,6 +1385,26 @@ do_otp_10820(File, C, PC) -> true = test_server:stop_node(Node), ok. +%% OTP_14285: Unicode atoms. +otp_14285(Config) when is_list(Config) -> + %% This is just a sample of errors. + Cs = [{otp_8562, + <<"-export([f/0]). + -define('a\x{400}b', 'a\x{400}d'). + f() -> + ?'a\x{400}b'. + g() -> + ?\"a\x{400}b\". + h() -> + ?'a\x{400}no'(). + "/utf8>>, + {errors,[{6,epp,{call,[63,[91,["97",44,"1024",44,"98"],93]]}}, + {8,epp,{undefined,'a\x{400}no',0}}], + []}} + ], + [] = compile(Config, Cs), + ok. + %% OTP-11728. Bugfix circular macro. otp_11728(Config) when is_list(Config) -> Dir = proplists:get_value(priv_dir, Config), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index cc3d605840..6a75eaa737 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -66,7 +66,7 @@ otp_11851/1,otp_11879/1,otp_13230/1, record_errors/1, otp_11879_cont/1, non_latin1_module/1, otp_14323/1, - get_stacktrace/1]). + get_stacktrace/1, otp_14285/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -87,7 +87,7 @@ all() -> maps, maps_type, maps_parallel_match, otp_11851, otp_11879, otp_13230, record_errors, otp_11879_cont, non_latin1_module, otp_14323, - get_stacktrace]. + get_stacktrace, otp_14285]. groups() -> [{unused_vars_warn, [], @@ -3922,10 +3922,72 @@ otp_11879_cont(Config) -> %% OTP-14285: We currently don't support non-latin1 module names. -non_latin1_module(_Config) -> +non_latin1_module(Config) -> do_non_latin1_module('юникод'), do_non_latin1_module(list_to_atom([256,$a,$b,$c])), do_non_latin1_module(list_to_atom([$a,$b,256,$c])), + + "module names with non-latin1 characters are not supported" = + format_error(non_latin1_module_unsupported), + BadCallback = + {bad_callback,{'кирилли́ческий атом','кирилли́ческий атом',0}}, + "explicit module not allowed for callback " + "'кирилли́ческий атом':'кирилли́ческий атом'/0" = + format_error(BadCallback), + UndefBehav = {undefined_behaviour,'кирилли́ческий атом'}, + "behaviour 'кирилли́ческий атом' undefined" = + format_error(UndefBehav), + BadDepr = {bad_nowarn_deprecated_function, + {'кирилли́ческий атом','кирилли́ческий атом',18}}, + "'кирилли́ческий атом':'кирилли́ческий атом'/18 is not a deprecated " + "function" = format_error(BadDepr), + Ts = [{non_latin1_module, + <<" + %% Report uses of module names with non-Latin-1 characters. + + -import('кирилли́ческий атом', []). + -behaviour('кирилли́ческий атом'). + -behavior('кирилли́ческий атом'). + + -callback 'кирилли́ческий атом':'кирилли́ческий атом'() -> a. + + -compile([{nowarn_deprecated_function, + [{'кирилли́ческий атом','кирилли́ческий атом',18}]}]). + + %% erl_lint:gexpr/3 is not extended to check module name here: + t1() when 'кирилли́ческий атом':'кирилли́ческий атом'(1) -> + b. + + t2() -> + 'кирилли́ческий атом':'кирилли́ческий атом'(). + + -spec 'кирилли́ческий атом':'кирилли́ческий атом'() -> atom(). + + -spec 'кирилли́ческий атом'(integer()) -> + 'кирилли́ческий атом':'кирилли́ческий атом'(). + + 'кирилли́ческий атом'(1) -> + 'кирилли́ческий атом':f(), + F = f, + 'кирилли́ческий атом':F()."/utf8>>, + [], + {error, + [{4,erl_lint,non_latin1_module_unsupported}, + {5,erl_lint,non_latin1_module_unsupported}, + {6,erl_lint,non_latin1_module_unsupported}, + {8,erl_lint,non_latin1_module_unsupported}, + {8,erl_lint,BadCallback}, + {10,erl_lint,non_latin1_module_unsupported}, + {14,erl_lint,illegal_guard_expr}, + {18,erl_lint,non_latin1_module_unsupported}, + {20,erl_lint,non_latin1_module_unsupported}, + {23,erl_lint,non_latin1_module_unsupported}, + {26,erl_lint,non_latin1_module_unsupported}, + {28,erl_lint,non_latin1_module_unsupported}], + [{5,erl_lint,UndefBehav}, + {6,erl_lint,UndefBehav}, + {10,erl_lint,BadDepr}]}}], + run(Config, Ts), ok. do_non_latin1_module(Mod) -> @@ -4042,6 +4104,53 @@ get_stacktrace(Config) -> run(Config, Ts), ok. +%% Unicode atoms. +otp_14285(Config) -> + %% A small sample of all the errors and warnings in module erl_lint. + E1 = {redefine_function,{'кирилли́ческий атом',0}}, + E2 = {attribute,'кирилли́ческий атом'}, + E3 = {undefined_record,'кирилли́ческий атом'}, + E4 = {undefined_bittype,'кирилли́ческий атом'}, + "function 'кирилли́ческий атом'/0 already defined" = format_error(E1), + "attribute 'кирилли́ческий атом' after function definitions" = + format_error(E2), + "record 'кирилли́ческий атом' undefined" = format_error(E3), + "bit type 'кирилли́ческий атом' undefined" = format_error(E4), + Ts = [{otp_14285_1, + <<"'кирилли́ческий атом'() -> a. + 'кирилли́ческий атом'() -> a. + "/utf8>>, + [], + {errors, + [{2,erl_lint,E1}], + []}}, + {otp_14285_2, + <<"'кирилли́ческий атом'() -> a. + -'кирилли́ческий атом'(a). + "/utf8>>, + [], + {errors, + [{2,erl_lint,E2}], + []}}, + {otp_14285_3, + <<"'кирилли́ческий атом'() -> #'кирилли́ческий атом'{}. + "/utf8>>, + [], + {errors, + [{1,erl_lint,E3}], + []}}, + {otp_14285_4, + <<"t() -> <<34/'кирилли́ческий атом'>>. + "/utf8>>, + [], + {errors, + [{1,erl_lint,E4}], + []}}], + run(Config, Ts), + ok. + +format_error(E) -> + lists:flatten(erl_lint:format_error(E)). run(Config, Tests) -> F = fun({N,P,Ws,E}, BadL) -> diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl index f35013b1b2..d1e6faf863 100644 --- a/lib/stdlib/test/ms_transform_SUITE.erl +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2017. 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. @@ -43,6 +43,7 @@ -export([warnings/1]). -export([no_warnings/1]). -export([eep37/1]). +-export([otp_14454/1]). init_per_testcase(_Func, Config) -> Config. @@ -59,7 +60,7 @@ all() -> record_index, multipass, bitsyntax, record_defaults, andalso_orelse, float_1_function, action_function, warnings, no_warnings, top_match, old_guards, autoimported, - semicolon, eep37]. + semicolon, eep37, otp_14454]. groups() -> []. @@ -771,6 +772,16 @@ eep37(Config) when is_list(Config) -> "F()">>). +otp_14454(Config) when is_list(Config) -> + setup(Config), + [{'$1',[],[{'band','$1',136}]}] = + compile_and_run( + <<"ets:fun2ms(fun(A) -> A band ( -(-17) bsl 3) end)">>), + [{'$1',[],[{'band','$1',136}]}] = + compile_and_run( + <<"ets:fun2ms(fun(A) -> A band ( erlang:'bsl'(-(-17), 3)) end)">>), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Helpers diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl index a53e99afc9..029e6286e4 100644 --- a/lib/stdlib/test/proc_lib_SUITE.erl +++ b/lib/stdlib/test/proc_lib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. 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. @@ -27,7 +27,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, crash/1, stacktrace/1, sync_start_nolink/1, sync_start_link/1, - spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, + spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, '\x{447}'/0, hibernate/1, stop/1, t_format/1]). -export([ otp_6345/1, init_dont_hang/1]). @@ -139,6 +139,14 @@ crash(Config) when is_list(Config) -> {error_info,{exit,abnormal,{stacktrace}}}], analyse_crash(Pid5, Exp5, []), + %% Unicode atom + Pid6 = proc_lib:spawn(?MODULE, '\x{447}', []), + Pid6 ! die, + Exp6 = [{initial_call,{?MODULE,'\x{447}',[]}}, + {ancestors,[self()]}, + {error_info,{exit,die,{stacktrace}}}], + analyse_crash(Pid6, Exp6, []), + error_logger:delete_report_handler(?MODULE), ok. @@ -304,6 +312,12 @@ sp4(Parent, Tester) -> end, proc_lib:init_ack(Parent, self()). +'\x{447}'() -> + receive + die -> exit(die); + _ -> sp1() + end. + hibernate(Config) when is_list(Config) -> Ref = make_ref(), Self = self(), diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index 99411bc8fd..4f0fdc4c6a 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -376,6 +376,9 @@ records(Config) when is_list(Config) -> [[state]] = scan(RR4), Test = filename:join(proplists:get_value(priv_dir, Config), "test.erl"), + BeamDir = filename:join(proplists:get_value(priv_dir, Config), "beam"), + BeamFile = filename:join(BeamDir, "test"), + ok = file:make_dir(BeamDir), Contents = <<"-module(test). -record(state, {bin :: binary(), reply = no, @@ -387,8 +390,10 @@ records(Config) when is_list(Config) -> -ifdef(test2). -record(test2, {g}). - -endif.">>, + -endif. + ">>, ok = file:write_file(Test, Contents), + {ok, test} = compile:file(Test, [{outdir, BeamDir}]), RR5 = "rr(\"" ++ Test ++ "\", '_', {d,test1}), rl([test1,test2]).", A1 = erl_anno:new(1), @@ -404,7 +409,11 @@ records(Config) when is_list(Config) -> Dir = filename:join(proplists:get_value(priv_dir, Config), "*.erl"), RR8 = "rp(rr(\"" ++ Dir ++ "\")).", [_,ok] = scan(RR8), + + {module, test} = code:load_abs(BeamFile), + [[state]] = scan(<<"rr(test).">>), file:delete(Test), + file:delete(BeamFile++".beam"), RR1000 = "begin rr(" ++ MS ++ ") end.", [_] = scan(RR1000), @@ -2671,7 +2680,7 @@ prompt_err(B) -> S = string:strip(S2, both, $"), string:strip(S, right, $.). -%% OTP-10302. Unicode. +%% OTP-10302. Unicode. Also OTP-14285, Unicode atoms. otp_10302(Config) when is_list(Config) -> {ok,Node} = start_node(shell_suite_helper_2, "-pa "++proplists:get_value(priv_dir,Config)++ @@ -2809,6 +2818,22 @@ otp_10302(Config) when is_list(Config) -> " erl_eval:'-inside-an-interpreted-fun-'(65,\"\x{441}\")" " .\n" = t({Node,Test13}), + %% Unicode atoms. + Test14 = <<"'\\x{447}\\x{435}'().">>, + "** exception error: undefined shell command '\\x{447}\\x{435}'/0.\n" = + t(Test14), + Test15 = <<"io:setopts([{encoding,utf8}]). + '\\x{447}\\x{435}'().">>, + "ok.\n** exception error: undefined shell command '\x{447}\x{435}'/0.\n" = + t({Node,Test15}), + Test16 = <<"shell_SUITE:'\\x{447}\\x{435}'().">>, + "** exception error: undefined function " + "shell_SUITE:'\\x{447}\\x{435}'/0.\n" = t(Test16), + Test17 = <<"io:setopts([{encoding,utf8}]). + shell_SUITE:'\\x{447}\\x{435}'().">>, + "ok.\n** exception error: undefined function " + "shell_SUITE:'\x{447}\x{435}'/0.\n" = + t({Node,Test17}), test_server:stop_node(Node), ok. |