diff options
Diffstat (limited to 'lib/dialyzer')
-rw-r--r-- | lib/dialyzer/src/dialyzer_behaviours.erl | 5 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_plt.erl | 48 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_succ_typings.erl | 41 |
3 files changed, 47 insertions, 47 deletions
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl index 127e906135..f86cc3d3d6 100644 --- a/lib/dialyzer/src/dialyzer_behaviours.erl +++ b/lib/dialyzer/src/dialyzer_behaviours.erl @@ -92,8 +92,9 @@ get_warnings(Module, [Behaviour|Rest], State, Acc) -> check_behaviour(Module, Behaviour, #state{plt = Plt} = State, Acc) -> case dialyzer_plt:lookup_callbacks(Plt, Behaviour) of - [] -> [{callback_info_missing, [Behaviour]}|Acc]; - Callbacks -> check_all_callbacks(Module, Behaviour, Callbacks, State, Acc) + none -> [{callback_info_missing, [Behaviour]}|Acc]; + {value, Callbacks} -> + check_all_callbacks(Module, Behaviour, Callbacks, State, Acc) end. check_all_callbacks(_Module, _Behaviour, [], _State, Acc) -> diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl index 0c0773e977..35bee913c2 100644 --- a/lib/dialyzer/src/dialyzer_plt.erl +++ b/lib/dialyzer/src/dialyzer_plt.erl @@ -87,7 +87,8 @@ exported_types = sets:new() :: set()}). -record(mini_plt, {info :: ets:tid(), - contracts :: ets:tid() + contracts :: ets:tid(), + callbacks :: ets:tid() }). -opaque plt() :: #plt{} | #mini_plt{}. @@ -140,8 +141,6 @@ delete_list(#plt{info = Info, types = Types, -spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt(). -insert_contract_list(#plt{contracts = Contracts} = PLT, List) -> - PLT#plt{contracts = table_insert_list(Contracts, List)}; insert_contract_list(#mini_plt{contracts = Contracts} = PLT, List) -> true = ets:insert(Contracts, List), PLT. @@ -154,9 +153,6 @@ insert_callbacks(#plt{callbacks = Callbacks} = Plt, Codeserver) -> -spec lookup_contract(plt(), mfa_patt()) -> 'none' | {'value', #contract{}}. -lookup_contract(#plt{contracts = Contracts}, - {M, F, _} = MFA) when is_atom(M), is_atom(F) -> - table_lookup(Contracts, MFA); lookup_contract(#mini_plt{contracts = ETSContracts}, {M, F, _} = MFA) when is_atom(M), is_atom(F) -> ets_table_lookup(ETSContracts, MFA). @@ -164,15 +160,13 @@ lookup_contract(#mini_plt{contracts = ETSContracts}, -spec lookup_callbacks(plt(), module()) -> [{mfa(), {{Filename::string(), Line::pos_integer()}, #contract{}}}]. -lookup_callbacks(#plt{callbacks = Callbacks}, Mod) when is_atom(Mod) -> - table_filter_module(Callbacks, Mod). +lookup_callbacks(#mini_plt{callbacks = ETSCallbacks}, Mod) when is_atom(Mod) -> + ets_table_lookup(ETSCallbacks, Mod). -type ret_args_types() :: {erl_types:erl_type(), [erl_types:erl_type()]}. -spec insert_list(plt(), [{mfa() | integer(), ret_args_types()}]) -> plt(). -insert_list(#plt{info = Info} = PLT, List) -> - PLT#plt{info = table_insert_list(Info, List)}; insert_list(#mini_plt{info = Info} = PLT, List) -> true = ets:insert(Info, List), PLT. @@ -185,8 +179,6 @@ lookup(Plt, {M, F, _} = MFA) when is_atom(M), is_atom(F) -> lookup(Plt, Label) when is_integer(Label) -> lookup_1(Plt, Label). -lookup_1(#plt{info = Info}, MFAorLabel) -> - table_lookup(Info, MFAorLabel); lookup_1(#mini_plt{info = Info}, MFAorLabel) -> ets_table_lookup(Info, MFAorLabel). @@ -517,12 +509,20 @@ init_md5_list_1(Md5List, [], Acc) -> -spec get_mini_plt(plt()) -> plt(). -get_mini_plt(#plt{info = Info, contracts = Contracts}) -> - ETSInfo = ets:new(plt_info, [public]), - ETSContracts = ets:new(plt_contracts, [public]), - true = ets:insert(ETSInfo, dict:to_list(Info)), - true = ets:insert(ETSContracts, dict:to_list(Contracts)), - #mini_plt{info = ETSInfo, contracts = ETSContracts}. +get_mini_plt(#plt{info = Info, contracts = Contracts, callbacks = Callbacks}) -> + [ETSInfo, ETSContracts, ETSCallbacks] = + [ets:new(Name, [public]) || Name <- [plt_info, plt_contracts, plt_callbacks]], + CallbackList = dict:to_list(Callbacks), + CallbacksByModule = + [{M, [Cb || {{M1,_,_},_} = Cb <- CallbackList, M1 =:= M]} || + M <- lists:usort([M || {{M,_,_},_} <- CallbackList])], + [true, true] = + [ets:insert(ETS, dict:to_list(Data)) || + {ETS, Data} <- [{ETSInfo, Info}, {ETSContracts, Contracts}]], + true = ets:insert(ETSCallbacks, CallbacksByModule), + #mini_plt{info = ETSInfo, contracts = ETSContracts, callbacks = ETSCallbacks}; +get_mini_plt(undefined) -> + undefined. -spec restore_full_plt(plt(), plt()) -> plt(). @@ -531,7 +531,9 @@ restore_full_plt(#mini_plt{info = ETSInfo, contracts = ETSContracts}, Plt) -> Contracts = dict:from_list(ets:tab2list(ETSContracts)), ets:delete(ETSContracts), ets:delete(ETSInfo), - Plt#plt{info = Info, contracts = Contracts}. + Plt#plt{info = Info, contracts = Contracts}; +restore_full_plt(undefined, undefined) -> + undefined. %%--------------------------------------------------------------------------- %% Edoc @@ -645,14 +647,6 @@ table_lookup_module(Plt, Mod) -> false -> {value, List} end. -table_filter_module(Plt, Mod) -> - FunModFilter = - fun({M, _F, _A}, _Val) -> M =:= Mod; - ( _Key, _Val) -> false - end, - ModCallbacks = dict:filter(FunModFilter, Plt), - dict:to_list(ModCallbacks). - table_all_modules(Plt) -> Fold = fun({M, _F, _A}, _Val, Acc) -> sets:add_element(M, Acc); diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index 38f3d47353..4d813e06bb 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -126,13 +126,16 @@ get_refined_success_typings(SCCs, State) -> get_warnings(Callgraph, Plt, DocPlt, Codeserver, NoWarnUnused, Parent) -> InitState = init_state_and_get_success_typings(Callgraph, Plt, Codeserver, Parent), - NewState = - InitState#st{no_warn_unused = NoWarnUnused, - plt = dialyzer_plt:restore_full_plt(InitState#st.plt, Plt)}, + NewState = InitState#st{no_warn_unused = NoWarnUnused}, Mods = dialyzer_callgraph:modules(NewState#st.callgraph), CWarns = dialyzer_contracts:get_invalid_contract_warnings(Mods, Codeserver, NewState#st.plt), - get_warnings_from_modules(Mods, NewState, DocPlt, CWarns). + MiniDocPlt = dialyzer_plt:get_mini_plt(DocPlt), + {Warnings, FinalPlt, FinalDocPlt} = + get_warnings_from_modules(Mods, NewState, MiniDocPlt, CWarns), + {postprocess_warnings(Warnings, Codeserver), + dialyzer_plt:restore_full_plt(FinalPlt, Plt), + dialyzer_plt:restore_full_plt(FinalDocPlt, DocPlt)}. get_warnings_from_modules([M|Ms], State, DocPlt, Acc) when is_atom(M) -> send_log(State#st.parent, io_lib:format("Getting warnings for ~w\n", [M])), @@ -145,25 +148,29 @@ get_warnings_from_modules([M|Ms], State, DocPlt, Acc) when is_atom(M) -> %% Check if there are contracts for functions that do not exist Warnings1 = dialyzer_contracts:contracts_without_fun(Contracts, AllFuns, Callgraph), - {RawWarnings2, FunTypes} = + {Warnings2, FunTypes} = dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Records, NoWarnUnused), - {NewAcc, Warnings2} = postprocess_dataflow_warns(RawWarnings2, State, Acc), Attrs = cerl:module_attrs(ModCode), Warnings3 = dialyzer_behaviours:check_callbacks(M, Attrs, Plt, Codeserver), NewDocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt), get_warnings_from_modules(Ms, State, NewDocPlt, - [Warnings1, Warnings2, Warnings3|NewAcc]); + [Warnings1, Warnings2, Warnings3|Acc]); 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_warnings(RawWarnings, Codeserver) -> + Pred = + fun({?WARN_CONTRACT_RANGE, _, _}) -> true; + (_) -> false + end, + {CRWarns, NonCRWarns} = lists:partition(Pred, RawWarnings), + postprocess_dataflow_warns(CRWarns, Codeserver, NonCRWarns, []). -postprocess_dataflow_warns([], _State, WAcc, Acc) -> - {WAcc, lists:reverse(Acc)}; +postprocess_dataflow_warns([], _Callgraph, WAcc, Acc) -> + lists:reverse(Acc, WAcc); postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest], - #st{codeserver = Codeserver} = State, WAcc, Acc) -> + Codeserver, WAcc, Acc) -> {contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg, case dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver) of {ok, {{ContrF, _ContrL} = FileLine, _C}} -> @@ -176,19 +183,17 @@ postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest], (_) -> true end, FilterWAcc = lists:filter(Filter, WAcc), - postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]); + postprocess_dataflow_warns(Rest, Codeserver, FilterWAcc, [W|Acc]); false -> - postprocess_dataflow_warns(Rest, State, WAcc, Acc) + postprocess_dataflow_warns(Rest, Codeserver, WAcc, Acc) end; error -> %% The contract is not in a module that is currently under analysis. %% We display the warning in the file/line of the call. NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, W = {?WARN_CONTRACT_RANGE, {CallF, CallL}, NewMsg}, - postprocess_dataflow_warns(Rest, State, WAcc, [W|Acc]) - end; -postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) -> - postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]). + postprocess_dataflow_warns(Rest, Codeserver, WAcc, [W|Acc]) + end. refine_succ_typings(ModulePostorder, #st{codeserver = Codeserver, callgraph = Callgraph, |