aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStavros Aronis <aronisstav@gmail.com>2011-10-28 18:38:35 +0200
committerStavros Aronis <aronisstav@gmail.com>2011-11-18 14:42:56 +0100
commit93aa83a1646e0b8e69dea1d8aad13bb3a9b73de9 (patch)
treeaad79f91138fc7fd0f603c40f7469a19d9b1fe88
parent0472f66e548ff5870b6446ddc91d704c5ff954d1 (diff)
downloadotp-93aa83a1646e0b8e69dea1d8aad13bb3a9b73de9.tar.gz
otp-93aa83a1646e0b8e69dea1d8aad13bb3a9b73de9.tar.bz2
otp-93aa83a1646e0b8e69dea1d8aad13bb3a9b73de9.zip
Collect callback definitions during compilation
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl77
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl49
3 files changed, 62 insertions, 66 deletions
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index abad1f3a75..983f1ceefa 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -325,63 +325,40 @@ compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts) ->
case dialyzer_utils:get_abstract_code_from_src(File, CompOpts) of
{error, _Msg} = Error -> Error;
{ok, AbstrCode} ->
- case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of
- error -> {error, " Could not find abstract code for: " ++ File};
- {ok, Core} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- NoWarn = abs_get_nowarn(AbstrCode, Mod),
- case dialyzer_utils:get_record_and_type_info(AbstrCode) of
- {error, _} = Error -> Error;
- {ok, RecInfo} ->
- CServer2 =
- dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
- case UseContracts of
- true ->
- case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
- {error, _} = Error -> Error;
- {ok, SpecInfo} ->
- CServer3 =
- dialyzer_codeserver:store_temp_contracts(Mod,
- SpecInfo,
- CServer2),
- store_core(Mod, Core, NoWarn, Callgraph, CServer3)
- end;
- false ->
- store_core(Mod, Core, NoWarn, Callgraph, CServer2)
- end
- end
- end
+ compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts)
end.
compile_byte(File, Callgraph, CServer, UseContracts) ->
case dialyzer_utils:get_abstract_code_from_beam(File) of
error ->
{error, " Could not get abstract code for: " ++ File ++ "\n" ++
- " Recompile with +debug_info or analyze starting from source code"};
+ " Recompile with +debug_info or analyze starting from source code"};
{ok, AbstrCode} ->
- case dialyzer_utils:get_core_from_abstract_code(AbstrCode) of
- error -> {error, " Could not get core for: "++File};
- {ok, Core} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- NoWarn = abs_get_nowarn(AbstrCode, Mod),
- case dialyzer_utils:get_record_and_type_info(AbstrCode) of
- {error, _} = Error -> Error;
- {ok, RecInfo} ->
- CServer1 =
- dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
- case UseContracts of
- true ->
- case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
- {error, _} = Error -> Error;
- {ok, SpecInfo} ->
- CServer2 =
- dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
- CServer1),
- store_core(Mod, Core, NoWarn, Callgraph, CServer2)
- end;
- false ->
- store_core(Mod, Core, NoWarn, Callgraph, CServer1)
- end
+ compile_common(File, AbstrCode, [], Callgraph, CServer, UseContracts)
+ end.
+
+compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts) ->
+ case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of
+ error -> {error, " Could not get core Erlang code for: " ++ File};
+ {ok, Core} ->
+ Mod = cerl:concrete(cerl:module_name(Core)),
+ NoWarn = abs_get_nowarn(AbstrCode, Mod),
+ case dialyzer_utils:get_record_and_type_info(AbstrCode) of
+ {error, _} = Error -> Error;
+ {ok, RecInfo} ->
+ CServer1 =
+ dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
+ case UseContracts of
+ true ->
+ case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
+ {error, _} = Error -> Error;
+ {ok, SpecInfo, _CallbackInfo} ->
+ CServer2 =
+ dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo, CServer1),
+ store_core(Mod, Core, NoWarn, Callgraph, CServer2)
+ end;
+ false ->
+ store_core(Mod, Core, NoWarn, Callgraph, CServer1)
end
end
end.
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index dc5a3fed37..5d24e0d0d6 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -476,7 +476,7 @@ doit(Module) ->
{ok, Code} = dialyzer_utils:get_core_from_abstract_code(AbstrCode),
{ok, Records} = dialyzer_utils:get_record_and_type_info(AbstrCode),
%% contract typing info in dictionary format
- {ok, Contracts} =
+ {ok, Contracts, _Callbacks} =
dialyzer_utils:get_spec_info(cerl:concrete(cerl:module_name(Code)),
AbstrCode, Records),
Sigs0 = get_top_level_signatures(Code, Records, Contracts),
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 12f8dec67e..2a248fb028 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -311,11 +311,15 @@ merge_records(NewRecords, OldRecords) ->
%%
%% ============================================================================
+-type spec_dict() :: dict().
+-type callback_dict() :: dict().
+
-spec get_spec_info(atom(), abstract_code(), dict()) ->
- {'ok', dict()} | {'error', string()}.
+ {'ok', spec_dict(), callback_dict()} | {'error', string()}.
get_spec_info(ModName, AbstractCode, RecordsDict) ->
- get_spec_info(AbstractCode, dict:new(), RecordsDict, ModName, "nofile").
+ get_spec_info(AbstractCode, dict:new(), dict:new(),
+ RecordsDict, ModName, "nofile").
%% TypeSpec is a list of conditional contracts for a function.
%% Each contract is of the form {[Argument], Range, [Constraint]} where
@@ -323,21 +327,34 @@ get_spec_info(ModName, AbstractCode, RecordsDict) ->
%% - Constraint is of the form {subtype, T1, T2} where T1 and T2
%% are erl_types:erl_type()
-get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left],
- SpecDict, RecordsDict, ModName, File) when is_list(TypeSpec) ->
+get_spec_info([{attribute, Ln, Contract, {Id, TypeSpec}}|Left],
+ SpecDict, CallbackDict, RecordsDict, ModName, File)
+ when ((Contract =:= 'spec') or (Contract =:= 'callback')),
+ is_list(TypeSpec) ->
MFA = case Id of
{_, _, _} = T -> T;
{F, A} -> {ModName, F, A}
end,
- try dict:find(MFA, SpecDict) of
+ ActiveDict =
+ case Contract of
+ spec -> SpecDict;
+ callback -> CallbackDict
+ end,
+ try dict:find(MFA, ActiveDict) of
error ->
- NewSpecDict =
+ NewActiveDict =
dialyzer_contracts:store_tmp_contract(MFA, {File, Ln}, TypeSpec,
- SpecDict, RecordsDict),
- get_spec_info(Left, NewSpecDict, RecordsDict, ModName, File);
+ ActiveDict, RecordsDict),
+ {NewSpecDict, NewCallbackDict} =
+ case Contract of
+ spec -> {NewActiveDict, CallbackDict};
+ callback -> {SpecDict, NewActiveDict}
+ end,
+ get_spec_info(Left, NewSpecDict, NewCallbackDict,
+ RecordsDict, ModName,File);
{ok, {{OtherFile, L},_C}} ->
{Mod, Fun, Arity} = MFA,
- Msg = flat_format(" Contract for function ~w:~w/~w "
+ Msg = flat_format(" Contract/callback for function ~w:~w/~w "
"already defined in ~s:~w\n",
[Mod, Fun, Arity, OtherFile, L]),
throw({error, Msg})
@@ -347,12 +364,14 @@ get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left],
[Ln, Error])}
end;
get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left],
- SpecDict, RecordsDict, ModName, _File) ->
- get_spec_info(Left, SpecDict, RecordsDict, ModName, IncludeFile);
-get_spec_info([_Other|Left], SpecDict, RecordsDict, ModName, File) ->
- get_spec_info(Left, SpecDict, RecordsDict, ModName, File);
-get_spec_info([], SpecDict, _RecordsDict, _ModName, _File) ->
- {ok, SpecDict}.
+ SpecDict, CallbackDict, RecordsDict, ModName, _File) ->
+ get_spec_info(Left, SpecDict, CallbackDict,
+ RecordsDict, ModName, IncludeFile);
+get_spec_info([_Other|Left], SpecDict, CallbackDict,
+ RecordsDict, ModName, File) ->
+ get_spec_info(Left, SpecDict, CallbackDict, RecordsDict, ModName, File);
+get_spec_info([], SpecDict, CallbackDict, _RecordsDict, _ModName, _File) ->
+ {ok, SpecDict, CallbackDict}.
%% ============================================================================
%%