From 4884986bc945978177b02a7e81c50a5ea2f007fa Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 26 Nov 2015 15:18:39 +0100 Subject: dialyzer: Fix a bug concerning the option 'plt_remove' [James Fish:] Dialyzer always asserts that files and directories passed in its options exist. Therefore it is not possible to remove a beam/module from a PLT when the beam file no longer exists. Dialyzer should not to check files exist on disk when removing from the PLT. --- lib/dialyzer/src/dialyzer_options.erl | 36 +++++++++++++++++++++-------- lib/dialyzer/test/plt_SUITE.erl | 43 +++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl index ce84c17f43..dd81dd01ed 100644 --- a/lib/dialyzer/src/dialyzer_options.erl +++ b/lib/dialyzer/src/dialyzer_options.erl @@ -72,9 +72,15 @@ preprocess_opts([Opt|Opts]) -> [Opt|preprocess_opts(Opts)]. postprocess_opts(Opts = #options{}) -> + check_file_existence(Opts), Opts1 = check_output_plt(Opts), adapt_get_warnings(Opts1). +check_file_existence(#options{analysis_type = plt_remove}) -> ok; +check_file_existence(#options{files = Files, files_rec = FilesRec}) -> + assert_filenames_exist(Files), + assert_filenames_exist(FilesRec). + check_output_plt(Opts = #options{analysis_type = Mode, from = From, output_plt = OutPLT}) -> case is_plt_mode(Mode) of @@ -126,14 +132,14 @@ build_options([{OptionName, Value} = Term|Rest], Options) -> apps -> OldValues = Options#options.files_rec, AppDirs = get_app_dirs(Value), - assert_filenames(Term, AppDirs), + assert_filenames_form(Term, AppDirs), build_options(Rest, Options#options{files_rec = AppDirs ++ OldValues}); files -> - assert_filenames(Term, Value), + assert_filenames_form(Term, Value), build_options(Rest, Options#options{files = Value}); files_rec -> OldValues = Options#options.files_rec, - assert_filenames(Term, Value), + assert_filenames_form(Term, Value), build_options(Rest, Options#options{files_rec = Value ++ OldValues}); analysis_type -> NewOptions = @@ -210,16 +216,26 @@ get_app_dirs(Apps) when is_list(Apps) -> get_app_dirs(Apps) -> bad_option("Use a list of otp applications", Apps). -assert_filenames(Term, [FileName|Left]) when length(FileName) >= 0 -> +assert_filenames(Term, Files) -> + assert_filenames_form(Term, Files), + assert_filenames_exist(Files). + +assert_filenames_form(Term, [FileName|Left]) when length(FileName) >= 0 -> + assert_filenames_form(Term, Left); +assert_filenames_form(_Term, []) -> + ok; +assert_filenames_form(Term, [_|_]) -> + bad_option("Malformed or non-existing filename", Term). + +assert_filenames_exist([FileName|Left]) -> case filelib:is_file(FileName) orelse filelib:is_dir(FileName) of true -> ok; - false -> bad_option("No such file, directory or application", FileName) + false -> + bad_option("No such file, directory or application", FileName) end, - assert_filenames(Term, Left); -assert_filenames(_Term, []) -> - ok; -assert_filenames(Term, [_|_]) -> - bad_option("Malformed or non-existing filename", Term). + assert_filenames_exist(Left); +assert_filenames_exist([]) -> + ok. assert_filename(FileName) when length(FileName) >= 0 -> ok; diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl index 16180a7435..6ebe23b54b 100644 --- a/lib/dialyzer/test/plt_SUITE.erl +++ b/lib/dialyzer/test/plt_SUITE.erl @@ -8,14 +8,13 @@ -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]). + remove_plt/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, - local_fun_same_as_callback]. +all() -> [build_plt, beam_tests, update_plt, run_plt_check, + remove_plt, run_succ_typings, local_fun_same_as_callback]. build_plt(Config) -> OutDir = ?config(priv_dir, Config), @@ -213,6 +212,42 @@ local_fun_same_as_callback(Config) when is_list(Config) -> {init_plt, Plt}] ++ Opts), ok. +%%% [James Fish:] +%%% Dialyzer always asserts that files and directories passed in its +%%% options exist. Therefore it is not possible to remove a beam/module +%%% from a PLT when the beam file no longer exists. Dialyzer should not to +%%% check files exist on disk when removing from the PLT. +remove_plt(Config) -> + PrivDir = ?config(priv_dir, Config), + Prog1 = <<"-module(m1). + -export([t/0]). + t() -> + m2:a(a).">>, + {ok, Beam1} = compile(Config, Prog1, m1, []), + + Prog2 = <<"-module(m2). + -export([a/1]). + a(A) when is_integer(A) -> A.">>, + {ok, Beam2} = compile(Config, Prog2, m2, []), + + Plt = filename:join(PrivDir, "remove.plt"), + Opts = [{check_plt, true}, {from, byte_code}], + + [{warn_return_no_exit, _, {no_return,[only_normal,t,0]}}, + {warn_failing_call, _, {call, [m2,a,"('a')",_,_,_,_,_]}}] = + dialyzer:run([{analysis_type, plt_build}, + {files, [Beam1, Beam2]}, + {get_warnings, true}, + {output_plt, Plt}] ++ Opts), + + [] = dialyzer:run([{init_plt, Plt}, + {files, [Beam2]}, + {analysis_type, plt_remove}]), + + [] = dialyzer:run([{analysis_type, succ_typings}, + {files, [Beam1]}, + {init_plt, Plt}] ++ Opts), + ok. compile(Config, Prog, Module, CompileOpts) -> Source = lists:concat([Module, ".erl"]), -- cgit v1.2.3