aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStavros Aronis <[email protected]>2016-01-07 15:57:45 +0100
committerStavros Aronis <[email protected]>2016-01-11 15:10:06 +0100
commit56ab0f42911cc55c6a1640fa4949a267c1394c23 (patch)
tree85deda1a01a40940a397aa73a4696e1065a910b2
parent7e1ff61bac96c16a1453acb5be65ba90f48aa820 (diff)
downloadotp-56ab0f42911cc55c6a1640fa4949a267c1394c23.tar.gz
otp-56ab0f42911cc55c6a1640fa4949a267c1394c23.tar.bz2
otp-56ab0f42911cc55c6a1640fa4949a267c1394c23.zip
Fix inadvertent deletion of callback info
If a behaviour module contains an non-exported function with the same name as one of the behaviour's callbacks, the callback info was inadvertently deleted from the PLT as the dialyzer_plt:delete_list/2 function was cleaning up the callback table. This bug was reported by Brujo Benavides. Fixes ERL-72 bug report.
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl2
-rw-r--r--lib/dialyzer/test/plt_SUITE.erl58
2 files changed, 58 insertions, 2 deletions
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 634871b2eb..769f26a3df 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -137,7 +137,7 @@ delete_list(#plt{info = Info, types = Types,
#plt{info = table_delete_list(Info, List),
types = Types,
contracts = table_delete_list(Contracts, List),
- callbacks = table_delete_list(Callbacks, List),
+ callbacks = Callbacks,
exported_types = ExpTypes}.
-spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt().
diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl
index ecbac14e5d..16180a7435 100644
--- a/lib/dialyzer/test/plt_SUITE.erl
+++ b/lib/dialyzer/test/plt_SUITE.erl
@@ -7,12 +7,15 @@
-include("dialyzer_test_constants.hrl").
-export([suite/0, all/0, build_plt/1, beam_tests/1, update_plt/1,
+ local_fun_same_as_callback/1,
run_plt_check/1, run_succ_typings/1]).
suite() ->
[{timetrap, ?plt_timeout}].
-all() -> [build_plt, beam_tests, update_plt, run_plt_check, run_succ_typings].
+all() ->
+ [build_plt, beam_tests, update_plt, run_plt_check, run_succ_typings,
+ local_fun_same_as_callback].
build_plt(Config) ->
OutDir = ?config(priv_dir, Config),
@@ -158,6 +161,59 @@ update_plt(Config) ->
{init_plt, Plt}] ++ Opts),
ok.
+%%% If a behaviour module contains an non-exported function with the same name
+%%% as one of the behaviour's callbacks, the callback info was inadvertently
+%%% deleted from the PLT as the dialyzer_plt:delete_list/2 function was cleaning
+%%% up the callback table. This bug was reported by Brujo Benavides.
+
+local_fun_same_as_callback(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Prog1 =
+ <<"-module(bad_behaviour).
+ -callback bad() -> bad.
+ -export([publicly_bad/0]).
+
+ %% @doc This function is here just to avoid the 'unused' warning for bad/0
+ publicly_bad() -> bad().
+
+ %% @doc This function overlaps with the callback with the same name, and
+ %% that was an issue for dialyzer since it's a private function.
+ bad() -> bad.">>,
+ {ok, Beam} = compile(Config, Prog1, bad_behaviour, []),
+
+ ErlangBeam = case code:where_is_file("erlang.beam") of
+ non_existing ->
+ filename:join([code:root_dir(),
+ "erts", "preloaded", "ebin",
+ "erlang.beam"]);
+ EBeam ->
+ EBeam
+ end,
+ Plt = filename:join(PrivDir, "plt_bad_behaviour.plt"),
+ Opts = [{check_plt, true}, {from, byte_code}],
+ [] = dialyzer:run([{analysis_type, plt_build},
+ {files, [Beam, ErlangBeam]},
+ {output_plt, Plt}] ++ Opts),
+
+ Prog2 =
+ <<"-module(bad_child).
+ -behaviour(bad_behaviour).
+
+ -export([bad/0]).
+
+ %% @doc This function incorreclty implements bad_behaviour.
+ bad() -> not_bad.">>,
+ {ok, TestBeam} = compile(Config, Prog2, bad_child, []),
+
+ [{warn_behaviour, _,
+ {callback_type_mismatch,
+ [bad_behaviour,bad,0,"'not_bad'","'bad'"]}}] =
+ dialyzer:run([{analysis_type, succ_typings},
+ {files, [TestBeam]},
+ {init_plt, Plt}] ++ Opts),
+ ok.
+
+
compile(Config, Prog, Module, CompileOpts) ->
Source = lists:concat([Module, ".erl"]),
PrivDir = ?config(priv_dir,Config),