瀏覽代碼

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`.
pull/13/head
James Fish 10 年之前
父節點
當前提交
a96fddfcde
共有 1 個檔案被更改,包括 51 行新增11 行删除
  1. +51
    -11
      src/rebar_prv_dialyzer.erl

+ 51
- 11
src/rebar_prv_dialyzer.erl 查看文件

@ -72,11 +72,42 @@ update_plt(State, Apps, Deps) ->
get_plt_files(State, Apps, Deps) -> get_plt_files(State, Apps, Deps) ->
case rebar_state:get(State, plt_apps) of case rebar_state:get(State, plt_apps) of
undefined -> undefined ->
apps_to_files(Deps);
default_plt_files(Apps, Deps);
PltApps -> PltApps ->
app_names_to_files(PltApps, Apps ++ Deps) app_names_to_files(PltApps, Apps ++ Deps)
end. 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) -> apps_to_files(Apps) ->
lists:flatmap(fun app_to_files/1, Apps). lists:flatmap(fun app_to_files/1, Apps).
@ -102,33 +133,42 @@ module_to_file(Module, EbinDir, Ext) ->
end. end.
app_names_to_files(AppNames, Apps) -> 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 case rebar_app_utils:find(ec_cnv:to_binary(AppName), Apps) of
{ok, App} -> {ok, App} ->
app_to_files(App);
DepApps = rebar_app_info:applications(App),
Files = app_to_files(App),
{DepApps, Files};
error -> error ->
app_name_to_files(AppName)
app_name_to_info(AppName)
end. end.
app_name_to_files(AppName) ->
app_name_to_info(AppName) ->
case code:lib_dir(AppName) of case code:lib_dir(AppName) of
{error, _} -> {error, _} ->
?CONSOLE("Unknown application ~s", [AppName]), ?CONSOLE("Unknown application ~s", [AppName]),
[];
{[], []};
AppDir -> AppDir ->
app_dir_to_files(AppDir, AppName)
app_dir_to_info(AppDir, AppName)
end. end.
app_dir_to_files(AppDir, AppName) ->
app_dir_to_info(AppDir, AppName) ->
EbinDir = filename:join(AppDir, "ebin"), EbinDir = filename:join(AppDir, "ebin"),
AppFile = filename:join(EbinDir, atom_to_list(AppName) ++ ".app"), AppFile = filename:join(EbinDir, atom_to_list(AppName) ++ ".app"),
case file:consult(AppFile) of case file:consult(AppFile) of
{ok, [{application, AppName, AppDetails}]} -> {ok, [{application, AppName, AppDetails}]} ->
DepApps = proplists:get_value(applications, AppDetails, []),
IncApps = proplists:get_value(included_applications, AppDetails,
[]),
Modules = proplists:get_value(modules, 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]), Error = io_lib:format("Could not parse ~p", [AppFile]),
throw({dialyzer_error, Error}) throw({dialyzer_error, Error})

Loading…
取消
儲存