aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl6
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl48
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl7
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl60
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl2
5 files changed, 91 insertions, 32 deletions
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 983f1ceefa..1f462c216b 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -352,9 +352,11 @@ compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts) ->
true ->
case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
{error, _} = Error -> Error;
- {ok, SpecInfo, _CallbackInfo} ->
+ {ok, SpecInfo, CallbackInfo} ->
CServer2 =
- dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo, CServer1),
+ dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
+ CallbackInfo,
+ CServer1),
store_core(Mod, Core, NoWarn, Callgraph, CServer2)
end;
false ->
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index b2097f7e53..e7d60f4cb0 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -28,10 +28,11 @@
-module(dialyzer_codeserver).
-export([delete/1,
- finalize_contracts/2,
+ finalize_contracts/3,
finalize_exported_types/2,
finalize_records/2,
get_contracts/1,
+ get_callbacks/1,
get_exported_types/1,
get_exports/1,
get_records/1,
@@ -54,7 +55,7 @@
store_records/3,
store_temp_records/3,
store_contracts/3,
- store_temp_contracts/3]).
+ store_temp_contracts/4]).
-export_type([codeserver/0]).
@@ -70,7 +71,10 @@
records = dict:new() :: dict(),
temp_records = dict:new() :: dict(),
contracts = dict:new() :: dict(),
- temp_contracts = dict:new() :: dict()}).
+ callbacks = dict:new() :: dict(),
+ temp_contracts = dict:new() :: dict(),
+ temp_callbacks = dict:new() :: dict()
+ }).
-opaque codeserver() :: #codeserver{}.
@@ -227,24 +231,42 @@ lookup_mfa_contract({M,_F,_A} = MFA, #codeserver{contracts = ContDict}) ->
get_contracts(#codeserver{contracts = ContDict}) ->
ContDict.
--spec store_temp_contracts(atom(), dict(), codeserver()) -> codeserver().
+-spec get_callbacks(codeserver()) -> dict().
-store_temp_contracts(Mod, Dict, #codeserver{temp_contracts = C} = CS)
+get_callbacks(#codeserver{callbacks = CallbDict}) ->
+ CallbDict.
+
+-spec store_temp_contracts(atom(), dict(), dict(), codeserver()) ->
+ codeserver().
+
+store_temp_contracts(Mod, SpecDict, CallbackDict,
+ #codeserver{temp_contracts = Cn,
+ temp_callbacks = Cb} = CS)
when is_atom(Mod) ->
- case dict:size(Dict) =:= 0 of
- true -> CS;
- false -> CS#codeserver{temp_contracts = dict:store(Mod, Dict, C)}
+ CS1 =
+ case dict:size(SpecDict) =:= 0 of
+ true -> CS;
+ false -> CS#codeserver{temp_contracts = dict:store(Mod, SpecDict, Cn)}
+ end,
+ case dict:size(CallbackDict) =:= 0 of
+ true -> CS1;
+ false -> CS1#codeserver{temp_callbacks = dict:store(Mod, CallbackDict, Cb)}
end.
-spec get_temp_contracts(codeserver()) -> dict().
-get_temp_contracts(#codeserver{temp_contracts = TempContDict}) ->
- TempContDict.
+get_temp_contracts(#codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict}) ->
+ {TempContDict, TempCallDict}.
--spec finalize_contracts(dict(), codeserver()) -> codeserver().
+-spec finalize_contracts(dict(), dict(), codeserver()) -> codeserver().
-finalize_contracts(Dict, CS) ->
- CS#codeserver{contracts = Dict, temp_contracts = dict:new()}.
+finalize_contracts(CnDict, CbDict, CS) ->
+ CS#codeserver{contracts = CnDict,
+ callbacks = CbDict,
+ temp_contracts = dict:new(),
+ temp_callbacks = dict:new()
+ }.
table__new() ->
spawn_link(fun() -> table__loop(none, dict:new()) end).
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index 84b926a17a..3469d70a4d 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -141,7 +141,8 @@ sequence([H|T], Delimiter) -> H ++ Delimiter ++ sequence(T, Delimiter).
dialyzer_codeserver:codeserver().
process_contract_remote_types(CodeServer) ->
- TmpContractDict = dialyzer_codeserver:get_temp_contracts(CodeServer),
+ {TmpContractDict, TmpCallbackDict} =
+ dialyzer_codeserver:get_temp_contracts(CodeServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer),
RecordDict = dialyzer_codeserver:get_records(CodeServer),
ContractFun =
@@ -155,7 +156,9 @@ process_contract_remote_types(CodeServer) ->
dict:map(ContractFun, ContractDict)
end,
NewContractDict = dict:map(ModuleFun, TmpContractDict),
- dialyzer_codeserver:finalize_contracts(NewContractDict, CodeServer).
+ NewCallbackDict = dict:map(ModuleFun, TmpCallbackDict),
+ dialyzer_codeserver:finalize_contracts(NewContractDict, NewCallbackDict,
+ CodeServer).
-spec check_contracts([{mfa(), file_contract()}],
dialyzer_callgraph:callgraph(), dict()) -> plt_contracts().
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 6033d7f17c..afa46564dd 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -43,6 +43,7 @@
%% insert/3,
insert_list/2,
insert_contract_list/2,
+ insert_callbacks/2,
insert_types/2,
insert_exported_types/2,
lookup/2,
@@ -79,6 +80,7 @@
-record(plt, {info = table_new() :: dict(),
types = table_new() :: dict(),
contracts = table_new() :: dict(),
+ callbacks = table_new() :: dict(),
exported_types = sets:new() :: set()}).
-opaque plt() :: #plt{}.
@@ -91,6 +93,7 @@
file_md5_list = [] :: [file_md5()],
info = dict:new() :: dict(),
contracts = dict:new() :: dict(),
+ callbacks = dict:new() :: dict(),
types = dict:new() :: dict(),
exported_types = sets:new() :: set(),
mod_deps :: mod_deps(),
@@ -105,20 +108,26 @@ new() ->
-spec delete_module(plt(), atom()) -> plt().
-delete_module(#plt{info = Info, types = Types, contracts = Contracts,
+delete_module(#plt{info = Info, types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
exported_types = ExpTypes}, Mod) ->
#plt{info = table_delete_module(Info, Mod),
types = table_delete_module2(Types, Mod),
contracts = table_delete_module(Contracts, Mod),
+ callbacks = table_delete_module(Callbacks, Mod),
exported_types = table_delete_module1(ExpTypes, Mod)}.
-spec delete_list(plt(), [mfa() | integer()]) -> plt().
-delete_list(#plt{info = Info, types = Types, contracts = Contracts,
+delete_list(#plt{info = Info, types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
exported_types = ExpTypes}, List) ->
#plt{info = table_delete_list(Info, List),
types = Types,
contracts = table_delete_list(Contracts, List),
+ callbacks = table_delete_list(Callbacks, List),
exported_types = ExpTypes}.
-spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt().
@@ -126,6 +135,17 @@ delete_list(#plt{info = Info, types = Types, contracts = Contracts,
insert_contract_list(#plt{contracts = Contracts} = PLT, List) ->
PLT#plt{contracts = table_insert_list(Contracts, List)}.
+-spec insert_callbacks(plt(), dialyzer_codeserver:codeserver()) -> plt().
+
+insert_callbacks(#plt{callbacks = Callbacks} = Plt, Codeserver) ->
+ FunPreferNew = fun(_Key, _Val1, Val2) -> Val2 end,
+ FunDictMerger =
+ fun(_Key, Value, AccIn) -> dict:merge(FunPreferNew, Value, AccIn) end,
+ MergedCallbacks = dict:fold(FunDictMerger, dict:new(),
+ dialyzer_codeserver:get_callbacks(Codeserver)),
+ List = dict:to_list(MergedCallbacks),
+ Plt#plt{callbacks = table_insert_list(Callbacks, List)}.
+
-spec lookup_contract(plt(), mfa_patt()) -> 'none' | {'value', #contract{}}.
lookup_contract(#plt{contracts = Contracts},
@@ -134,8 +154,10 @@ lookup_contract(#plt{contracts = Contracts},
-spec delete_contract_list(plt(), [mfa()]) -> plt().
-delete_contract_list(#plt{contracts = Contracts} = PLT, List) ->
- PLT#plt{contracts = table_delete_list(Contracts, List)}.
+delete_contract_list(#plt{contracts = Contracts,
+ callbacks = Callbacks} = PLT, List) ->
+ PLT#plt{contracts = table_delete_list(Contracts, List),
+ callbacks = table_delete_list(Callbacks, List)}.
%% -spec insert(plt(), mfa() | integer(), {_, _}) -> plt().
%%
@@ -230,6 +252,7 @@ from_file(FileName, ReturnInfo) ->
Plt = #plt{info = Rec#file_plt.info,
types = Rec#file_plt.types,
contracts = Rec#file_plt.contracts,
+ callbacks = Rec#file_plt.callbacks,
exported_types = Rec#file_plt.exported_types},
case ReturnInfo of
false -> Plt;
@@ -284,26 +307,34 @@ get_record_from_file(FileName) ->
-spec merge_plts([plt()]) -> plt().
merge_plts(List) ->
- InfoList = [Info || #plt{info = Info} <- List],
- TypesList = [Types || #plt{types = Types} <- List],
- ExpTypesList = [ExpTypes || #plt{exported_types = ExpTypes} <- List],
- ContractsList = [Contracts || #plt{contracts = Contracts} <- List],
+ {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList} =
+ group_fields(List),
#plt{info = table_merge(InfoList),
types = table_merge(TypesList),
exported_types = sets_merge(ExpTypesList),
- contracts = table_merge(ContractsList)}.
+ contracts = table_merge(ContractsList),
+ callbacks = table_merge(CallbacksList)
+ }.
-spec merge_disj_plts([plt()]) -> plt().
merge_disj_plts(List) ->
+ {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList} =
+ group_fields(List),
+ #plt{info = table_disj_merge(InfoList),
+ types = table_disj_merge(TypesList),
+ exported_types = sets_disj_merge(ExpTypesList),
+ contracts = table_disj_merge(ContractsList),
+ callbacks = table_disj_merge(CallbacksList)
+ }.
+
+group_fields(List) ->
InfoList = [Info || #plt{info = Info} <- List],
TypesList = [Types || #plt{types = Types} <- List],
ExpTypesList = [ExpTypes || #plt{exported_types = ExpTypes} <- List],
ContractsList = [Contracts || #plt{contracts = Contracts} <- List],
- #plt{info = table_disj_merge(InfoList),
- types = table_disj_merge(TypesList),
- exported_types = sets_disj_merge(ExpTypesList),
- contracts = table_disj_merge(ContractsList)}.
+ CallbacksList = [Callbacks || #plt{callbacks = Callbacks} <- List],
+ {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList}.
-spec merge_plts_or_report_conflicts([file:filename()], [plt()]) -> plt().
@@ -329,7 +360,7 @@ find_duplicates(List) ->
to_file(FileName,
#plt{info = Info, types = Types, contracts = Contracts,
- exported_types = ExpTypes},
+ callbacks = Callbacks, exported_types = ExpTypes},
ModDeps, {MD5, OldModDeps}) ->
NewModDeps = dict:merge(fun(_Key, OldVal, NewVal) ->
ordsets:union(OldVal, NewVal)
@@ -340,6 +371,7 @@ to_file(FileName,
file_md5_list = MD5,
info = Info,
contracts = Contracts,
+ callbacks = Callbacks,
types = Types,
exported_types = ExpTypes,
mod_deps = NewModDeps,
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index 5d24e0d0d6..45444ec6a3 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -78,7 +78,7 @@ analyze_callgraph(Callgraph, Plt, Codeserver, Parent) ->
State = #st{callgraph = Callgraph, plt = Plt,
codeserver = Codeserver, parent = Parent},
NewState = get_refined_success_typings(State),
- NewState#st.plt.
+ dialyzer_plt:insert_callbacks(NewState#st.plt, Codeserver).
%%--------------------------------------------------------------------