diff options
Diffstat (limited to 'lib/dialyzer/src/dialyzer_analysis_callgraph.erl')
-rw-r--r-- | lib/dialyzer/src/dialyzer_analysis_callgraph.erl | 61 |
1 files changed, 48 insertions, 13 deletions
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index 97d63a1f14..ab1bbe5ade 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %%-------------------------------------------------------------------- %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -43,7 +43,8 @@ parent :: pid(), plt :: dialyzer_plt:plt(), start_from = byte_code :: start_from(), - use_contracts = true :: boolean() + use_contracts = true :: boolean(), + behaviours = {false,[]} :: {boolean(),[atom()]} }). -record(server_state, {parent :: pid(), legal_warnings :: [dial_warn_tag()]}). @@ -56,7 +57,9 @@ start(Parent, LegalWarnings, Analysis) -> RacesOn = ordsets:is_element(?WARN_RACE_CONDITION, LegalWarnings), - Analysis0 = Analysis#analysis{race_detection = RacesOn}, + BehavOn = ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings), + Analysis0 = Analysis#analysis{race_detection = RacesOn, + behaviours_chk = BehavOn}, Analysis1 = expand_files(Analysis0), Analysis2 = run_analysis(Analysis1), State = #server_state{parent = Parent, legal_warnings = LegalWarnings}, @@ -93,6 +96,9 @@ loop(#server_state{parent = Parent, legal_warnings = LegalWarnings} = State, end; {AnalPid, ext_calls, NewExtCalls} -> loop(State, Analysis, NewExtCalls); + {AnalPid, unknown_behaviours, UnknownBehaviour} -> + send_unknown_behaviours(Parent, UnknownBehaviour), + loop(State, Analysis, ExtCalls); {AnalPid, mod_deps, ModDeps} -> send_mod_deps(Parent, ModDeps), loop(State, Analysis, ExtCalls); @@ -116,7 +122,9 @@ analysis_start(Parent, Analysis) -> plt = Plt, parent = Parent, start_from = Analysis#analysis.start_from, - use_contracts = Analysis#analysis.use_contracts + use_contracts = Analysis#analysis.use_contracts, + behaviours = {Analysis#analysis.behaviours_chk, + []} }, Files = ordsets:from_list(Analysis#analysis.files), {Callgraph, NoWarn, TmpCServer0} = compile_and_store(Files, State), @@ -167,11 +175,13 @@ analyze_callgraph(Callgraph, State) -> State#analysis_state{plt = NewPlt}; succ_typings -> NoWarn = State#analysis_state.no_warn_unused, + {BehavioursChk, _Known} = State#analysis_state.behaviours, DocPlt = State#analysis_state.doc_plt, Callgraph1 = dialyzer_callgraph:finalize(Callgraph), {Warnings, NewPlt, NewDocPlt} = dialyzer_succ_typings:get_warnings(Callgraph1, Plt, DocPlt, - Codeserver, NoWarn, Parent), + Codeserver, NoWarn, Parent, + BehavioursChk), dialyzer_callgraph:delete(Callgraph1), send_warnings(State#analysis_state.parent, Warnings), State#analysis_state{plt = NewPlt, doc_plt = NewDocPlt} @@ -186,7 +196,9 @@ compile_and_store(Files, #analysis_state{codeserver = CServer, include_dirs = Dirs, parent = Parent, use_contracts = UseContracts, - start_from = StartFrom} = State) -> + start_from = StartFrom, + behaviours = {BehChk, _} + } = State) -> send_log(Parent, "Reading files and computing callgraph... "), {T1, _} = statistics(runtime), Includes = [{i, D} || D <- Dirs], @@ -234,18 +246,37 @@ compile_and_store(Files, #analysis_state{codeserver = CServer, {T2, _} = statistics(runtime), Msg1 = io_lib:format("done in ~.2f secs\nRemoving edges... ", [(T2-T1)/1000]), send_log(Parent, Msg1), - NewCallgraph2 = cleanup_callgraph(State, NewCServer, NewCallgraph1, Modules), + {KnownBehaviours, UnknownBehaviours} = + dialyzer_behaviours:get_behaviours(Modules, NewCServer), + if UnknownBehaviours =:= [] -> ok; + true -> send_unknown_behaviours(Parent, UnknownBehaviours) + end, + State1 = State#analysis_state{behaviours = {BehChk,KnownBehaviours}}, + NewCallgraph2 = cleanup_callgraph(State1, NewCServer, NewCallgraph1, Modules), {T3, _} = statistics(runtime), Msg2 = io_lib:format("done in ~.2f secs\n", [(T3-T2)/1000]), send_log(Parent, Msg2), {NewCallgraph2, sets:from_list(NoWarn), NewCServer}. cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent, - codeserver = CodeServer}, + codeserver = CodeServer, + behaviours = {BehChk, KnownBehaviours} + }, CServer, Callgraph, Modules) -> ModuleDeps = dialyzer_callgraph:module_deps(Callgraph), send_mod_deps(Parent, ModuleDeps), {Callgraph1, ExtCalls} = dialyzer_callgraph:remove_external(Callgraph), + if BehChk -> + RelevantAPICalls = + dialyzer_behaviours:get_behaviour_apis(KnownBehaviours), + BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls, + lists:member(To, RelevantAPICalls)], + Callgraph2 = + dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls, + Callgraph1); + true -> + Callgraph2 = Callgraph1 + end, ExtCalls1 = [Call || Call = {_From, To} <- ExtCalls, not dialyzer_plt:contains_mfa(InitPlt, To)], {BadCalls1, RealExtCalls} = @@ -268,7 +299,7 @@ cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent, true -> send_ext_calls(Parent, lists:usort([To || {_From, To} <- RealExtCalls])) end, - Callgraph1. + Callgraph2. compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts) -> DefaultIncludes = default_includes(filename:dirname(File)), @@ -445,6 +476,10 @@ send_ext_calls(Parent, ExtCalls) -> Parent ! {self(), ext_calls, ExtCalls}, ok. +send_unknown_behaviours(Parent, UnknownBehaviours) -> + Parent ! {self(), unknown_behaviours, UnknownBehaviours}, + ok. + send_codeserver_plt(Parent, CServer, Plt ) -> Parent ! {self(), cserver, CServer, Plt}, ok. |