From 91316cccb9ca249928b2b969ef79710e1cf27c4d Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Thu, 10 Mar 2011 11:21:20 +0200 Subject: Add spec to dialyzer_cl_parse:get_lib_dir/1 --- lib/dialyzer/src/dialyzer_cl_parse.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl index b68d6d190e..6ecec421a2 100644 --- a/lib/dialyzer/src/dialyzer_cl_parse.erl +++ b/lib/dialyzer/src/dialyzer_cl_parse.erl @@ -304,6 +304,8 @@ common_options() -> %%----------------------------------------------------------------------- +-spec get_lib_dir([string()]) -> [string()]. + get_lib_dir(Apps) -> get_lib_dir(Apps, []). -- cgit v1.2.3 From 070d9917820c2dfe00b89f9b14bdb78db28aa3f5 Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Sat, 5 Mar 2011 19:06:10 +0200 Subject: Renamed error/1 function and added specs --- lib/dialyzer/src/dialyzer_cl_parse.erl | 40 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl index b68d6d190e..690ad7b8d3 100644 --- a/lib/dialyzer/src/dialyzer_cl_parse.erl +++ b/lib/dialyzer/src/dialyzer_cl_parse.erl @@ -20,10 +20,8 @@ -module(dialyzer_cl_parse). -%% Avoid warning for local function error/1 clashing with autoimported BIF. --compile({no_auto_import,[error/1]}). -export([start/0, get_lib_dir/1]). --export([collect_args/1]). % used also by typer_options.erl +-export([collect_args/1]). % used also by typer -include("dialyzer.hrl"). @@ -32,9 +30,11 @@ -type dial_cl_parse_ret() :: {'check_init', #options{}} | {'plt_info', #options{}} | {'cl', #options{}} - | {{'gui', 'gs' | 'wx'}, #options{}} + | {{'gui', 'gs' | 'wx'}, #options{}} | {'error', string()}. +-type deep_string() :: string() | [deep_string()]. + %%----------------------------------------------------------------------- -spec start() -> dial_cl_parse_ret(). @@ -82,7 +82,7 @@ cl(["--get_warnings"|T]) -> put(dialyzer_options_get_warnings, true), cl(T); cl(["-D"|_]) -> - error("No defines specified after -D"); + cl_error("No defines specified after -D"); cl(["-D"++Define|T]) -> Def = re:split(Define, "=", [{return, list}]), append_defines(Def), @@ -92,7 +92,7 @@ cl(["-h"|_]) -> cl(["--help"|_]) -> help_message(); cl(["-I"]) -> - error("no include directory specified after -I"); + cl_error("no include directory specified after -I"); cl(["-I", Dir|T]) -> append_include(Dir), cl(T); @@ -113,14 +113,14 @@ cl(["--com"++_|T]) -> NewTail = command_line(T), cl(NewTail); cl(["--output"]) -> - error("No outfile specified"); + cl_error("No outfile specified"); cl(["-o"]) -> - error("No outfile specified"); + cl_error("No outfile specified"); cl(["--output",Output|T]) -> put(dialyzer_output, Output), cl(T); cl(["--output_plt"]) -> - error("No outfile specified for --output_plt"); + cl_error("No outfile specified for --output_plt"); cl(["--output_plt",Output|T]) -> put(dialyzer_output_plt, Output), cl(T); @@ -139,7 +139,7 @@ cl(["--fullpath"|T]) -> cl(["-pa", Path|T]) -> case code:add_patha(Path) of true -> cl(T); - {error, _} -> error("Bad directory for -pa: "++Path) + {error, _} -> cl_error("Bad directory for -pa: " ++ Path) end; cl(["--plt"]) -> error("No plt specified for --plt"); @@ -174,14 +174,14 @@ cl(["--verbose"|T]) -> put(dialyzer_options_report_mode, verbose), cl(T); cl(["-W"|_]) -> - error("-W given without warning"); + cl_error("-W given without warning"); cl(["-Whelp"|_]) -> help_warnings(); cl(["-W"++Warn|T]) -> append_var(dialyzer_warnings, [list_to_atom(Warn)]), cl(T); cl(["--dump_callgraph"]) -> - error("No outfile specified for --dump_callgraph"); + cl_error("No outfile specified for --dump_callgraph"); cl(["--dump_callgraph", File|T]) -> put(dialyzer_callgraph_file, File), cl(T); @@ -197,7 +197,7 @@ cl([H|_] = L) -> NewTail = command_line(L), cl(NewTail); false -> - error("Unknown option: " ++ H) + cl_error("Unknown option: " ++ H) end; cl([]) -> {RetTag, Opts} = @@ -216,7 +216,7 @@ cl([]) -> end end, case dialyzer_options:build(Opts) of - {error, Msg} -> error(Msg); + {error, Msg} -> cl_error(Msg); OptsRecord -> {RetTag, OptsRecord} end. @@ -232,7 +232,9 @@ command_line(T0) -> end, T. -error(Str) -> +-spec cl_error(deep_string()) -> no_return(). + +cl_error(Str) -> Msg = lists:flatten(Str), throw({dialyzer_cl_parse_error, Msg}). @@ -330,11 +332,15 @@ get_plts([], Acc) -> {lists:reverse(Acc), []}. %%----------------------------------------------------------------------- +-spec help_warnings() -> no_return(). + help_warnings() -> S = warning_options_msg(), io:put_chars(S), erlang:halt(?RET_NOTHING_SUSPICIOUS). +-spec help_message() -> no_return(). + help_message() -> S = "Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [-pa dir]* [--plt plt] [--plts plt*] [-Ddefine]* @@ -494,13 +500,13 @@ warning_options_msg() -> Include warnings about behaviour callbacks which drift from the published recommended interfaces. -Wunderspecs *** - Warn about underspecified functions + Warn about underspecified functions (those whose -spec is strictly more allowing than the success typing). The following options are also available but their use is not recommended: (they are mostly for Dialyzer developers and internal debugging) -Woverspecs *** - Warn about overspecified functions + Warn about overspecified functions (those whose -spec is strictly less allowing than the success typing). -Wspecdiffs *** Warn when the -spec is different than the success typing. -- cgit v1.2.3 From 6cc382ee4d230d0168accc37d53fb46f0a430601 Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Sat, 5 Mar 2011 19:06:54 +0200 Subject: Renamed error/1 function and added specs --- lib/dialyzer/src/dialyzer_plt.erl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index a7ba270c41..807c9af44f 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -28,8 +28,6 @@ %%%------------------------------------------------------------------- -module(dialyzer_plt). -%% Avoid warning for local function error/1 clashing with autoimported BIF. --compile({no_auto_import,[error/1]}). -export([check_plt/3, compute_md5_from_files/1, contains_mfa/2, @@ -56,8 +54,7 @@ plt_and_info_from_file/1, get_specs/1, get_specs/4, - to_file/4 - ]). + to_file/4]). %% Debug utilities -export([pp_non_returning/0, pp_mod/1]). @@ -68,6 +65,8 @@ -type mod_deps() :: dict(). +-type deep_string() :: string() | [deep_string()]. + %% The following are used for searching the PLT when using the GUI %% (e.g. in show or search PLT contents). The user might be searching %% with a partial specification, in which case the missing items @@ -203,8 +202,8 @@ get_default_plt() -> false -> case os:getenv("HOME") of false -> - error("The HOME environment variable needs to be set " ++ - "so that Dialyzer knows where to find the default PLT"); + plt_error("The HOME environment variable needs to be set " ++ + "so that Dialyzer knows where to find the default PLT"); HomeDir -> filename:join(HomeDir, ".dialyzer_plt") end; UserSpecPlt -> UserSpecPlt @@ -226,7 +225,7 @@ from_file(FileName, ReturnInfo) -> case check_version(Rec) of error -> Msg = io_lib:format("Old PLT file ~s\n", [FileName]), - error(Msg); + plt_error(Msg); ok -> Plt = #plt{info = Rec#file_plt.info, types = Rec#file_plt.types, @@ -241,8 +240,9 @@ from_file(FileName, ReturnInfo) -> end end; {error, Reason} -> - error(io_lib:format("Could not read PLT file ~s: ~p\n", - [FileName, Reason])) + Msg = io_lib:format("Could not read PLT file ~s: ~p\n", + [FileName, Reason]), + plt_error(Msg) end. -type err_rsn() :: 'not_valid' | 'no_such_file' | 'read_error'. @@ -518,7 +518,9 @@ expand_args([ArgType|Left]) -> end ++ ","|expand_args(Left)]. -error(Msg) -> +-spec plt_error(deep_string()) -> no_return(). + +plt_error(Msg) -> throw({dialyzer_error, lists:flatten(Msg)}). %%--------------------------------------------------------------------------- -- cgit v1.2.3 From c639406ac2d53e56ce941717285f3f41068d0bdd Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Sat, 5 Mar 2011 19:07:46 +0200 Subject: Refactoring so that a flat string() is returned --- lib/dialyzer/src/dialyzer_utils.erl | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index 248fdf6835..12f8dec67e 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -214,14 +214,13 @@ get_record_and_type_info([], _Module, Records, RecDict) -> ?debug(_NewRecDict), Ok; {error, Name, Error} -> - {error, lists:flatten(io_lib:format(" Error while parsing #~w{}: ~s\n", - [Name, Error]))} + {error, flat_format(" Error while parsing #~w{}: ~s\n", [Name, Error])} end. add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, RecDict) -> case erl_types:type_is_defined(TypeOrOpaque, Name, RecDict) of true -> - throw({error, io_lib:format("Type already defined: ~w\n", [Name])}); + throw({error, flat_format("Type ~s already defined\n", [Name])}); false -> ArgTypes = [erl_types:t_from_form(X) || X <- ArgForms], case lists:all(fun erl_types:t_is_var/1, ArgTypes) of @@ -229,8 +228,8 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, RecDict) -> ArgNames = [erl_types:t_var_name(X) || X <- ArgTypes], dict:store({TypeOrOpaque, Name}, {Module, TypeForm, ArgNames}, RecDict); false -> - throw({error, io_lib:format("Type declaration for ~w does not " - "have variables as parameters", [Name])}) + throw({error, flat_format("Type declaration for ~w does not " + "have variables as parameters", [Name])}) end end. @@ -338,14 +337,14 @@ get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left], get_spec_info(Left, NewSpecDict, RecordsDict, ModName, File); {ok, {{OtherFile, L},_C}} -> {Mod, Fun, Arity} = MFA, - Msg = io_lib:format(" Contract for function ~w:~w/~w " - "already defined in ~s:~w\n", - [Mod, Fun, Arity, OtherFile, L]), + Msg = flat_format(" Contract for function ~w:~w/~w " + "already defined in ~s:~w\n", + [Mod, Fun, Arity, OtherFile, L]), throw({error, Msg}) catch throw:{error, Error} -> - {error, lists:flatten(io_lib:format(" Error while parsing contract " - "in line ~w: ~s\n", [Ln, Error]))} + {error, flat_format(" Error while parsing contract in line ~w: ~s\n", + [Ln, Error])} end; get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left], SpecDict, RecordsDict, ModName, _File) -> @@ -419,6 +418,9 @@ format_sig(Type, RecDict) -> ")" ++ RevSig = lists:reverse(Sig), lists:reverse(RevSig). +flat_format(Fmt, Lst) -> + lists:flatten(io_lib:format(Fmt, Lst)). + %%------------------------------------------------------------------- %% Author : Per Gustafsson %% Description : Provides better printing of binaries. -- cgit v1.2.3 From 8148d9a6e19e54e4f6769062ee4e01c8291f4fbf Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Sat, 5 Mar 2011 19:10:14 +0200 Subject: Fix an erroneous warning --- lib/dialyzer/src/dialyzer_dataflow.erl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 2ffbcd3e82..f4e429e6fd 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -2,7 +2,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -2217,7 +2217,7 @@ bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State) -> true -> {Map1, t_atom(true)}; false -> {_, Type0} = bind_guard(Arg2, Map, Env, Eval, State), - signal_guard_fail(Eval, Guard, [Type0, t_atom(true)], State) + signal_guard_fail(Eval, Guard, [Type0, t_atom(false)], State) end; Term -> LitType = t_from_term(Term), @@ -2767,8 +2767,6 @@ state__new(Callgraph, Tree, Plt, Module, Records, BehaviourTranslations) -> FunTab = init_fun_tab(Funs, dict:new(), TreeMap, Callgraph, Plt, Opaques), Work = init_work([get_label(Tree)]), Env = dict:store(top, map__new(), dict:new()), - Opaques = erl_types:module_builtin_opaques(Module) ++ - erl_types:t_opaque_from_records(Records), #state{callgraph = Callgraph, envs = Env, fun_tab = FunTab, opaques = Opaques, plt = Plt, races = dialyzer_races:new(), records = Records, warning_mode = false, warnings = [], work = Work, tree_map = TreeMap, -- cgit v1.2.3 From 31ffea630ffd73d39970c3def796b00dd782373d Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 6 Mar 2011 00:01:59 +0200 Subject: Generate better warnings for failing guards --- lib/dialyzer/src/dialyzer.erl | 3 +++ lib/dialyzer/src/dialyzer_dataflow.erl | 42 +++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index dde0c17c39..3e7680f4bb 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -334,6 +334,9 @@ 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]); +message_to_string({neg_guard_fail, [Arg1, Infix, Arg2]}) -> + io_lib:format("Guard test not(~s ~s ~s) 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]); message_to_string({neg_guard_fail, [Guard, Args]}) -> diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index f4e429e6fd..b01e7a4b05 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -2087,7 +2087,10 @@ handle_guard_eq(Guard, Map, Env, Eval, State) -> true -> if Eval =:= pos -> {Map, t_atom(true)}; - Eval =:= neg -> throw({fail, none}); + Eval =:= neg -> + ArgTypes = [t_from_term(cerl:concrete(Arg1)), + t_from_term(cerl:concrete(Arg2))], + signal_guard_fail(Eval, Guard, ArgTypes, State); Eval =:= dont_know -> {Map, t_atom(true)} end; false -> @@ -2142,7 +2145,10 @@ handle_guard_eqeq(Guard, Map, Env, Eval, State) -> {literal, literal} -> case cerl:concrete(Arg1) =:= cerl:concrete(Arg2) of true -> - if Eval =:= neg -> throw({fail, none}); + if Eval =:= neg -> + ArgTypes = [t_from_term(cerl:concrete(Arg1)), + t_from_term(cerl:concrete(Arg2))], + signal_guard_fail(Eval, Guard, ArgTypes, State); Eval =:= pos -> {Map, t_atom(true)}; Eval =:= dont_know -> {Map, t_atom(true)} end; @@ -2238,11 +2244,11 @@ handle_guard_and(Guard, Map, Env, Eval, State) -> pos -> {Map1, Type1} = bind_guard(Arg1, Map, Env, Eval, State), case t_is_atom(true, Type1) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, t_any()], State); true -> {Map2, Type2} = bind_guard(Arg2, Map1, Env, Eval, State), case t_is_atom(true, Type2) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State); true -> {Map2, t_atom(true)} end end; @@ -2257,7 +2263,7 @@ handle_guard_and(Guard, Map, Env, Eval, State) -> end, case t_is_atom(false, Type1) orelse t_is_atom(false, Type2) of true -> {join_maps([Map1, Map2], Map), t_atom(false)}; - false -> throw({fail, none}) + false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State) end; dont_know -> {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State), @@ -2297,16 +2303,16 @@ handle_guard_or(Guard, Map, Env, Eval, State) -> orelse (t_is_atom(true, Bool2) andalso t_is_boolean(Bool1))) of true -> {join_maps([Map1, Map2], Map), t_atom(true)}; - false -> throw({fail, none}) + false -> signal_guard_fail(Eval, Guard, [Bool1, Bool2], State) end; neg -> {Map1, Type1} = bind_guard(Arg1, Map, Env, neg, State), case t_is_atom(false, Type1) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, t_any()], State); true -> {Map2, Type2} = bind_guard(Arg2, Map1, Env, neg, State), case t_is_atom(false, Type2) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State); true -> {Map2, t_atom(false)} end end; @@ -2337,13 +2343,17 @@ handle_guard_not(Guard, Map, Env, Eval, State) -> {Map1, Type} = bind_guard(Arg, Map, Env, pos, State), case t_is_atom(true, Type) of true -> {Map1, t_atom(false)}; - false -> throw({fail, none}) + false -> + {_, Type0} = bind_guard(Arg, Map, Env, Eval, State), + signal_guard_fail(Eval, Guard, [Type0], State) end; pos -> {Map1, Type} = bind_guard(Arg, Map, Env, neg, State), case t_is_atom(false, Type) of true -> {Map1, t_atom(true)}; - false -> throw({fail, none}) + false -> + {_, Type0} = bind_guard(Arg, Map, Env, Eval, State), + signal_guard_fail(Eval, Guard, [Type0], State) end; dont_know -> {Map1, Type} = bind_guard(Arg, Map, Env, dont_know, State), @@ -2382,9 +2392,15 @@ signal_guard_fail(Eval, Guard, ArgTypes, State) -> true -> [ArgType1, ArgType2] = ArgTypes, [Arg1, Arg2] = Args, - {guard_fail, [format_args_1([Arg1], [ArgType1], State), - atom_to_list(F), - format_args_1([Arg2], [ArgType2], State)]}; + Kind = + case Eval of + neg -> neg_guard_fail; + pos -> guard_fail; + dont_know -> guard_fail + end, + {Kind, [format_args_1([Arg1], [ArgType1], State), + atom_to_list(F), + format_args_1([Arg2], [ArgType2], State)]}; false -> mk_guard_msg(Eval, F, Args, ArgTypes, State) end, -- cgit v1.2.3 From 8342fcf5395133a19d647f2ace606af9b7fc1732 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 22 Feb 2011 02:41:06 +0200 Subject: Better blame assignment when a spec is erroneous Applies to the specification of the return value of a function. --- lib/dialyzer/src/dialyzer.erl | 4 +++ lib/dialyzer/src/dialyzer.hrl | 5 +-- lib/dialyzer/src/dialyzer_dataflow.erl | 53 ++++++++++++++++++++---------- lib/dialyzer/src/dialyzer_options.erl | 1 + lib/dialyzer/src/dialyzer_succ_typings.erl | 26 +++++++++++++-- 5 files changed, 68 insertions(+), 21 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 3e7680f4bb..683b518831 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -394,6 +394,10 @@ 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", [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", + [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]); diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl index aa3f703af2..9d2e554981 100644 --- a/lib/dialyzer/src/dialyzer.hrl +++ b/lib/dialyzer/src/dialyzer.hrl @@ -52,10 +52,11 @@ -define(WARN_CONTRACT_NOT_EQUAL, warn_contract_not_equal). -define(WARN_CONTRACT_SUBTYPE, warn_contract_subtype). -define(WARN_CONTRACT_SUPERTYPE, warn_contract_supertype). +-define(WARN_CONTRACT_RANGE, warn_contract_range). -define(WARN_CALLGRAPH, warn_callgraph). -define(WARN_UNMATCHED_RETURN, warn_umatched_return). -define(WARN_RACE_CONDITION, warn_race_condition). --define(WARN_BEHAVIOUR,warn_behaviour). +-define(WARN_BEHAVIOUR, warn_behaviour). %% %% The following type has double role: @@ -70,7 +71,7 @@ | ?WARN_CONTRACT_NOT_EQUAL | ?WARN_CONTRACT_SUBTYPE | ?WARN_CONTRACT_SUPERTYPE | ?WARN_CALLGRAPH | ?WARN_UNMATCHED_RETURN | ?WARN_RACE_CONDITION - | ?WARN_BEHAVIOUR. + | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE. %% %% This is the representation of each warning as they will be returned diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index b01e7a4b05..215b4d67c1 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -657,7 +657,8 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], true -> opaque; false -> structured end, - RetWithoutLocal = t_inf(t_inf(ContrRet, BifRet, RetMode), SigRange, RetMode), + RetWithoutContr = t_inf(SigRange, BifRet, RetMode), + RetWithoutLocal = t_inf(ContrRet, RetWithoutContr, RetMode), ?debug("--------------------------------------------------------\n", []), ?debug("Fun: ~p\n", [Fun]), ?debug("Args: ~s\n", [erl_types:t_to_string(t_product(ArgTypes))]), @@ -666,6 +667,7 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], [erl_types:t_to_string(t_product(NewArgsContract))]), ?debug("NewArgsBif: ~s\n", [erl_types:t_to_string(t_product(NewArgsBif))]), ?debug("NewArgTypes: ~s\n", [erl_types:t_to_string(t_product(NewArgTypes))]), + ?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("ContrRet: ~s\n", [erl_types:t_to_string(CRange(TmpArgTypes))]), @@ -700,22 +702,39 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], State2 = case FailedConj andalso not (IsFailBif orelse IsFailSig) of true -> - FailedSig = any_none(NewArgsSig), - FailedContract = any_none([CRange(TmpArgsContract)|NewArgsContract]), - FailedBif = any_none([BifRange(NewArgsBif)|NewArgsBif]), - InfSig = t_inf(t_fun(SigArgs, SigRange), - t_fun(BifArgs, BifRange(BifArgs))), - FailReason = apply_fail_reason(FailedSig, FailedBif, FailedContract), - Msg = get_apply_fail_msg(Fun, Args, ArgTypes, NewArgTypes, InfSig, - Contr, CArgs, State1, FailReason), - WarnType = case Msg of - {call, _} -> ?WARN_FAILING_CALL; - {apply, _} -> ?WARN_FAILING_CALL; - {call_with_opaque, _} -> ?WARN_OPAQUE; - {call_without_opaque, _} -> ?WARN_OPAQUE; - {opaque_type_test, _} -> ?WARN_OPAQUE - end, - state__add_warning(State1, WarnType, Tree, Msg); + case t_is_none(RetWithoutLocal) andalso + not t_is_none(RetWithoutContr) andalso + not any_none(NewArgTypes) of + true -> + {value, C1} = Contr, + Contract = dialyzer_contracts:contract_to_string(C1), + {M1, F1, A1} = state__lookup_name(Fun, State), + ArgStrings = format_args(Args, ArgTypes, State), + CRet = erl_types:t_to_string(RetWithoutContr), + %% This Msg will be post_processed by dialyzer_succ_typings + Msg = + {contract_range, [Contract, M1, F1, A1, ArgStrings, CRet]}, + state__add_warning(State1, ?WARN_CONTRACT_RANGE, Tree, Msg); + false -> + FailedSig = any_none(NewArgsSig), + FailedContract = + any_none([CRange(TmpArgsContract)|NewArgsContract]), + FailedBif = any_none([BifRange(NewArgsBif)|NewArgsBif]), + InfSig = t_inf(t_fun(SigArgs, SigRange), + t_fun(BifArgs, BifRange(BifArgs))), + FailReason = + apply_fail_reason(FailedSig, FailedBif, FailedContract), + Msg = get_apply_fail_msg(Fun, Args, ArgTypes, NewArgTypes, InfSig, + Contr, CArgs, State1, FailReason), + WarnType = case Msg of + {call, _} -> ?WARN_FAILING_CALL; + {apply, _} -> ?WARN_FAILING_CALL; + {call_with_opaque, _} -> ?WARN_OPAQUE; + {call_without_opaque, _} -> ?WARN_OPAQUE; + {opaque_type_test, _} -> ?WARN_OPAQUE + end, + state__add_warning(State1, WarnType, Tree, Msg) + end; false -> State1 end, State3 = diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index 29e164628a..b2a67de8bd 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -47,6 +47,7 @@ build(Opts) -> ?WARN_FAILING_CALL, ?WARN_BIN_CONSTRUCTION, ?WARN_CALLGRAPH, + ?WARN_CONTRACT_RANGE, ?WARN_CONTRACT_TYPES, ?WARN_CONTRACT_SYNTAX], DefaultWarns1 = ordsets:from_list(DefaultWarns), diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index 8bfc66fc39..daf68d24f0 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -131,8 +131,9 @@ get_warnings_from_modules([M|Ms], State, DocPlt, %% Check if there are contracts for functions that do not exist Warnings1 = dialyzer_contracts:contracts_without_fun(Contracts, AllFuns, Callgraph), - {Warnings2, FunTypes, RaceCode, PublicTables, NamedTables} = + {RawWarnings2, FunTypes, RaceCode, PublicTables, NamedTables} = dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Records, NoWarnUnused), + {NewAcc, Warnings2} = postprocess_dataflow_warns(RawWarnings2, State, Acc), Attrs = cerl:module_attrs(ModCode), Warnings3 = if BehavioursChk -> dialyzer_behaviours:check_callbacks(M, Attrs, @@ -145,10 +146,31 @@ get_warnings_from_modules([M|Ms], State, DocPlt, NamedTables), State1 = st__renew_state_calls(NewCallgraph, State), get_warnings_from_modules(Ms, State1, NewDocPlt, BehavioursChk, - [Warnings1, Warnings2, Warnings3|Acc]); + [Warnings1, Warnings2, Warnings3|NewAcc]); get_warnings_from_modules([], #st{plt = Plt}, DocPlt, _, Acc) -> {lists:flatten(Acc), Plt, DocPlt}. +postprocess_dataflow_warns(RawWarnings, State, WarnAcc) -> + postprocess_dataflow_warns(RawWarnings, State, WarnAcc, []). + +postprocess_dataflow_warns([], _State, WAcc, Acc) -> + {WAcc, lists:reverse(Acc)}; +postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {File, CallL}, Msg}|Rest], + #st{codeserver = Codeserver} = State, WAcc, Acc) -> + {contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg, + {ok, {{File, _ContrL} = FileLine, _C}} = + dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver), + NewMsg = + {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, + W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, + Filter = + fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; + (_) -> true + end, + postprocess_dataflow_warns(Rest, State, lists:filter(Filter, WAcc), [W|Acc]); +postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) -> + postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]). + refine_succ_typings(ModulePostorder, State) -> ?debug("Module postorder: ~p\n", [ModulePostorder]), refine_succ_typings(ModulePostorder, State, []). -- cgit v1.2.3 From f01ef637c938cf3cf295eb3ae1d579516723ee80 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 8 Mar 2011 15:28:09 +0200 Subject: More descriptive warning when a tuple pattern matches a typed record --- lib/dialyzer/src/dialyzer.erl | 3 +++ lib/dialyzer/src/dialyzer_dataflow.erl | 41 +++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 13 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 683b518831..5014a4244c 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -368,6 +368,9 @@ message_to_string({record_constr, [Name, Field, Type]}) -> message_to_string({record_matching, [String, Name]}) -> io_lib:format("The ~s violates the" " declared type for #~w{}\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]); message_to_string({pattern_match, [Pat, Type]}) -> io_lib:format("The ~s can never match the type ~s\n", [Pat, Type]); message_to_string({pattern_match_cov, [Pat, Type]}) -> diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 215b4d67c1..7137dbc036 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -1369,7 +1369,7 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, bind_pat_vars(Pats, ArgTypes, [], Map1, State1) end, case BindRes of - {error, BindOrOpaque, NewPats, Type, OpaqueTerm} -> + {error, ErrorType, NewPats, Type, OpaqueTerm} -> ?debug("Failed binding pattern: ~s\nto ~s\n", [cerl_prettypr:format(C), format_type(ArgType0, State1)]), case state__warning_mode(State1) of @@ -1377,8 +1377,9 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, {State1, Map, t_none(), ArgType0}; true -> PatString = - case BindOrOpaque of + case ErrorType of bind -> format_patterns(Pats); + record -> format_patterns(Pats); opaque -> format_patterns(NewPats) end, {Msg, Force} = @@ -1418,13 +1419,15 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, false -> true end, - PatTypes = case BindOrOpaque of + PatTypes = case ErrorType of bind -> [PatString, format_type(ArgType0, State1)]; + record -> [PatString, format_type(Type, State1)]; opaque -> [PatString, format_type(Type, State1), format_type(OpaqueTerm, State1)] - end, - FailedMsg = case BindOrOpaque of + end, + FailedMsg = case ErrorType of bind -> {pattern_match, PatTypes}; + record -> {record_match, PatTypes}; opaque -> {opaque_match, PatTypes} end, {FailedMsg, Force0} @@ -1432,6 +1435,7 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, WarnType = case Msg of {opaque_match, _} -> ?WARN_OPAQUE; {pattern_match, _} -> ?WARN_MATCHING; + {record_match, _} -> ?WARN_MATCHING; {pattern_match_cov, _} -> ?WARN_MATCHING end, {state__add_warning(State1, WarnType, C, Msg, Force), @@ -1525,14 +1529,18 @@ bind_pat_vars(Pats, Types, Acc, Map, State) -> try bind_pat_vars(Pats, Types, Acc, Map, State, false) catch - throw:Error -> Error % Error = {error, bind | opaque, ErrorPats, ErrorType} + throw:Error -> + %% Error = {error, bind | opaque | record, ErrorPats, ErrorType} + Error end. bind_pat_vars_reverse(Pats, Types, Acc, Map, State) -> try bind_pat_vars(Pats, Types, Acc, Map, State, true) catch - throw:Error -> Error % Error = {error, bind | opaque, ErrorPats, ErrorType} + throw:Error -> + %% Error = {error, bind | opaque | record, ErrorPats, ErrorType} + Error end. bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) -> @@ -1587,18 +1595,21 @@ bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) -> end; tuple -> Es = cerl:tuple_es(Pat), - Prototype = + {TypedRecord, Prototype} = case Es of - [] -> t_tuple([]); + [] -> {false, t_tuple([])}; [Tag|Left] -> case cerl:is_c_atom(Tag) of true -> TagAtom = cerl:atom_val(Tag), case state__lookup_record(TagAtom, length(Left), State) of - error -> t_tuple(length(Es)); - {ok, Record} -> Record + error -> {false, t_tuple(length(Es))}; + {ok, Record} -> + [_Head|AnyTail] = [t_any() || _ <- Es], + UntypedRecord = t_tuple([t_atom(TagAtom)|AnyTail]), + {not erl_types:t_is_equal(Record, UntypedRecord), Record} end; - false -> t_tuple(length(Es)) + false -> {false, t_tuple(length(Es))} end end, Tuple = t_inf(Prototype, Type), @@ -1623,7 +1634,11 @@ bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) -> bind_error([Pat], Tuple, Opaque, opaque); false -> case [M || {M, _} <- Results, M =/= error] of - [] -> bind_error([Pat], Tuple, t_none(), bind); + [] -> + case TypedRecord of + true -> bind_error([Pat], Tuple, Prototype, record); + false -> bind_error([Pat], Tuple, t_none(), bind) + end; Maps -> Map1 = join_maps(Maps, Map), TupleType = t_sup([t_tuple(EsTypes) -- cgit v1.2.3 From 8c563c842e1966391c4dfbced4426a2ce2e9e7cb Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Wed, 9 Mar 2011 01:58:45 +0200 Subject: Release notes and new version for R14B02 --- lib/dialyzer/RELEASE_NOTES | 12 ++++++++++++ lib/dialyzer/vsn.mk | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/RELEASE_NOTES b/lib/dialyzer/RELEASE_NOTES index 3fd5e9cc7d..4e311bb543 100644 --- a/lib/dialyzer/RELEASE_NOTES +++ b/lib/dialyzer/RELEASE_NOTES @@ -3,6 +3,18 @@ (in reversed chronological order) ============================================================================== +Version 2.4.2 (in Erlang/OTP R14B02) +------------------------------------ + - Added --fullpath option to display files with warnings with their full + file names (thanks to Magnus Henoch for the original patch). + - Better handling of 'and'/'or'/'not' guards that generate warnings + (thanks to Stavros Aronis). + - Better blame assignment for cases when a function's spec is erroneous + (thanks to Stavros Aronis). + - More descriptive warnings when a tuple/record pattern contains subterms + that violate the declared types of record fields (thanks to Matthias Lang + for the test case and for Stavros Aronis for the actual fix). + Version 2.4.0 (in Erlang/OTP R14B01) ------------------------------------ - Added ability to supply multiple PLTs for the analysis (option --plts). diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk index b2902e95ed..53b6f8c553 100644 --- a/lib/dialyzer/vsn.mk +++ b/lib/dialyzer/vsn.mk @@ -1 +1 @@ -DIALYZER_VSN = 2.4.0 +DIALYZER_VSN = 2.4.2 -- cgit v1.2.3 From d53be747c945d5e86997e1944446795b271dacb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 11 Mar 2011 17:34:22 +0100 Subject: Update copyright years --- lib/dialyzer/doc/src/dialyzer.xml | 2 +- lib/dialyzer/src/dialyzer_gui.erl | 2 +- lib/dialyzer/src/dialyzer_plt.erl | 2 +- lib/dialyzer/src/dialyzer_succ_typings.erl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index 8813d51f1f..b6547b11e1 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -4,7 +4,7 @@
- 20062010 + 20062011 Ericsson AB. All Rights Reserved. diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl index 4436330f7f..ccd80a4835 100644 --- a/lib/dialyzer/src/dialyzer_gui.erl +++ b/lib/dialyzer/src/dialyzer_gui.erl @@ -2,7 +2,7 @@ %%------------------------------------------------------------------------ %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 807c9af44f..8d62f2c529 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -2,7 +2,7 @@ %%---------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index daf68d24f0..24d6013692 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in -- cgit v1.2.3 From 91b2e57ea0e3ab794d4b57a12ef10205383525a5 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Mon, 14 Mar 2011 18:18:42 +0100 Subject: Prepare release --- lib/dialyzer/doc/src/notes.xml | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml index 3678291be7..f132a50e0d 100755 --- a/lib/dialyzer/doc/src/notes.xml +++ b/lib/dialyzer/doc/src/notes.xml @@ -31,6 +31,92 @@

This document describes the changes made to the Dialyzer application.

+
Dialyzer 2.4.2 + +
Fixed Bugs and Malfunctions + + +

+ Add a --fullpath option to Dialyzer

+

+ This change adds a --fullpath option to Dialyzer, which + makes the warning messages contain the full path of the + corresponding file.

+

+ Original patch submitted by Magnus Henoch (legoscia) on + 15/9/2010 and cooked to death in the 'pu' branch all this + time.

+

+ The patch was essentially correct and most of it has been + used as is, but there have been some changes to make the + code slightly prettier, avoid some code duplication, and + add documentation to dialyzer's doc files and to its help + message.

+

+ Own Id: OTP-9098

+
+ +

+ Fix warnings about guards containing not

+

+ The wording of warnings about unsatisfiable guards that + used 'not' was incorrect (the 'not' was not mentioned and + it appeared as "Guard test is_atom(atom()) can never + succeed") (thanks to Stavros Aronis).

+

+ Own Id: OTP-9099

+
+ +

+ Version 2.4.2 (in Erlang/OTP R14B02) + ------------------------------------ - Added --fullpath + option to display files with warnings with their full + file names (thanks to Magnus Henoch for the original + patch). - Better handling of 'and'/'or'/'not' guards that + generate warnings (thanks to Stavros Aronis). - Better + blame assignment for cases when a function's spec is + erroneous (thanks to Stavros Aronis). - More descriptive + warnings when a tuple/record pattern contains subterms + that violate the declared types of record fields (thanks + to Matthias Lang for the test case and for Stavros Aronis + for the actual fix).

+

+ Own Id: OTP-9126

+
+ +

+ Add spec to dialyzer_cl_parse:get_lib_dir/1

+

+ Own Id: OTP-9129

+
+
+
+ + +
Improvements and New Features + + +

+ Test suites for Dialyzer

+

+ This is a transcription of most of the + cvs.srv.it.uu.se:/hipe repository dialyzer_tests into + test suites that use the test server framework.

+

+ See README for information on how to use the included + scripts for modifications and updates.

+

+ When testing Dialyzer it's important that several OTP + modules are included in the plt. The suites takes care of + that too.

+

+ Own Id: OTP-9116

+
+
+
+ +
+
Dialyzer 2.4.0
Fixed Bugs and Malfunctions -- cgit v1.2.3 From deaaaa252863fbda315f7eeee37fcb903c36494e Mon Sep 17 00:00:00 2001 From: Maria Christakis Date: Tue, 29 Mar 2011 20:07:16 +0300 Subject: Fix the name of an error function --- lib/dialyzer/src/dialyzer_plt.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 8d62f2c529..6033d7f17c 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -317,7 +317,7 @@ merge_plts_or_report_conflicts(PltFiles, Plts) -> 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]), - error(Msg) + plt_error(Msg) end. find_duplicates(List) -> -- cgit v1.2.3 From beec1818a8f6b3176bd0c7558feaf7cecad3da3a Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Tue, 29 Mar 2011 19:19:19 +0300 Subject: Fix crash related with the contract blame assignment patch The relevant commit is 8342fcf5395133a19d647f2ace606af9b7fc1732. The old patch could emit warnings even for function that had a problematic spec even without refinement. This warnings would consume the relevant invalid spec warnings. This patch takes care of this by ensuring that normal invalid spec messages are emitted if the call that triggers the blame contract range warning is in another module. --- lib/dialyzer/src/dialyzer_succ_typings.erl | 25 ++++++++------ lib/dialyzer/test/small_tests_SUITE.erl | 38 +++++++++++++--------- .../small_tests_SUITE_data/results/invalid_specs | 3 ++ .../src/invalid_specs/invalid_spec1.erl | 28 ++++++++++++++++ .../src/invalid_specs/invalid_spec2.erl | 11 +++++++ 5 files changed, 79 insertions(+), 26 deletions(-) create mode 100644 lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs create mode 100644 lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl create mode 100644 lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index 24d6013692..b8da57d3f9 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -155,19 +155,24 @@ postprocess_dataflow_warns(RawWarnings, State, WarnAcc) -> postprocess_dataflow_warns([], _State, WAcc, Acc) -> {WAcc, lists:reverse(Acc)}; -postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {File, CallL}, Msg}|Rest], +postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest], #st{codeserver = Codeserver} = State, WAcc, Acc) -> {contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg, - {ok, {{File, _ContrL} = FileLine, _C}} = + {ok, {{ContrF, _ContrL} = FileLine, _C}} = dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver), - NewMsg = - {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, - W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, - Filter = - fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; - (_) -> true - end, - postprocess_dataflow_warns(Rest, State, lists:filter(Filter, WAcc), [W|Acc]); + case CallF =:= ContrF of + true -> + NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, + W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, + Filter = + fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; + (_) -> true + end, + FilterWAcc = lists:filter(Filter, WAcc), + postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]); + false -> + postprocess_dataflow_warns(Rest, State, WAcc, Acc) + end; postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) -> postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]). diff --git a/lib/dialyzer/test/small_tests_SUITE.erl b/lib/dialyzer/test/small_tests_SUITE.erl index 21a2c76160..dbcc044eea 100644 --- a/lib/dialyzer/test/small_tests_SUITE.erl +++ b/lib/dialyzer/test/small_tests_SUITE.erl @@ -18,18 +18,18 @@ contract5/1, disj_norm_form/1, eqeq/1, ets_select/1, exhaust_case/1, failing_guard1/1, flatten/1, fun_app/1, fun_ref_match/1, fun_ref_record/1, gencall/1, gs_make/1, - inf_loop2/1, letrec1/1, list_match/1, lzip/1, make_tuple/1, - minus_minus/1, mod_info/1, my_filter/1, my_sofs/1, no_match/1, - no_unused_fun/1, no_unused_fun2/1, non_existing/1, - not_guard_crash/1, or_bug/1, orelsebug/1, orelsebug2/1, - overloaded1/1, port_info_test/1, process_info_test/1, pubsub/1, - receive1/1, record_construct/1, record_pat/1, - record_send_test/1, record_test/1, recursive_types1/1, - recursive_types2/1, recursive_types3/1, recursive_types4/1, - recursive_types5/1, recursive_types6/1, recursive_types7/1, - refine_bug1/1, toth/1, trec/1, try1/1, tuple1/1, - unsafe_beamcode_bug/1, unused_cases/1, unused_clauses/1, - zero_tuple/1]). + inf_loop2/1, invalid_specs/1, letrec1/1, list_match/1, lzip/1, + make_tuple/1, minus_minus/1, mod_info/1, my_filter/1, + my_sofs/1, no_match/1, no_unused_fun/1, no_unused_fun2/1, + non_existing/1, not_guard_crash/1, or_bug/1, orelsebug/1, + orelsebug2/1, overloaded1/1, port_info_test/1, + process_info_test/1, pubsub/1, receive1/1, record_construct/1, + record_pat/1, record_send_test/1, record_test/1, + recursive_types1/1, recursive_types2/1, recursive_types3/1, + recursive_types4/1, recursive_types5/1, recursive_types6/1, + recursive_types7/1, refine_bug1/1, toth/1, trec/1, try1/1, + tuple1/1, unsafe_beamcode_bug/1, unused_cases/1, + unused_clauses/1, zero_tuple/1]). suite() -> [{timetrap, {minutes, 1}}]. @@ -51,10 +51,10 @@ all() -> atom_guard,atom_widen,bs_fail_constr,bs_utf8,cerl_hipeify,comm_layer, compare1,confusing_warning,contract2,contract3,contract5,disj_norm_form, eqeq,ets_select,exhaust_case,failing_guard1,flatten,fun_app,fun_ref_match, - fun_ref_record,gencall,gs_make,inf_loop2,letrec1,list_match,lzip, - make_tuple,minus_minus,mod_info,my_filter,my_sofs,no_match,no_unused_fun, - no_unused_fun2,non_existing,not_guard_crash,or_bug,orelsebug,orelsebug2, - overloaded1,port_info_test,process_info_test,pubsub,receive1, + fun_ref_record,gencall,gs_make,inf_loop2,invalid_specs,letrec1,list_match, + lzip,make_tuple,minus_minus,mod_info,my_filter,my_sofs,no_match, + no_unused_fun,no_unused_fun2,non_existing,not_guard_crash,or_bug,orelsebug, + orelsebug2,overloaded1,port_info_test,process_info_test,pubsub,receive1, record_construct,record_pat,record_send_test,record_test,recursive_types1, recursive_types2,recursive_types3,recursive_types4,recursive_types5, recursive_types6,recursive_types7,refine_bug1,toth,trec,try1,tuple1, @@ -235,6 +235,12 @@ inf_loop2(Config) -> Error -> ct:fail(Error) end. +invalid_specs(Config) -> + case dialyze(Config, invalid_specs) of + 'same' -> 'same'; + Error -> ct:fail(Error) + end. + letrec1(Config) -> case dialyze(Config, letrec1) of 'same' -> 'same'; diff --git a/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs b/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs new file mode 100644 index 0000000000..c95c0ff1f8 --- /dev/null +++ b/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs @@ -0,0 +1,3 @@ + +invalid_spec1.erl:5: Invalid type specification for function invalid_spec1:get_plan_dirty/1. The success typing is ([string()]) -> {maybe_improper_list(),[atom()]} +invalid_spec2.erl:5: Function foo/0 has no local return diff --git a/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl new file mode 100644 index 0000000000..06ab2f9a22 --- /dev/null +++ b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl @@ -0,0 +1,28 @@ +-module(invalid_spec1). + +-export([get_plan_dirty/1]). + +-spec get_plan_dirty([string()]) -> {{atom(), any()}, [atom()]}. + +get_plan_dirty(ClassL) -> + get_plan_dirty(ClassL, [], []). + +get_plan_dirty([], Res, FoundClassList) -> + {Res,FoundClassList}; +get_plan_dirty([Class|ClassL], Res, FoundClassList) -> + ClassPlan = list_to_atom(Class ++ "_plan"), + case catch mnesia:dirty_all_keys(ClassPlan) of + {'EXIT',_} -> + get_plan_dirty(ClassL, Res, FoundClassList); + [] -> + get_plan_dirty(ClassL, Res, FoundClassList); + KeyL -> + ClassAtom = list_to_atom(Class), + Res2 = + lists:foldl(fun(Key, Acc) -> + [{ClassAtom,Key}|Acc] + end, + Res, + KeyL), + get_plan_dirty(ClassL, Res2, [ClassAtom|FoundClassList]) + end. diff --git a/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl new file mode 100644 index 0000000000..e49f73d014 --- /dev/null +++ b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl @@ -0,0 +1,11 @@ +-module(invalid_spec2). + +-export([foo/0]). + +foo() -> + case + invalid_spec1:get_plan_dirty(mnesia:dirty_all_keys(cmClassInfo)) + of + {[],[]} -> foo; + { _, _} -> bar + end. -- cgit v1.2.3 From 890defc468ebd3e88464643e5a4cb46ef0ff2298 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Mon, 11 Apr 2011 19:52:52 +0200 Subject: dialyzer/doc: use consistent colons in type specs --- lib/dialyzer/doc/src/dialyzer.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index b6547b11e1..3a4f605b93 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -279,14 +279,14 @@

