aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer')
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl19
-rw-r--r--lib/dialyzer/src/dialyzer_callgraph.erl29
-rw-r--r--lib/dialyzer/src/dialyzer_coordinator.erl63
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl159
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl148
-rw-r--r--lib/dialyzer/src/dialyzer_worker.erl45
6 files changed, 107 insertions, 356 deletions
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index e009b8f43f..febaf56e40 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -35,6 +35,10 @@
start_compilation/2,
continue_compilation/2]).
+-export_type([compilation_data/0,
+ result/0,
+ servers/0]).
+
-include("dialyzer.hrl").
-record(analysis_state,
@@ -247,10 +251,10 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
send_log(Parent, Msg2),
{Callgraph, sets:from_list(NoWarn), CServer2}.
--type servers() :: term().
--type result() :: term().
--type file_result() :: term().
--type data() :: term().
+-type servers() :: term(). %%opaque
+-type result() :: term(). %%opaque
+-type file_result() :: term(). %%opaque
+-type compilation_data() :: term(). %%opaque
-spec compile_coordinator_init() -> result().
@@ -266,7 +270,8 @@ add_to_result(File, NewData, {V, E, Failed, NoWarn, Mods}) ->
{NV ++ V, NE ++ E, Failed, NewNoWarn ++ NoWarn, [Mod|Mods]}
end.
--spec start_compilation(file:filename(), servers()) -> data().
+-spec start_compilation(file:filename(), servers()) ->
+ {error, term()} |{ok, integer(), compilation_data()}.
start_compilation(File, {Callgraph, Codeserver, StartFrom,
Includes, Defines, UseContracts}) ->
@@ -368,9 +373,9 @@ store_core(Mod, Core, NoWarn, Callgraph, CServer) ->
CServer = dialyzer_codeserver:insert_exports(Exp, CServer),
CServer = dialyzer_codeserver:insert_temp_exported_types(ExpTypes, CServer),
CoreTree = cerl:from_records(Core),
- {cerl_trees:size(CoreTree), {Mod, CoreTree, NoWarn, Callgraph, CServer}}.
+ {ok, cerl_trees:size(CoreTree), {Mod, CoreTree, NoWarn, Callgraph, CServer}}.
--spec continue_compilation(integer(), data()) -> {integer(), file_result()}.
+-spec continue_compilation(integer(), compilation_data()) -> file_result().
continue_compilation(NextLabel, {Mod, CoreTree, NoWarn, Callgraph, CServer}) ->
{LabeledTree, _NewNextLabel} = cerl_trees:label(CoreTree, NextLabel),
diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl
index bf939655d0..bb96ada65f 100644
--- a/lib/dialyzer/src/dialyzer_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_callgraph.erl
@@ -264,7 +264,7 @@ get_required_by(SCC, #callgraph{active_digraph = DG}) ->
modules(#callgraph{digraph = DG}) ->
ordsets:from_list([M || {M,_F,_A} <- digraph_vertices(DG)]).
--spec module_postorder(callgraph()) -> [module()].
+-spec module_postorder(callgraph()) -> {[module()], digraph()}.
module_postorder(#callgraph{digraph = DG}) ->
Edges = digraph_edges(DG),
@@ -323,7 +323,8 @@ reset_from_funs(Funs, #callgraph{digraph = DG,
digraph_delete(SubGraph),
{Postorder, CG#callgraph{active_digraph = NewActiveDG}}.
--spec module_postorder_from_funs([mfa_or_funlbl()], callgraph()) -> [module()].
+-spec module_postorder_from_funs([mfa_or_funlbl()], callgraph()) ->
+ {[module()], callgraph()}.
module_postorder_from_funs(Funs, #callgraph{digraph = DG} = CG) ->
SubGraph = digraph_reaching_subgraph(Funs, DG),
@@ -352,7 +353,8 @@ ets_lookup_set(Key, Table) ->
%% The set of labels in the tree must be disjoint from the set of
%% labels already occuring in the callgraph.
--spec scan_core_tree(cerl:c_module(), callgraph()) -> callgraph().
+-spec scan_core_tree(cerl:c_module(), callgraph()) ->
+ {[mfa_or_funlbl()], [callgraph_edge()]}.
scan_core_tree(Tree, #callgraph{calls = ETSCalls,
esc = ETSEsc,
@@ -595,9 +597,10 @@ renew_race_code(Races, #callgraph{race_data_server = RaceDataServer} = CG) ->
ok = race_data_server_cast(
{renew_race_code, {Fun, FunArgs, Code}},
RaceDataServer),
- CG;
-renew_race_code({Fun, FunArgs, Code},
- #race_data_state{race_code = RaceCode} = State) ->
+ CG.
+
+renew_race_code_handler({Fun, FunArgs, Code},
+ #race_data_state{race_code = RaceCode} = State) ->
State#race_data_state{race_code = dict:store(Fun, [FunArgs, Code], RaceCode)}.
-spec renew_race_public_tables(label(), callgraph()) -> callgraph().
@@ -606,9 +609,11 @@ renew_race_public_tables(VarLabel,
#callgraph{race_data_server = RaceDataServer} = CG) ->
ok =
race_data_server_cast({renew_race_public_tables, VarLabel}, RaceDataServer),
- CG;
-renew_race_public_tables(VarLabel,
- #race_data_state{public_tables = PT} = State) ->
+ CG.
+
+renew_race_public_tables_handler(VarLabel,
+ #race_data_state{public_tables = PT}
+ = State) ->
State#race_data_state{public_tables = ordsets:add_element(VarLabel, PT)}.
-spec cleanup(callgraph()) -> callgraph().
@@ -739,8 +744,8 @@ race_data_server_handle_cast(race_code_new, State) ->
race_data_server_handle_cast({Tag, Data}, State) ->
case Tag of
renew_race_info -> renew_race_info(Data, State);
- renew_race_code -> renew_race_code(Data, State);
- renew_race_public_tables -> renew_race_public_tables(Data, State);
+ renew_race_code -> renew_race_code_handler(Data, State);
+ renew_race_public_tables -> renew_race_public_tables_handler(Data, State);
put_race_code -> State#race_data_state{race_code = Data};
put_public_tables -> State#race_data_state{public_tables = Data};
put_named_tables -> State#race_data_state{named_tables = Data};
@@ -775,7 +780,7 @@ to_dot(#callgraph{digraph = DG, esc = Esc} = CG, File) ->
end
end,
Escaping = [{Fun(L), {color, red}}
- || L <- sets:to_list(Esc), L =/= external],
+ || L <- [E || {E} <- ets:tab2list(Esc)], L =/= external],
Vertices = digraph_edges(DG),
hipe_dot:translate_list(Vertices, File, "CG", Escaping).
diff --git a/lib/dialyzer/src/dialyzer_coordinator.erl b/lib/dialyzer/src/dialyzer_coordinator.erl
index d8a3ef2bd2..9bcd7e4c63 100644
--- a/lib/dialyzer/src/dialyzer_coordinator.erl
+++ b/lib/dialyzer/src/dialyzer_coordinator.erl
@@ -46,17 +46,19 @@
-module(dialyzer_coordinator).
-%%% Exports for all possible uses of coordinator
+%%% Exports for all possible uses of coordinator from main process
-export([start/2,
all_spawned/1]).
+%%% Exports for all possible workers
+-export([job_done/3]).
+
%%% Exports for the typesig and dataflow analysis main process
-export([scc_spawn/2,
receive_not_fixpoint/0]).
%%% Exports for the typesig and dataflow analysis workers
--export([scc_done/3,
- sccs_to_pids_reply/0,
+-export([sccs_to_pids_reply/0,
sccs_to_pids_request/2]).
%%% Exports for the compilation main process
@@ -67,39 +69,44 @@
-export([compilation_done/3,
get_next_label/2]).
+-export_type([coordinator/0, mode/0]).
+
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
--type coordinator() :: pid().
--type map() :: dict().
--type scc() :: [mfa_or_funlbl()].
--type mode() :: 'typesig' | 'dataflow' | 'compile'.
-
--record(state, {parent :: pid(),
- mode :: mode(),
- spawn_count = 0 :: integer(),
- all_spawned = false :: boolean(),
- job_to_pid :: map(),
- next_label :: integer(),
- result :: [mfa_or_funlbl()] |
- dialyzer_analysis_callgraph:result(),
- init_job_data :: dialyzer_typesig:servers()
+-type coordinator() :: pid(). %%opaque
+
+-type map() :: dict().
+-type scc() :: [mfa_or_funlbl()].
+-type mode() :: 'typesig' | 'dataflow' | 'compile'.
+-type servers() :: dialyzer_succ_typings:servers() |
+ dialyzer_analysis_callgraph:servers().
+
+-record(state, {parent :: pid(),
+ mode :: mode(),
+ spawn_count = 0 :: integer(),
+ all_spawned = false :: boolean(),
+ job_to_pid :: map(),
+ next_label :: integer(),
+ result :: [mfa_or_funlbl()] |
+ dialyzer_analysis_callgraph:result(),
+ init_job_data :: servers()
}).
-include("dialyzer.hrl").
%%--------------------------------------------------------------------
--spec start('typesig' | 'dataflow', dialyzer_typesig:servers()) -> pid();
+-spec start('typesig' | 'dataflow', dialyzer_succ_typings:servers()) -> pid();
('compile', dialyzer_analysis_callgraph:servers()) -> pid().
start(Mode, Servers) ->
{ok, Pid} = gen_server:start(?MODULE, {self(), Mode, Servers}, []),
Pid.
--spec scc_spawn(scc(), coordinator()) -> ok.
+-spec scc_spawn(scc() | module(), coordinator()) -> ok.
scc_spawn(SCC, Coordinator) ->
cast({scc_spawn, SCC}, Coordinator).
@@ -119,10 +126,10 @@ scc_to_pids_request_handle(Worker, SCCs, SCCtoPID) ->
sccs_to_pids_reply() ->
receive {sccs_to_pids, Pids} -> Pids end.
--spec scc_done(scc(), scc(), coordinator()) -> ok.
+-spec job_done(scc() | file:filename(), term(), coordinator()) -> ok.
-scc_done(SCC, NotFixpoint, Coordinator) ->
- cast({done, SCC, NotFixpoint}, Coordinator).
+job_done(Job, Result, Coordinator) ->
+ cast({done, Job, Result}, Coordinator).
-spec compilation_done(file:filename(),
dialyzer_analysis_callgraph:compilation_data(),
@@ -145,9 +152,10 @@ send_done_to_parent(#state{mode = Mode,
X when X =:= 'typesig'; X =:= 'dataflow' -> {not_fixpoint, Result};
'compile' -> {compilation_data, Result, NextLabel}
end,
- Parent ! Msg.
+ Parent ! Msg,
+ ok.
--spec receive_not_fixpoint() -> dialyzer_plt:plt().
+-spec receive_not_fixpoint() -> [mfa_or_funlbl()].
receive_not_fixpoint() ->
receive {not_fixpoint, NotFixpoint} -> NotFixpoint end.
@@ -172,8 +180,7 @@ get_next_label(EstimatedSize, Coordinator) ->
%%--------------------------------------------------------------------
--spec init({pid(), mode(), dialyzer_succ_typings:servers() |
- dialyzer_analysis_callgraph:servers()}) -> {ok, #state{}}.
+-spec init({pid(), mode(), servers()}) -> {ok, #state{}}.
init({Parent, Mode, InitJobData}) ->
InitState = #state{parent = Parent, mode = Mode, init_job_data = InitJobData},
@@ -247,7 +254,7 @@ handle_cast({scc_spawn, SCC},
spawn_count = SpawnCount,
job_to_pid = SCCtoPID
} = State) ->
- Pid = dialyzer_worker:launch(Mode, SCC, Servers),
+ Pid = dialyzer_worker:launch(Mode, SCC, Servers, self()),
{noreply,
State#state{spawn_count = SpawnCount + 1,
job_to_pid = store_map(SCC, Pid, SCCtoPID)}
@@ -257,7 +264,7 @@ handle_cast({compiler_spawn, Filename},
init_job_data = Servers,
spawn_count = SpawnCount
} = State) ->
- dialyzer_worker:launch(Mode, Filename, Servers),
+ dialyzer_worker:launch(Mode, Filename, Servers, self()),
{noreply,
State#state{spawn_count = SpawnCount + 1}
}.
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 248ad328ab..cb376daf68 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -37,9 +37,6 @@
state__get_records/1, state__put_callgraph/2,
state__put_races/2, state__records_only/1]).
-%% Debug and test interfaces.
--export([get_top_level_signatures/2, pp/1]).
-
-export_type([state/0]).
-include("dialyzer.hrl").
@@ -68,7 +65,7 @@
%%-define(DEBUG, true).
%%-define(DEBUG_PP, true).
-%%-define(DOT, true).
+%%-define(DEBUG_TIME, true).
-ifdef(DEBUG).
-import(erl_types, [t_to_string/1]).
@@ -129,137 +126,12 @@ get_fun_types(Tree, Plt, Callgraph, Records) ->
State = analyze_module(Tree, Plt, Callgraph, Records, false),
state__all_fun_types(State).
-%%--------------------------------------------------------------------
-
--spec pp(file:filename()) -> 'ok'.
-
-pp(File) ->
- {ok, Code} = dialyzer_utils:get_core_from_src(File, [no_copt]),
- Plt = get_def_plt(),
- AnnTree = annotate_module(Code, Plt),
- io:put_chars(cerl_prettypr:format(AnnTree, [{hook, cerl_typean:pp_hook()}])),
- io:nl().
-
-%%--------------------------------------------------------------------
-%% This is used in the testsuite.
-
--spec get_top_level_signatures(cerl:c_module(), dict()) ->
- [{{atom(), arity()}, erl_types:erl_type()}].
-
-get_top_level_signatures(Code, Records) ->
- {Tree, _} = cerl_trees:label(cerl:from_records(Code)),
- Callgraph0 = dialyzer_callgraph:new(),
- Callgraph1 = dialyzer_callgraph:scan_core_tree(Tree, Callgraph0),
- {Callgraph2, _} = dialyzer_callgraph:remove_external(Callgraph1),
- Callgraph = dialyzer_callgraph:finalize(Callgraph2),
- to_dot(Callgraph),
- Plt = get_def_plt(),
- FunTypes = get_fun_types(Tree, Plt, Callgraph, Records),
- FunTypes1 = lists:foldl(fun({V, F}, Acc) ->
- Label = get_label(F),
- case dict:find(Label, Acc) of
- error ->
- Arity = cerl:fname_arity(V),
- Type = t_fun(lists:duplicate(Arity,
- t_none()),
- t_none()),
- dict:store(Label, Type, Acc);
- {ok, _} -> Acc
- end
- end, FunTypes, cerl:module_defs(Tree)),
- dialyzer_callgraph:delete(Callgraph),
- Sigs = [{{cerl:fname_id(V), cerl:fname_arity(V)},
- dict:fetch(get_label(F), FunTypes1)}
- || {V, F} <- cerl:module_defs(Tree)],
- ordsets:from_list(Sigs).
-
-get_def_plt() ->
- try
- dialyzer_plt:from_file(dialyzer_plt:get_default_plt())
- catch
- throw:{dialyzer_error, _} -> dialyzer_plt:new()
- end.
-
-%%% ===========================================================================
-%%%
-%%% Annotate all top level funs.
-%%%
-%%% ===========================================================================
-
-annotate_module(Code, Plt) ->
- {Tree, _} = cerl_trees:label(cerl:from_records(Code)),
- Callgraph0 = dialyzer_callgraph:new(),
- Callgraph1 = dialyzer_callgraph:scan_core_tree(Tree, Callgraph0),
- {Callgraph2, _} = dialyzer_callgraph:remove_external(Callgraph1),
- Callgraph = dialyzer_callgraph:finalize(Callgraph2),
- State = analyze_module(Tree, Plt, Callgraph),
- Res = annotate(Tree, State),
- dialyzer_callgraph:delete(Callgraph),
- Res.
-
-annotate(Tree, State) ->
- case cerl:subtrees(Tree) of
- [] -> set_type(Tree, State);
- List ->
- NewSubTrees = [[annotate(Subtree, State) || Subtree <- Group]
- || Group <- List],
- NewTree = cerl:update_tree(Tree, NewSubTrees),
- set_type(NewTree, State)
- end.
-
-set_type(Tree, State) ->
- case cerl:type(Tree) of
- 'fun' ->
- Type = state__fun_type(Tree, State),
- case t_is_any(Type) of
- true ->
- cerl:set_ann(Tree, delete_ann(typesig, cerl:get_ann(Tree)));
- false ->
- cerl:set_ann(Tree, append_ann(typesig, Type, cerl:get_ann(Tree)))
- end;
- apply ->
- case state__find_apply_return(Tree, State) of
- unknown -> Tree;
- ReturnType ->
- case t_is_any(ReturnType) of
- true ->
- cerl:set_ann(Tree, delete_ann(type, cerl:get_ann(Tree)));
- false ->
- cerl:set_ann(Tree, append_ann(type, ReturnType,
- cerl:get_ann(Tree)))
- end
- end;
- _ ->
- Tree
- end.
-
-append_ann(Tag, Val, [X | Xs]) ->
- if tuple_size(X) >= 1, element(1, X) =:= Tag ->
- append_ann(Tag, Val, Xs);
- true ->
- [X | append_ann(Tag, Val, Xs)]
- end;
-append_ann(Tag, Val, []) ->
- [{Tag, Val}].
-
-delete_ann(Tag, [X | Xs]) ->
- if tuple_size(X) >= 1, element(1, X) =:= Tag ->
- delete_ann(Tag, Xs);
- true ->
- [X | delete_ann(Tag, Xs)]
- end;
-delete_ann(_, []) ->
- [].
-
%%% ===========================================================================
%%%
%%% The analysis.
%%%
%%% ===========================================================================
-analyze_module(Tree, Plt, Callgraph) ->
- analyze_module(Tree, Plt, Callgraph, dict:new(), false).
-
analyze_module(Tree, Plt, Callgraph, Records, GetWarnings) ->
debug_pp(Tree, false),
Module = cerl:atom_val(cerl:module_name(Tree)),
@@ -3204,21 +3076,6 @@ state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) ->
?debug("LocalRet: ~s\n", [t_to_string(LocalRet)]),
{Fun, Sig, Contract, LocalRet}.
-state__find_apply_return(Tree, #state{callgraph = Callgraph} = State) ->
- Apply = get_label(Tree),
- case dialyzer_callgraph:lookup_call_site(Apply, Callgraph) of
- error ->
- unknown;
- {ok, List} ->
- case lists:member(external, List) of
- true -> t_any();
- false ->
- FunTypes = [state__fun_type(F, State) || F <- List],
- Returns = [t_fun_range(F) || F <- FunTypes],
- t_sup(Returns)
- end
- end.
-
forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) ->
{OldArgTypes, OldOut, Fixpoint} =
case dict:find(Fun, FunTab) of
@@ -3652,17 +3509,3 @@ strip_annotations(Tree) ->
debug_pp(_Tree, _UseHook) ->
ok.
-endif.
-
-%%----------------------------------------------------------------------------
-
--spec to_dot(dialyzer_callgraph:callgraph()) -> 'ok'.
-
--ifdef(DOT).
-to_dot(CG) ->
- dialyzer_callgraph:to_dot(CG).
--else.
-to_dot(_CG) ->
- ok.
--endif.
-
-%%----------------------------------------------------------------------------
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index 90d851bc3c..38f3d47353 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -29,7 +29,10 @@
-export([analyze_callgraph/3,
analyze_callgraph/4,
- get_warnings/6,
+ get_warnings/6
+ ]).
+
+-export([
find_succ_types_for_scc/1,
refine_one_module/1,
collect_scc_data/2,
@@ -38,12 +41,9 @@
find_depends_on/2
]).
-%% These are only intended as debug functions.
--export([doit/1,
- get_top_level_signatures/3]).
+-export_type([servers/0, scc_data/0, scc_refine_data/0]).
%%-define(DEBUG, true).
-%%-define(DEBUG_PP, true).
-ifdef(DEBUG).
-define(debug(X__, Y__), io:format(X__, Y__)).
@@ -213,9 +213,9 @@ refine_succ_typings([], State, Coordinator) ->
false -> {not_fixpoint, NotFixpoint, State}
end.
--type servers() :: term().
--type scc_data() :: term().
--type scc_refine_data() :: term().
+-type servers() :: term(). %%opaque
+-type scc_data() :: term(). %%opaque
+-type scc_refine_data() :: term(). %%opaque
-type scc() :: [mfa_or_funlbl()] | [module()].
-spec find_depends_on(scc(), servers()) -> [scc()].
@@ -237,18 +237,17 @@ collect_refine_scc_data(M, {CodeServer, Callgraph, PLT}) ->
FunTypes = get_fun_types_from_plt(AllFuns, Callgraph, PLT),
{ModCode, PLT, Callgraph, Records, FunTypes}.
--spec refine_one_module(scc_refine_data()) ->
- {dialyzer_callgraph:callgraph(), [label()]}. % ordset
+-spec refine_one_module(scc_refine_data()) -> [label()]. % ordset
-refine_one_module({ModCode, PLT, Callgraph, Records, FunTypes}) ->
+refine_one_module({ModCode, Plt, Callgraph, Records, FunTypes}) ->
NewFunTypes =
- dialyzer_dataflow:get_fun_types(ModCode, PLT, Callgraph, Records),
+ dialyzer_dataflow:get_fun_types(ModCode, Plt, Callgraph, Records),
case reached_fixpoint(FunTypes, NewFunTypes) of
true ->
ordsets:new();
{false, NotFixpoint} ->
?debug("Not fixpoint\n", []),
- insert_into_plt(dict:from_list(NotFixpoint), Callgraph, PLT),
+ Plt = insert_into_plt(dict:from_list(NotFixpoint), Callgraph, Plt),
ordsets:from_list([FunLbl || {FunLbl,_Type} <- NotFixpoint])
end.
@@ -366,8 +365,8 @@ find_succ_types_for_scc({SCC_Info, Contracts, NextLabel, AllFuns,
{value, _} -> true
end
end, PltContracts),
- insert_into_plt(FilteredFunTypes, Callgraph, Plt),
- dialyzer_plt:insert_contract_list(Plt, PltContracts),
+ Plt = insert_into_plt(FilteredFunTypes, Callgraph, Plt),
+ Plt = dialyzer_plt:insert_contract_list(Plt, PltContracts),
case (ContractFixpoint andalso
reached_fixpoint_strict(PropTypes, FilteredFunTypes)) of
true -> [];
@@ -460,122 +459,3 @@ send_log(Parent, Msg) ->
format_scc(SCC) ->
[MFA || {_M, _F, _A} = MFA <- SCC].
-
-%% ============================================================================
-%%
-%% Debug interface.
-%%
-%% ============================================================================
-
--spec doit(atom() | file:filename()) -> 'ok'.
-
-doit(Module) ->
- {ok, AbstrCode} = dialyzer_utils:get_abstract_code_from_src(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, _Callbacks} =
- dialyzer_utils:get_spec_info(cerl:concrete(cerl:module_name(Code)),
- AbstrCode, Records),
- Sigs0 = get_top_level_signatures(Code, Records, Contracts),
- M = if is_atom(Module) ->
- list_to_atom(filename:basename(atom_to_list(Module)));
- is_list(Module) ->
- list_to_atom(filename:basename(Module))
- end,
- Sigs1 = [{{M, F, A}, Type} || {{F, A}, Type} <- Sigs0],
- Sigs = ordsets:from_list(Sigs1),
- io:format("==================== Final result ====================\n\n", []),
- pp_signatures(Sigs, Records),
- ok.
-
--spec get_top_level_signatures(cerl:c_module(), dict(), dict()) ->
- [{{atom(), arity()}, erl_types:erl_type()}].
-
-get_top_level_signatures(Code, Records, Contracts) ->
- Tree = cerl:from_records(Code),
- {LabeledTree, NextLabel} = cerl_trees:label(Tree),
- Plt = get_def_plt(),
- ModuleName = cerl:atom_val(cerl:module_name(LabeledTree)),
- Plt1 = dialyzer_plt:delete_module(Plt, ModuleName),
- Plt2 = analyze_module(LabeledTree, NextLabel, Plt1, Records, Contracts),
- M = cerl:concrete(cerl:module_name(Tree)),
- Functions = [{M, cerl:fname_id(V), cerl:fname_arity(V)}
- || {V, _F} <- cerl:module_defs(LabeledTree)],
- %% First contracts check
- AllContracts = dict:fetch_keys(Contracts),
- ErrorContracts = AllContracts -- Functions,
- lists:foreach(fun(C) ->
- io:format("Contract for non-existing function: ~w\n",[C])
- end, ErrorContracts),
- Types = [{MFA, dialyzer_plt:lookup(Plt2, MFA)} || MFA <- Functions],
- Sigs = [{{F, A}, erl_types:t_fun(ArgT, RetT)}
- || {{_M, F, A}, {value, {RetT, ArgT}}} <- Types],
- ordsets:from_list(Sigs).
-
-get_def_plt() ->
- try
- dialyzer_plt:from_file(dialyzer_plt:get_default_plt())
- catch
- error:no_such_file -> dialyzer_plt:new();
- throw:{dialyzer_error, _} -> dialyzer_plt:new()
- end.
-
-pp_signatures([{{_, module_info, 0}, _}|Left], Records) ->
- pp_signatures(Left, Records);
-pp_signatures([{{_, module_info, 1}, _}|Left], Records) ->
- pp_signatures(Left, Records);
-pp_signatures([{{M, F, _A}, Type}|Left], Records) ->
- TypeString =
- case cerl:is_literal(Type) of
-%% Commented out so that dialyzer does not complain
-%% false ->
-%% "fun(" ++ String = erl_types:t_to_string(Type, Records),
-%% string:substr(String, 1, length(String)-1);
- true ->
- io_lib:format("~w", [cerl:concrete(Type)])
- end,
- io:format("~w:~w~s\n", [M, F, TypeString]),
- pp_signatures(Left, Records);
-pp_signatures([], _Records) ->
- ok.
-
--ifdef(DEBUG_PP).
-debug_pp(Tree, _Map) ->
- Tree1 = strip_annotations(Tree),
- io:put_chars(cerl_prettypr:format(Tree1)),
- io:nl().
-
-strip_annotations(Tree) ->
- cerl_trees:map(fun(T) ->
- case cerl:is_literal(T) orelse cerl:is_c_values(T) of
- true -> cerl:set_ann(T, []);
- false ->
- Label = cerl_trees:get_label(T),
- cerl:set_ann(T, [{'label', Label}])
- end
- end, Tree).
--else.
-debug_pp(_Tree, _Map) ->
- ok.
--endif. % DEBUG_PP
-
-%%
-%% Analysis of a single module
-%%
-analyze_module(LabeledTree, NextLbl, Plt, Records, Contracts) ->
- debug_pp(LabeledTree, dict:new()),
- CallGraph1 = dialyzer_callgraph:new(),
- CallGraph2 = dialyzer_callgraph:scan_core_tree(LabeledTree, CallGraph1),
- {CallGraph3, _Ext} = dialyzer_callgraph:remove_external(CallGraph2),
- CallGraph4 = dialyzer_callgraph:finalize(CallGraph3),
- CodeServer1 = dialyzer_codeserver:new(),
- Mod = cerl:concrete(cerl:module_name(LabeledTree)),
- CodeServer2 = dialyzer_codeserver:insert(Mod, LabeledTree, CodeServer1),
- CodeServer3 = dialyzer_codeserver:set_next_core_label(NextLbl, CodeServer2),
- CodeServer4 = dialyzer_codeserver:store_records(Mod, Records, CodeServer3),
- CodeServer5 = dialyzer_codeserver:store_contracts(Mod, Contracts, CodeServer4),
- Res = analyze_callgraph(CallGraph4, Plt, CodeServer5),
- dialyzer_callgraph:delete(CallGraph4),
- dialyzer_codeserver:delete(CodeServer5),
- Res.
diff --git a/lib/dialyzer/src/dialyzer_worker.erl b/lib/dialyzer/src/dialyzer_worker.erl
index b24103c5a8..48dae7cb56 100644
--- a/lib/dialyzer/src/dialyzer_worker.erl
+++ b/lib/dialyzer/src/dialyzer_worker.erl
@@ -20,18 +20,26 @@
-module(dialyzer_worker).
--export([launch/3]).
+-export([launch/4]).
--type worker() :: pid().
+-export_type([worker/0]).
+
+-type worker() :: pid(). %%opaque
+
+-type mode() :: dialyzer_coordinator:mode().
+-type coordinator() :: dialyzer_coordinator:coordinator().
+-type servers() :: dialyzer_succ_typings:servers() |
+ dialyzer_analysis_callgraph:servers().
+-type data() :: dialyzer_succ_typings:scc_data() |
+ dialyzer_succ_typings:scc_refine_data().
-record(state, {
- mode :: dialyzer_coordinator:mode(),
+ mode :: mode(),
job :: mfa_or_funlbl() | file:filename(),
+ coordinator :: coordinator(),
+ servers :: servers(),
depends_on = [] :: list(),
- coordinator :: dialyzer_coordinator:coordinator(),
- servers :: dialyzer_typesig:servers() |
- dialyzer_analysis_callgraph:servers(),
- scc_data :: dialyzer_typesig:scc_data()
+ scc_data :: data()
}).
-include("dialyzer.hrl").
@@ -46,14 +54,13 @@
%%--------------------------------------------------------------------
--spec launch(dialyzer_coordinator:mode(), [mfa_or_funlbl()],
- dialyzer_typesig:servers()) -> worker().
+-spec launch(mode(), [mfa_or_funlbl()], servers(), coordinator()) -> worker().
-launch(Mode, Job, Servers) ->
+launch(Mode, Job, Servers, Coordinator) ->
State = #state{mode = Mode,
job = Job,
servers = Servers,
- coordinator = self()},
+ coordinator = Coordinator},
InitState =
case Mode of
X when X =:= 'typesig'; X =:= 'dataflow' -> initializing;
@@ -93,9 +100,14 @@ loop(getting_data, State) ->
loop(updating, get_data(State));
loop(running, #state{mode = 'compile'} = State) ->
?debug("Compile: ~s\n",[State#state.job]),
- {EstimatedSize, Data} = start_compilation(State),
- Label = ask_coordinator_for_label(EstimatedSize, State),
- Result = continue_compilation(Label, Data),
+ Result =
+ case start_compilation(State) of
+ {ok, EstimatedSize, Data} ->
+ Label = ask_coordinator_for_label(EstimatedSize, State),
+ continue_compilation(Label, Data);
+ {error, _Reason} = Error ->
+ Error
+ end,
report_to_coordinator(Result, State);
loop(running, #state{mode = Mode} = State) when
Mode =:= 'typesig'; Mode =:= 'dataflow' ->
@@ -160,10 +172,9 @@ do_work(#state{mode = Mode, scc_data = SCCData}) ->
dataflow -> dialyzer_succ_typings:refine_one_module(SCCData)
end.
-report_to_coordinator(NotFixpoint,
- #state{job = Job, coordinator = Coordinator}) ->
+report_to_coordinator(Result, #state{job = Job, coordinator = Coordinator}) ->
?debug("Done: ~p\n",[Job]),
- dialyzer_coordinator:scc_done(Job, NotFixpoint, Coordinator).
+ dialyzer_coordinator:job_done(Job, Result, Coordinator).
start_compilation(#state{job = Job, servers = Servers}) ->
dialyzer_analysis_callgraph:start_compilation(Job, Servers).