diff options
Diffstat (limited to 'lib/dialyzer/src')
-rw-r--r-- | lib/dialyzer/src/dialyzer.app.src | 2 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_analysis_callgraph.erl | 53 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_callgraph.erl | 27 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_cl.erl | 63 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_contracts.erl | 104 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_options.erl | 36 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_plt.erl | 2 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_utils.erl | 35 |
8 files changed, 163 insertions, 159 deletions
diff --git a/lib/dialyzer/src/dialyzer.app.src b/lib/dialyzer/src/dialyzer.app.src index 6718178fae..8ac6dc1367 100644 --- a/lib/dialyzer/src/dialyzer.app.src +++ b/lib/dialyzer/src/dialyzer.app.src @@ -47,5 +47,5 @@ {applications, [compiler, gs, hipe, kernel, stdlib, wx]}, {env, []}, {runtime_dependencies, ["wx-1.2","syntax_tools-1.6.14","stdlib-2.5", - "kernel-3.0","hipe-3.10.3","erts-7.0", + "kernel-3.0","hipe-3.13","erts-7.0", "compiler-5.0"]}]}. diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index 76b43b6ff0..8537878dfc 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -93,31 +93,19 @@ loop(#server_state{parent = Parent} = State, send_log(Parent, LogMsg), loop(State, Analysis, ExtCalls); {AnalPid, warnings, Warnings} -> - case Warnings of - [] -> ok; - SendWarnings -> - send_warnings(Parent, SendWarnings) - end, + send_warnings(Parent, Warnings), loop(State, Analysis, ExtCalls); {AnalPid, cserver, CServer, Plt} -> send_codeserver_plt(Parent, CServer, Plt), loop(State, Analysis, ExtCalls); {AnalPid, done, Plt, DocPlt} -> - case ExtCalls =:= none of - true -> - send_analysis_done(Parent, Plt, DocPlt); - false -> - send_ext_calls(Parent, ExtCalls), - send_analysis_done(Parent, Plt, DocPlt) - end; + send_ext_calls(Parent, ExtCalls), + send_analysis_done(Parent, Plt, DocPlt); {AnalPid, ext_calls, NewExtCalls} -> loop(State, Analysis, NewExtCalls); {AnalPid, ext_types, ExtTypes} -> send_ext_types(Parent, ExtTypes), loop(State, Analysis, ExtCalls); - {AnalPid, unknown_behaviours, UnknownBehaviour} -> - send_unknown_behaviours(Parent, UnknownBehaviour), - loop(State, Analysis, ExtCalls); {AnalPid, mod_deps, ModDeps} -> send_mod_deps(Parent, ModDeps), loop(State, Analysis, ExtCalls); @@ -167,9 +155,12 @@ analysis_start(Parent, Analysis, LegalWarnings) -> TmpCServer2 = dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes, TmpCServer1), - TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2), ?timing(State#analysis_state.timing_server, "remote", - dialyzer_contracts:process_contract_remote_types(TmpCServer3)) + begin + TmpCServer3 = + dialyzer_utils:process_record_remote_types(TmpCServer2), + dialyzer_contracts:process_contract_remote_types(TmpCServer3) + end) catch throw:{error, _ErrorMsg} = Error -> exit(Error) end, @@ -569,6 +560,8 @@ send_analysis_done(Parent, Plt, DocPlt) -> Parent ! {self(), done, Plt, DocPlt}, ok. +send_ext_calls(_Parent, none) -> + ok; send_ext_calls(Parent, ExtCalls) -> Parent ! {self(), ext_calls, ExtCalls}, ok. @@ -577,10 +570,6 @@ send_ext_types(Parent, ExtTypes) -> Parent ! {self(), ext_types, ExtTypes}, ok. -send_unknown_behaviours(Parent, UnknownBehaviours) -> - Parent ! {self(), unknown_behaviours, UnknownBehaviours}, - ok. - send_codeserver_plt(Parent, CServer, Plt ) -> Parent ! {self(), cserver, CServer, Plt}, ok. @@ -621,6 +610,28 @@ find_call_file_and_line(Tree, MFA) -> MFA -> Ann = cerl:get_ann(SubTree), [{get_file(Ann), get_line(Ann)}|Acc]; + {erlang, make_fun, 3} -> + [CA1, CA2, CA3] = cerl:call_args(SubTree), + case + cerl:is_c_atom(CA1) andalso + cerl:is_c_atom(CA2) andalso + cerl:is_c_int(CA3) + of + true -> + case + {cerl:concrete(CA1), + cerl:concrete(CA2), + cerl:concrete(CA3)} + of + MFA -> + Ann = cerl:get_ann(SubTree), + [{get_file(Ann), get_line(Ann)}|Acc]; + _ -> + Acc + end; + false -> + Acc + end; _ -> Acc end; false -> Acc diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl index a1cd2015ca..9e53e171c0 100644 --- a/lib/dialyzer/src/dialyzer_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_callgraph.erl @@ -478,14 +478,37 @@ scan_one_core_fun(TopTree, FunName) -> call -> CalleeM = cerl:call_module(Tree), CalleeF = cerl:call_name(Tree), - A = length(cerl:call_args(Tree)), + CalleeArgs = cerl:call_args(Tree), + A = length(CalleeArgs), case (cerl:is_c_atom(CalleeM) andalso cerl:is_c_atom(CalleeF)) of true -> M = cerl:atom_val(CalleeM), F = cerl:atom_val(CalleeF), case erl_bif_types:is_known(M, F, A) of - true -> Acc; + true -> + case {M, F, A} of + {erlang, make_fun, 3} -> + [CA1, CA2, CA3] = CalleeArgs, + case + cerl:is_c_atom(CA1) andalso + cerl:is_c_atom(CA2) andalso + cerl:is_c_int(CA3) + of + true -> + MM = cerl:atom_val(CA1), + FF = cerl:atom_val(CA2), + AA = cerl:int_val(CA3), + case erl_bif_types:is_known(MM, FF, AA) of + true -> Acc; + false -> [{FunName, {MM, FF, AA}}|Acc] + end; + false -> + Acc + end; + _ -> + Acc + end; false -> [{FunName, {M, F, A}}|Acc] end; false -> diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index 55302d5869..9354b8007e 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -49,8 +49,7 @@ plt_info = none :: 'none' | dialyzer_plt:plt_info(), report_mode = normal :: rep_mode(), return_status= ?RET_NOTHING_SUSPICIOUS :: dial_ret(), - stored_warnings = [] :: [raw_warning()], - unknown_behaviours = [] :: [dialyzer_behaviours:behaviour()] + stored_warnings = [] :: [raw_warning()] }). %%-------------------------------------------------------------------- @@ -547,13 +546,13 @@ hc(Mod, Cache) -> hc_cache(Mod) -> CacheBase = cache_base_dir(), - %% Use HiPE architecture and version in directory name, to avoid - %% clashes between incompatible binaries. + %% Use HiPE architecture, version and erts checksum in directory name, + %% to avoid clashes between incompatible binaries. HipeArchVersion = lists:concat( [erlang:system_info(hipe_architecture), "-", hipe:version(), "-", - hipe_bifs:system_crc()]), + hipe:erts_checksum()]), CacheDir = filename:join(CacheBase, HipeArchVersion), OrigBeamFile = code:which(Mod), {ok, {Mod, <<Checksum:128>>}} = beam_lib:md5(OrigBeamFile), @@ -638,9 +637,6 @@ cl_loop(State, LogCache) -> {BackendPid, warnings, Warnings} -> NewState = store_warnings(State, Warnings), cl_loop(NewState, LogCache); - {BackendPid, unknown_behaviours, Behaviours} -> - NewState = store_unknown_behaviours(State, Behaviours), - cl_loop(NewState, LogCache); {BackendPid, done, NewPlt, _NewDocPlt} -> return_value(State, NewPlt); {BackendPid, ext_calls, ExtCalls} -> @@ -683,11 +679,6 @@ format_log_cache(LogCache) -> store_warnings(#cl_state{stored_warnings = StoredWarnings} = St, Warnings) -> St#cl_state{stored_warnings = StoredWarnings ++ Warnings}. --spec store_unknown_behaviours(#cl_state{}, [dialyzer_behaviours:behaviour()]) -> #cl_state{}. - -store_unknown_behaviours(#cl_state{unknown_behaviours = Behs} = St, Beh) -> - St#cl_state{unknown_behaviours = Beh ++ Behs}. - -spec cl_error(string()) -> no_return(). cl_error(Msg) -> @@ -724,7 +715,6 @@ return_value(State = #cl_state{erlang_mode = ErlangMode, print_warnings(State), print_ext_calls(State), print_ext_types(State), - print_unknown_behaviours(State), maybe_close_output_file(State), {RetValue, []}; true -> @@ -737,8 +727,7 @@ unknown_warnings(State = #cl_state{legal_warnings = LegalWarnings}) -> Unknown = case ordsets:is_element(?WARN_UNKNOWN, LegalWarnings) of true -> unknown_functions(State) ++ - unknown_types(State) ++ - unknown_behaviours(State); + unknown_types(State); false -> [] end, WarningInfo = {_Filename = "", _Line = 0, _MorMFA = ''}, @@ -814,48 +803,6 @@ do_print_ext_types(Output, [{M,F,A}|T], Before) -> do_print_ext_types(_, [], _) -> ok. -unknown_behaviours(#cl_state{unknown_behaviours = DupBehaviours, - legal_warnings = LegalWarnings}) -> - case ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings) of - false -> []; - true -> - Behaviours = lists:usort(DupBehaviours), - [{unknown_behaviour, B} || B <- Behaviours] - end. - -%%print_unknown_behaviours(#cl_state{report_mode = quiet}) -> -%% ok; -print_unknown_behaviours(#cl_state{output = Output, - external_calls = Calls, - external_types = Types, - stored_warnings = Warnings, - unknown_behaviours = DupBehaviours, - legal_warnings = LegalWarnings, - output_format = Format}) -> - case ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings) - andalso DupBehaviours =/= [] of - false -> ok; - true -> - Behaviours = lists:usort(DupBehaviours), - case Warnings =:= [] andalso Calls =:= [] andalso Types =:= [] of - true -> io:nl(Output); %% Need to do a newline first - false -> ok - end, - {Prompt, Prefix} = - case Format of - formatted -> {"Unknown behaviours:\n"," "}; - raw -> {"%% Unknown behaviours:\n","%% "} - end, - io:put_chars(Output, Prompt), - do_print_unknown_behaviours(Output, Behaviours, Prefix) - end. - -do_print_unknown_behaviours(Output, [B|T], Before) -> - io:format(Output, "~s~p\n", [Before,B]), - do_print_unknown_behaviours(Output, T, Before); -do_print_unknown_behaviours(_, [], _) -> - ok. - print_warnings(#cl_state{stored_warnings = []}) -> ok; print_warnings(#cl_state{output = Output, diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index 0c29d524b5..7251de8b10 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -46,7 +46,7 @@ -type file_contract() :: {file_line(), #contract{}, Extra :: [_]}. --type plt_contracts() :: [{mfa(), #contract{}}]. % actually, an orddict() +-type plt_contracts() :: orddict:orddict(mfa(), #contract{}). %%----------------------------------------------------------------------- %% Internal record for contracts whose components have not been processed @@ -395,22 +395,21 @@ insert_constraints([], Dict) -> Dict. store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecDict, RecordsDict) -> %% io:format("contract from form: ~p\n", [TypeSpec]), - {Module, _, _} = MFA, - TmpContract = contract_from_form(TypeSpec, Module, RecordsDict, FileLine), + TmpContract = contract_from_form(TypeSpec, MFA, RecordsDict, FileLine), %% io:format("contract: ~p\n", [TmpContract]), dict:store(MFA, {FileLine, TmpContract, Xtra}, SpecDict). -contract_from_form(Forms, Module, RecDict, FileLine) -> - {CFuns, Forms1} = contract_from_form(Forms, Module, RecDict, FileLine, [], []), +contract_from_form(Forms, MFA, RecDict, FileLine) -> + {CFuns, Forms1} = contract_from_form(Forms, MFA, RecDict, FileLine, [], []), #tmp_contract{contract_funs = CFuns, forms = Forms1}. -contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], Module, RecDict, +contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], MFA, RecDict, FileLine, TypeAcc, FormAcc) -> TypeFun = fun(ExpTypes, AllRecords) -> NewType = try - from_form_with_check(Form, ExpTypes, Module, AllRecords) + from_form_with_check(Form, ExpTypes, MFA, AllRecords) catch throw:{error, Msg} -> {File, Line} = FileLine, @@ -423,55 +422,55 @@ contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], Module, RecDict, end, NewTypeAcc = [TypeFun | TypeAcc], NewFormAcc = [{Form, []} | FormAcc], - contract_from_form(Left, Module, RecDict, FileLine, NewTypeAcc, NewFormAcc); + contract_from_form(Left, MFA, RecDict, FileLine, NewTypeAcc, NewFormAcc); contract_from_form([{type, _L1, bounded_fun, [{type, _L2, 'fun', [_, _]} = Form, Constr]}| Left], - Module, RecDict, FileLine, TypeAcc, FormAcc) -> + MFA, RecDict, FileLine, TypeAcc, FormAcc) -> TypeFun = fun(ExpTypes, AllRecords) -> {Constr1, VarDict} = - process_constraints(Constr, Module, RecDict, ExpTypes, AllRecords), - NewType = from_form_with_check(Form, ExpTypes, Module, AllRecords, + process_constraints(Constr, MFA, RecDict, ExpTypes, AllRecords), + NewType = from_form_with_check(Form, ExpTypes, MFA, AllRecords, VarDict), NewTypeNoVars = erl_types:subst_all_vars_to_any(NewType), {NewTypeNoVars, Constr1} end, NewTypeAcc = [TypeFun | TypeAcc], NewFormAcc = [{Form, Constr} | FormAcc], - contract_from_form(Left, Module, RecDict, FileLine, NewTypeAcc, NewFormAcc); -contract_from_form([], _Module, _RecDict, _FileLine, TypeAcc, FormAcc) -> + contract_from_form(Left, MFA, RecDict, FileLine, NewTypeAcc, NewFormAcc); +contract_from_form([], _MFA, _RecDict, _FileLine, TypeAcc, FormAcc) -> {lists:reverse(TypeAcc), lists:reverse(FormAcc)}. -process_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords) -> - Init0 = initialize_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords), +process_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords) -> + Init0 = initialize_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords), Init = remove_cycles(Init0), - constraints_fixpoint(Init, Module, RecDict, ExpTypes, AllRecords). + constraints_fixpoint(Init, MFA, RecDict, ExpTypes, AllRecords). -initialize_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords) -> - initialize_constraints(Constrs, Module, RecDict, ExpTypes, AllRecords, []). +initialize_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords) -> + initialize_constraints(Constrs, MFA, RecDict, ExpTypes, AllRecords, []). -initialize_constraints([], _Module, _RecDict, _ExpTypes, _AllRecords, Acc) -> +initialize_constraints([], _MFA, _RecDict, _ExpTypes, _AllRecords, Acc) -> Acc; -initialize_constraints([Constr|Rest], Module, RecDict, ExpTypes, AllRecords, Acc) -> +initialize_constraints([Constr|Rest], MFA, RecDict, ExpTypes, AllRecords, Acc) -> case Constr of {type, _, constraint, [{atom, _, is_subtype}, [Type1, Type2]]} -> - T1 = final_form(Type1, ExpTypes, Module, AllRecords, dict:new()), + T1 = final_form(Type1, ExpTypes, MFA, AllRecords, dict:new()), Entry = {T1, Type2}, - initialize_constraints(Rest, Module, RecDict, ExpTypes, AllRecords, [Entry|Acc]); + initialize_constraints(Rest, MFA, RecDict, ExpTypes, AllRecords, [Entry|Acc]); {type, _, constraint, [{atom,_,Name}, List]} -> N = length(List), throw({error, io_lib:format("Unsupported type guard ~w/~w\n", [Name, N])}) end. -constraints_fixpoint(Constrs, Module, RecDict, ExpTypes, AllRecords) -> +constraints_fixpoint(Constrs, MFA, RecDict, ExpTypes, AllRecords) -> VarDict = - constraints_to_dict(Constrs, Module, RecDict, ExpTypes, AllRecords, dict:new()), - constraints_fixpoint(VarDict, Module, Constrs, RecDict, ExpTypes, AllRecords). + constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, AllRecords, dict:new()), + constraints_fixpoint(VarDict, MFA, Constrs, RecDict, ExpTypes, AllRecords). -constraints_fixpoint(OldVarDict, Module, Constrs, RecDict, ExpTypes, AllRecords) -> +constraints_fixpoint(OldVarDict, MFA, Constrs, RecDict, ExpTypes, AllRecords) -> NewVarDict = - constraints_to_dict(Constrs, Module, RecDict, ExpTypes, AllRecords, OldVarDict), + constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, AllRecords, OldVarDict), case NewVarDict of OldVarDict -> DictFold = @@ -481,33 +480,33 @@ constraints_fixpoint(OldVarDict, Module, Constrs, RecDict, ExpTypes, AllRecords) FinalConstrs = dict:fold(DictFold, [], NewVarDict), {FinalConstrs, NewVarDict}; _Other -> - constraints_fixpoint(NewVarDict, Module, Constrs, RecDict, ExpTypes, AllRecords) + constraints_fixpoint(NewVarDict, MFA, Constrs, RecDict, ExpTypes, AllRecords) end. -final_form(Form, ExpTypes, Module, AllRecords, VarDict) -> - from_form_with_check(Form, ExpTypes, Module, AllRecords, VarDict). +final_form(Form, ExpTypes, MFA, AllRecords, VarDict) -> + from_form_with_check(Form, ExpTypes, MFA, AllRecords, VarDict). -from_form_with_check(Form, ExpTypes, Module, AllRecords) -> - erl_types:t_check_record_fields(Form, ExpTypes, Module, AllRecords), - erl_types:t_from_form(Form, ExpTypes, Module, AllRecords). +from_form_with_check(Form, ExpTypes, MFA, AllRecords) -> + from_form_with_check(Form, ExpTypes, MFA, AllRecords, dict:new()). -from_form_with_check(Form, ExpTypes, Module, AllRecords, VarDict) -> - erl_types:t_check_record_fields(Form, ExpTypes, Module, AllRecords, +from_form_with_check(Form, ExpTypes, MFA, AllRecords, VarDict) -> + Site = {spec, MFA}, + erl_types:t_check_record_fields(Form, ExpTypes, Site, AllRecords, VarDict), - erl_types:t_from_form(Form, ExpTypes, Module, AllRecords, VarDict). + erl_types:t_from_form(Form, ExpTypes, Site, AllRecords, VarDict). -constraints_to_dict(Constrs, Module, RecDict, ExpTypes, AllRecords, VarDict) -> +constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, AllRecords, VarDict) -> Subtypes = - constraints_to_subs(Constrs, Module, RecDict, ExpTypes, AllRecords, VarDict, []), + constraints_to_subs(Constrs, MFA, RecDict, ExpTypes, AllRecords, VarDict, []), insert_constraints(Subtypes, dict:new()). -constraints_to_subs([], _Module, _RecDict, _ExpTypes, _AllRecords, _VarDict, Acc) -> +constraints_to_subs([], _MFA, _RecDict, _ExpTypes, _AllRecords, _VarDict, Acc) -> Acc; -constraints_to_subs([C|Rest], Module, RecDict, ExpTypes, AllRecords, VarDict, Acc) -> +constraints_to_subs([C|Rest], MFA, RecDict, ExpTypes, AllRecords, VarDict, Acc) -> {T1, Form2} = C, - T2 = final_form(Form2, ExpTypes, Module, AllRecords, VarDict), + T2 = final_form(Form2, ExpTypes, MFA, AllRecords, VarDict), NewAcc = [{subtype, T1, T2}|Acc], - constraints_to_subs(Rest, Module, RecDict, ExpTypes, AllRecords, VarDict, NewAcc). + constraints_to_subs(Rest, MFA, RecDict, ExpTypes, AllRecords, VarDict, NewAcc). %% Replaces variables with '_' when necessary to break up cycles among %% the constraints. @@ -630,7 +629,7 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left], {error, {extra_range, ExtraRanges, STRange}} -> Warn = case t_from_forms_without_remote(Contract#contract.forms, - RecDict) of + MFA, RecDict) of {ok, NoRemoteType} -> CRet = erl_types:t_fun_range(NoRemoteType), erl_types:t_is_subtype(ExtraRanges, CRet); @@ -705,7 +704,7 @@ picky_contract_check(CSig0, Sig0, MFA, WarningInfo, Contract, RecDict, Acc) -> end end. -extra_contract_warning({M, F, A}, WarningInfo, Contract, CSig, Sig, RecDict) -> +extra_contract_warning(MFA, WarningInfo, Contract, CSig, Sig, RecDict) -> %% We do not want to depend upon erl_types:t_to_string() possibly %% hiding the contents of opaque types. SigUnopaque = erl_types:t_unopaque(Sig), @@ -717,11 +716,12 @@ extra_contract_warning({M, F, A}, WarningInfo, Contract, CSig, Sig, RecDict) -> %% The only difference is in record fields containing 'undefined' or not. IsUndefRecordFieldsRelated = SigString0 =:= ContractString0, {IsRemoteTypesRelated, SubtypeRelation} = - is_remote_types_related(Contract, CSig, Sig, RecDict), + is_remote_types_related(Contract, CSig, Sig, MFA, RecDict), case IsUndefRecordFieldsRelated orelse IsRemoteTypesRelated of true -> no_warning; false -> + {M, F, A} = MFA, SigString = lists:flatten(dialyzer_utils:format_sig(Sig, RecDict)), ContractString = contract_to_string(Contract), {Tag, Msg} = @@ -739,14 +739,15 @@ extra_contract_warning({M, F, A}, WarningInfo, Contract, CSig, Sig, RecDict) -> {warning, {Tag, WarningInfo, Msg}} end. -is_remote_types_related(Contract, CSig, Sig, RecDict) -> +is_remote_types_related(Contract, CSig, Sig, MFA, RecDict) -> case erl_types:t_is_subtype(CSig, Sig) of true -> {false, contract_is_subtype}; false -> case erl_types:t_is_subtype(Sig, CSig) of true -> - case t_from_forms_without_remote(Contract#contract.forms, RecDict) of + case t_from_forms_without_remote(Contract#contract.forms, MFA, + RecDict) of {ok, NoRemoteTypeSig} -> case blame_remote(CSig, NoRemoteTypeSig, Sig) of true -> @@ -762,13 +763,14 @@ is_remote_types_related(Contract, CSig, Sig, RecDict) -> end end. -t_from_forms_without_remote([{FType, []}], RecDict) -> - Type1 = erl_types:t_from_form_without_remote(FType, RecDict), +t_from_forms_without_remote([{FType, []}], MFA, RecDict) -> + Site = {spec, MFA}, + Type1 = erl_types:t_from_form_without_remote(FType, Site, RecDict), {ok, erl_types:subst_all_vars_to_any(Type1)}; -t_from_forms_without_remote([{_FType, _Constrs}], _RecDict) -> +t_from_forms_without_remote([{_FType, _Constrs}], _MFA, _RecDict) -> %% 'When' constraints unsupported; -t_from_forms_without_remote(_Forms, _RecDict) -> +t_from_forms_without_remote(_Forms, _MFA, _RecDict) -> %% Lots of forms unsupported. diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index ce84c17f43..dd81dd01ed 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -72,9 +72,15 @@ preprocess_opts([Opt|Opts]) -> [Opt|preprocess_opts(Opts)]. postprocess_opts(Opts = #options{}) -> + check_file_existence(Opts), Opts1 = check_output_plt(Opts), adapt_get_warnings(Opts1). +check_file_existence(#options{analysis_type = plt_remove}) -> ok; +check_file_existence(#options{files = Files, files_rec = FilesRec}) -> + assert_filenames_exist(Files), + assert_filenames_exist(FilesRec). + check_output_plt(Opts = #options{analysis_type = Mode, from = From, output_plt = OutPLT}) -> case is_plt_mode(Mode) of @@ -126,14 +132,14 @@ build_options([{OptionName, Value} = Term|Rest], Options) -> apps -> OldValues = Options#options.files_rec, AppDirs = get_app_dirs(Value), - assert_filenames(Term, AppDirs), + assert_filenames_form(Term, AppDirs), build_options(Rest, Options#options{files_rec = AppDirs ++ OldValues}); files -> - assert_filenames(Term, Value), + assert_filenames_form(Term, Value), build_options(Rest, Options#options{files = Value}); files_rec -> OldValues = Options#options.files_rec, - assert_filenames(Term, Value), + assert_filenames_form(Term, Value), build_options(Rest, Options#options{files_rec = Value ++ OldValues}); analysis_type -> NewOptions = @@ -210,16 +216,26 @@ get_app_dirs(Apps) when is_list(Apps) -> get_app_dirs(Apps) -> bad_option("Use a list of otp applications", Apps). -assert_filenames(Term, [FileName|Left]) when length(FileName) >= 0 -> +assert_filenames(Term, Files) -> + assert_filenames_form(Term, Files), + assert_filenames_exist(Files). + +assert_filenames_form(Term, [FileName|Left]) when length(FileName) >= 0 -> + assert_filenames_form(Term, Left); +assert_filenames_form(_Term, []) -> + ok; +assert_filenames_form(Term, [_|_]) -> + bad_option("Malformed or non-existing filename", Term). + +assert_filenames_exist([FileName|Left]) -> case filelib:is_file(FileName) orelse filelib:is_dir(FileName) of true -> ok; - false -> bad_option("No such file, directory or application", FileName) + false -> + bad_option("No such file, directory or application", FileName) end, - assert_filenames(Term, Left); -assert_filenames(_Term, []) -> - ok; -assert_filenames(Term, [_|_]) -> - bad_option("Malformed or non-existing filename", Term). + assert_filenames_exist(Left); +assert_filenames_exist([]) -> + ok. assert_filename(FileName) when length(FileName) >= 0 -> ok; diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 634871b2eb..769f26a3df 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -137,7 +137,7 @@ delete_list(#plt{info = Info, types = Types, #plt{info = table_delete_list(Info, List), types = Types, contracts = table_delete_list(Contracts, List), - callbacks = table_delete_list(Callbacks, List), + callbacks = Callbacks, exported_types = ExpTypes}. -spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt(). diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index b585646fde..7fe982a992 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -304,15 +304,16 @@ process_record_remote_types(CServer) -> RecordFun = fun(Key, Value) -> case Key of - {record, _Name} -> + {record, Name} -> FieldFun = - fun(_Arity, Fields) -> - [{Name, Field, + fun(Arity, Fields) -> + Site = {record, {Module, Name, Arity}}, + [{FieldName, Field, erl_types:t_from_form(Field, TempExpTypes, - Module, + Site, TempRecords1)} - || {Name, Field, _} <- Fields] + || {FieldName, Field, _} <- Fields] end, {FileLine, Fields} = Value, {FileLine, orddict:map(FieldFun, Fields)}; @@ -340,9 +341,10 @@ process_opaque_types(TempRecords, TempExpTypes) -> RecordFun = fun(Key, Value) -> case Key of - {opaque, _Name, _NArgs} -> + {opaque, Name, NArgs} -> {{_Module, _FileLine, Form, _ArgNames}=F, _Type} = Value, - Type = erl_types:t_from_form(Form, TempExpTypes, Module, + Site = {type, {Module, Name, NArgs}}, + Type = erl_types:t_from_form(Form, TempExpTypes, Site, TempRecords), {F, Type}; _Other -> Value @@ -355,25 +357,28 @@ process_opaque_types(TempRecords, TempExpTypes) -> check_record_fields(Records, TempExpTypes) -> CheckFun = fun({Module, Element}) -> - CheckForm = fun(F) -> - erl_types:t_check_record_fields(F, TempExpTypes, - Module, Records) + CheckForm = fun(Form, Site) -> + erl_types:t_check_record_fields(Form, TempExpTypes, + Site, Records) end, ElemFun = fun({Key, Value}) -> case Key of - {record, _Name} -> + {record, Name} -> FieldFun = - fun({_Arity, Fields}) -> - _ = [ok = CheckForm(Field) || {_, Field, _} <- Fields], + fun({Arity, Fields}) -> + Site = {record, {Module, Name, Arity}}, + _ = [ok = CheckForm(Field, Site) || + {_, Field, _} <- Fields], ok end, {FileLine, Fields} = Value, Fun = fun() -> lists:foreach(FieldFun, Fields) end, msg_with_position(Fun, FileLine); - {_OpaqueOrType, _Name, _} -> + {_OpaqueOrType, Name, NArgs} -> + Site = {type, {Module, Name, NArgs}}, {{_Module, FileLine, Form, _ArgNames}, _Type} = Value, - Fun = fun() -> ok = CheckForm(Form) end, + Fun = fun() -> ok = CheckForm(Form, Site) end, msg_with_position(Fun, FileLine) end end, |