Dialyzer GUI version.

Date: Mon, 11 Apr 2011 20:15:54 +0200 Subject: dialyzer/doc: fix whitespace errors --- lib/dialyzer/doc/manual.txt | 22 +++++++++++----------- lib/dialyzer/doc/src/dialyzer.xml | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt index 1d7a1a6222..07897293a2 100644 --- a/lib/dialyzer/doc/manual.txt +++ b/lib/dialyzer/doc/manual.txt @@ -37,7 +37,7 @@ The parameters are: The analysis starts from .beam bytecode files. The files must be compiled with +debug_info. - Source code: - The analysis starts from .erl files. + The analysis starts from .erl files. Controlling the discrepancies reported by the Dialyzer ====================================================== @@ -131,7 +131,7 @@ Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] [--no_native] [--fullpath] -Options: +Options: files_or_dirs (for backwards compatibility also as: -c files_or_dirs) Use Dialyzer from the command line to detect defects in the specified files or directories containing .erl or .beam files, @@ -169,7 +169,7 @@ Options: --output_plt file Store the plt at the specified file after building it. --plt plt - Use the specified plt as the initial plt (if the plt was built + Use the specified plt as the initial plt (if the plt was built during setup the files will be checked for consistency). --plts plt* Merge the specified plts to create the initial plt -- requires @@ -204,8 +204,8 @@ Options: --add_to_plt The plt is extended to also include the files specified with -c and -r. Use --plt to specify which plt to start from, and --output_plt to - specify where to put the plt. Note that the analysis might include - files from the plt if they depend on the new files. + specify where to put the plt. Note that the analysis might include + files from the plt if they depend on the new files. This option only works with beam files. --remove_from_plt The information from the files specified with -c and -r is removed @@ -269,13 +269,13 @@ Warning options: Include warnings about behaviour callbacks which drift from the published recommended interfaces. -Wunderspecs *** - Warn about underspecified functions + Warn about underspecified functions (those whose -spec is strictly more allowing than the success typing). The following options are also available but their use is not recommended: (they are mostly for Dialyzer developers and internal debugging) -Woverspecs *** - Warn about overspecified functions + Warn about overspecified functions (those whose -spec is strictly less allowing than the success typing). -Wspecdiffs *** Warn when the -spec is different than the success typing. @@ -306,8 +306,8 @@ dialyzer:run(OptList) -> Warnings Warnings :: [{tag(), id(), msg()}] tag() :: 'warn_return_no_exit' | 'warn_return_only_exit' | 'warn_not_called' | 'warn_non_proper_list' | 'warn_fun_app' | 'warn_matching' - | 'warn_failing_call' | 'warn_contract_types' - | 'warn_contract_syntax' | 'warn_contract_not_equal' + | 'warn_failing_call' | 'warn_contract_types' + | 'warn_contract_syntax' | 'warn_contract_not_equal' | 'warn_contract_subtype' | 'warn_contract_supertype' id() :: {File :: string(), Line :: integer()} msg() :: Undefined @@ -319,7 +319,7 @@ Option :: {files, [Filename :: string()]} | {from, src_code | byte_code} %% Defaults to byte_code | {init_plt, FileName :: string()} %% If changed from default | {plts, [FileName :: string()]} %% If changed from default - | {include_dirs, [DirName :: string()]} + | {include_dirs, [DirName :: string()]} | {output_file, FileName :: string()} | {output_plt, FileName :: string()} | {analysis_type, 'succ_typings' | 'plt_add' | @@ -392,7 +392,7 @@ files that depend on these files. Note that this consistency check will be performed automatically the next time you run Dialyzer with this plt. The --check_plt option is merely for doing so without doing any other analysis. - + ----------------------------------------------- -- -- Feedback & bug reports diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index 3a4f605b93..7d8f9273d6 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -241,7 +241,7 @@ Include warnings about behaviour callbacks which drift from the published recommended interfaces. *** - Warn about underspecified functions + Warn about underspecified functions (the -spec is strictly more allowing than the success typing).

The following options are also available but their use is not @@ -249,7 +249,7 @@ debugging)

*** - Warn about overspecified functions + Warn about overspecified functions (the -spec is strictly less allowing than the success typing). *** Warn when the -spec is different than the success typing. -- cgit v1.2.3 From 8b852b4e67095d6a35fe662d5648facd887ae52b Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Mon, 11 Apr 2011 20:16:32 +0200 Subject: dialyzer/doc: synchronize manual.txt and dialyzer.xml --- lib/dialyzer/doc/manual.txt | 11 +++++-- lib/dialyzer/doc/src/dialyzer.xml | 66 +++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 35 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt index 07897293a2..d519ac960b 100644 --- a/lib/dialyzer/doc/manual.txt +++ b/lib/dialyzer/doc/manual.txt @@ -325,18 +325,25 @@ Option :: {files, [Filename :: string()]} | {analysis_type, 'succ_typings' | 'plt_add' | 'plt_build' | 'plt_check' | 'plt_remove'} | {warnings, [WarnOpts]} + | {get_warnings, bool()} WarnOpts :: no_return | no_unused | no_improper_lists | no_fun_app | no_match + | no_opaque | no_fail_call - | unmatched_returns | error_handling + | race_conditions + | behaviours + | unmatched_returns + | overspecs + | underspecs + | specdiffs dialyzer:format_warning({tag(), id(), msg()}) -> string() - + Returns a string representation of the warnings as returned by dialyzer:run/1. dialyzer:plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()} diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index 7d8f9273d6..4080dfdf77 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -278,34 +278,34 @@

Dialyzer GUI version.

@@ -320,12 +320,12 @@ WarnOpts : no_return

Dialyzer command line version.

-- cgit v1.2.3