aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/src')
-rw-r--r--lib/dialyzer/src/dialyzer.app.src2
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl53
-rw-r--r--lib/dialyzer/src/dialyzer_callgraph.erl27
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl63
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl104
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl36
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl35
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,