From a96fddfcde4ab3a71aea01914bd3e7a836db46c0 Mon Sep 17 00:00:00 2001 From: James Fish Date: Thu, 20 Nov 2014 15:46:54 +0000 Subject: Improve default dialyzer PLT by trying to guess dependencies Try to automatically detect all application dependencies when `plt_apps` is not included in `rebar.config`. Note that this will not follow `runtime_dependencies` in OTP applications. This can be resolved by adding any missing `runtime_dependencies` to `applications` in the .app.src file or including `plt_apps` in `rebar.config`. --- src/rebar_prv_dialyzer.erl | 62 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index f5d840d..7c13417 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -72,11 +72,42 @@ update_plt(State, Apps, Deps) -> get_plt_files(State, Apps, Deps) -> case rebar_state:get(State, plt_apps) of undefined -> - apps_to_files(Deps); + default_plt_files(Apps, Deps); PltApps -> app_names_to_files(PltApps, Apps ++ Deps) end. +default_plt_files(Apps, Deps) -> + DepApps = lists:flatmap(fun rebar_app_info:applications/1, Apps), + default_plt_files(default_plt_apps() ++ DepApps, Apps, Deps, [], []). + +default_plt_apps() -> + [erts, + kernel, + stdlib]. + +default_plt_files([], _, _, _, Files) -> + Files; +default_plt_files([AppName | DepApps], Apps, Deps, PltApps, Files) -> + case lists:member(AppName, PltApps) of + true -> + default_plt_files(DepApps, Apps, Deps, PltApps, Files); + false -> + {DepApps2, Files2} = app_name_to_info(AppName, Apps, Deps), + DepApps3 = DepApps2 ++ DepApps, + Files3 = Files2 ++ Files, + default_plt_files(DepApps3, Apps, Deps, [AppName | PltApps], Files3) + end. + +app_name_to_info(AppName, Apps, Deps) -> + case rebar_app_utils:find(ec_cnv:to_binary(AppName), Apps) of + {ok, App} -> + % Don't include project app files in plt + {rebar_app_info:applications(App), []}; + error -> + app_name_to_info(AppName, Deps) + end. + apps_to_files(Apps) -> lists:flatmap(fun app_to_files/1, Apps). @@ -102,33 +133,42 @@ module_to_file(Module, EbinDir, Ext) -> end. app_names_to_files(AppNames, Apps) -> - lists:flatmap(fun(AppName) -> app_name_to_files(AppName, Apps) end, - AppNames). + ToFiles = fun(AppName) -> + {_, Files} = app_name_to_info(AppName, Apps), + Files + end, + lists:flatmap(ToFiles, AppNames). -app_name_to_files(AppName, Apps) -> +app_name_to_info(AppName, Apps) -> case rebar_app_utils:find(ec_cnv:to_binary(AppName), Apps) of {ok, App} -> - app_to_files(App); + DepApps = rebar_app_info:applications(App), + Files = app_to_files(App), + {DepApps, Files}; error -> - app_name_to_files(AppName) + app_name_to_info(AppName) end. -app_name_to_files(AppName) -> +app_name_to_info(AppName) -> case code:lib_dir(AppName) of {error, _} -> ?CONSOLE("Unknown application ~s", [AppName]), - []; + {[], []}; AppDir -> - app_dir_to_files(AppDir, AppName) + app_dir_to_info(AppDir, AppName) end. -app_dir_to_files(AppDir, AppName) -> +app_dir_to_info(AppDir, AppName) -> EbinDir = filename:join(AppDir, "ebin"), AppFile = filename:join(EbinDir, atom_to_list(AppName) ++ ".app"), case file:consult(AppFile) of {ok, [{application, AppName, AppDetails}]} -> + DepApps = proplists:get_value(applications, AppDetails, []), + IncApps = proplists:get_value(included_applications, AppDetails, + []), Modules = proplists:get_value(modules, AppDetails, []), - modules_to_files(Modules, EbinDir); + Files = modules_to_files(Modules, EbinDir), + {IncApps ++ DepApps, Files}; _ -> Error = io_lib:format("Could not parse ~p", [AppFile]), throw({dialyzer_error, Error}) -- cgit v1.1