From 191151eca1779da7ccc8244b5dca0891ebf5b62d Mon Sep 17 00:00:00 2001
From: Stavros Aronis <aronisstav@gmail.com>
Date: Tue, 8 Nov 2011 14:17:24 +0100
Subject: Store callbacks in codeserver and PLT

---
 lib/dialyzer/src/dialyzer_analysis_callgraph.erl |  6 ++-
 lib/dialyzer/src/dialyzer_codeserver.erl         | 48 ++++++++++++++-----
 lib/dialyzer/src/dialyzer_contracts.erl          |  7 ++-
 lib/dialyzer/src/dialyzer_plt.erl                | 60 ++++++++++++++++++------
 lib/dialyzer/src/dialyzer_succ_typings.erl       |  2 +-
 5 files changed, 91 insertions(+), 32 deletions(-)

(limited to 'lib')

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).
 
 %%--------------------------------------------------------------------
 
-- 
cgit v1.2.3