From 2d2aed627f747533e2a40f44dd813160e582c7e2 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Mon, 25 Oct 2010 22:07:32 +0200 Subject: Refactor Dialyzer support to make it more usable --- src/rebar_dialyzer.erl | 113 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 28 deletions(-) (limited to 'src/rebar_dialyzer.erl') diff --git a/src/rebar_dialyzer.erl b/src/rebar_dialyzer.erl index de78a05..d2b89aa 100644 --- a/src/rebar_dialyzer.erl +++ b/src/rebar_dialyzer.erl @@ -27,9 +27,9 @@ %% @author Dave Smith %% @doc rebar_dialyzer supports the following commands: %% %% A single option plt can be presented in the dialyzer_opts %% options in rebar.config. If it is present, it is used as the PLT for the @@ -44,9 +44,9 @@ %% ------------------------------------------------------------------- -module(rebar_dialyzer). --export([analyze/2, - build_plt/2, - check_plt/2]). +-export([dialyze/2, + 'build-plt'/2, + 'check-plt'/2]). -include("rebar.hrl"). @@ -57,21 +57,39 @@ %% =================================================================== %% @doc Perform static analysis on the contents of the ebin directory. -%% @spec analyze(Config::#config{}, File::string()) -> ok --spec(analyze(Config::#config{}, File::string()) -> ok). -analyze(Config, File) -> - Plt = plt_path(Config, File), +%% @spec dialyze(Config::#config{}, File::string()) -> ok +-spec dialyze(Config::#config{}, File::string()) -> ok. +dialyze(Config, File) -> + Plt = existing_plt_path(Config, File), case dialyzer:plt_info(Plt) of {ok, _} -> - try dialyzer:run([{files_rec, ["ebin"]}, {init_plt, Plt}]) of + FromSrc = proplists:get_bool(src, rebar_config:get(Config, + dialyzer_opts, + [])), + DialyzerOpts0 = case FromSrc of + true -> + [{files_rec, ["src"]}, {init_plt, Plt}, + {from, src_code}]; + false -> + [{files_rec, ["ebin"]}, {init_plt, Plt}] + end, + WarnOpts = warnings(Config), + DialyzerOpts = case WarnOpts of + [] -> DialyzerOpts0; + _ -> [{warnings, WarnOpts}|DialyzerOpts0] + end, + ?DEBUG("DialyzerOpts: ~p~n", [DialyzerOpts]), + try dialyzer:run(DialyzerOpts) of Warnings -> output_warnings(Warnings) catch throw:{dialyzer_error, Reason} -> ?ABORT("~s~n", [Reason]) end; {error, no_such_file} -> - ?ABORT("The PLT ~s does not exist. Please perform the build_plt command to ~n" - "produce the initial PLT. Be aware this operation may take several minutes.", [Plt]); + ?ABORT("The PLT ~s does not exist. Please perform the build-plt " + "command to ~n" + "produce the initial PLT. Be aware that this operation may " + "take several minutes.~n", [Plt]); {error, read_error} -> ?ABORT("Unable to read PLT ~n~n", [Plt]); {error, not_valid} -> @@ -80,29 +98,30 @@ analyze(Config, File) -> ok. %% @doc Build the PLT. -%% @spec build_plt(Config::#config{}, File::string()) -> ok --spec(build_plt(Config::#config{}, File::string()) -> ok). -build_plt(Config, File) -> - Plt = plt_path(Config, File), +%% @spec build-plt(Config::#config{}, File::string()) -> ok +-spec 'build-plt'(Config::#config{}, File::string()) -> ok. +'build-plt'(Config, File) -> + Plt = new_plt_path(Config, File), Apps = rebar_app_utils:app_applications(File), + ?DEBUG("Build PLT ~s including following apps:~n~p~n", [Plt, Apps]), Warnings = dialyzer:run([{analysis_type, plt_build}, {files_rec, app_dirs(Apps)}, {output_plt, Plt}]), case Warnings of [] -> - ?INFO("The built PLT can be found in ~s", [Plt]); + ?INFO("The built PLT can be found in ~s~n", [Plt]); _ -> output_warnings(Warnings) end, ok. %% @doc Check whether the PLT is up-to-date (rebuilding it if not). -%% @spec check_plt(Config::#config{}, File::string()) -> ok --spec(check_plt(Config::#config{}, File::string()) -> ok). -check_plt(Config, File) -> - Plt = plt_path(Config, File), +%% @spec check-plt(Config::#config{}, File::string()) -> ok +-spec 'check-plt'(Config::#config{}, File::string()) -> ok. +'check-plt'(Config, File) -> + Plt = existing_plt_path(Config, File), try dialyzer:run([{analysis_type, plt_check}, {init_plt, Plt}]) of [] -> ?CONSOLE("The PLT ~s is up-to-date~n", [Plt]); @@ -121,14 +140,14 @@ check_plt(Config, File) -> %% @doc Obtain the library paths for the supplied applications. %% @spec app_dirs(Apps::[atom()]) -> [string()] --spec(app_dirs(Apps::[atom()]) -> [string()]). +-spec app_dirs(Apps::[atom()]) -> [string()]. app_dirs(Apps) -> [filename:join(Path, "ebin") || Path <- lists:map(fun(App) -> code:lib_dir(App) end, Apps), erlang:is_list(Path)]. %% @doc Render the warnings on the console. %% @spec output_warnings(Warnings::[warning()]) -> 'ok' --spec(output_warnings(Warnings::[warning()]) -> 'ok'). +-spec output_warnings(Warnings::[warning()]) -> 'ok'. output_warnings(Warnings) -> lists:foreach(fun(Warning) -> ?CONSOLE("~s", [dialyzer:format_warning(Warning)]) @@ -136,14 +155,52 @@ output_warnings(Warnings) -> %% @doc If the plt option is present in rebar.config return its value, otherwise %% return $HOME/.dialyzer_plt. -%% @spec plt_path(Config::#config{}, File::string()) -> string() --spec(plt_path(Config::#config{}, File::string()) -> string()). -plt_path(Config, File) -> +%% @spec new_plt_path(Config::#config{}, File::string()) -> string() +-spec new_plt_path(Config::#config{}, File::string()) -> string(). +new_plt_path(Config, File) -> AppName = rebar_app_utils:app_name(File), DialyzerOpts = rebar_config:get(Config, dialyzer_opts, []), case proplists:get_value(plt, DialyzerOpts) of undefined -> - filename:join(os:getenv("HOME"), "." ++ atom_to_list(AppName) ++ "_dialyzer_plt"); + filename:join(os:getenv("HOME"), + "." ++ atom_to_list(AppName) ++ "_dialyzer_plt"); Plt -> Plt end. + +%% @doc If the plt option is present in rebar.config and the file exists +%% return its value or if ~/.AppName_dialyzer_plt exists return that. +%% Otherwise return ~/.dialyzer_plt if it exists or abort. +%% @spec existing_plt_path(Config::#config{}, File::string()) -> string() +-spec existing_plt_path(Config::#config{}, File::string()) -> string(). +existing_plt_path(Config, File) -> + AppName = rebar_app_utils:app_name(File), + DialyzerOpts = rebar_config:get(Config, dialyzer_opts, []), + Home = os:getenv("HOME"), + case proplists:get_value(plt, DialyzerOpts) of + undefined -> + AppPlt = filename:join(Home, "." ++ atom_to_list(AppName) + ++ "_dialyzer_plt"), + case filelib:is_regular(AppPlt) of + true -> + AppPlt; + false -> + HomePlt = filename:join(Home, ".dialyzer_plt"), + case filelib:is_regular(HomePlt) of + true -> + HomePlt; + false -> + ?ABORT("No PLT found~n", []) + end + end; + Plt -> + Plt + end. + +%% @doc If the warnings option is present in rebar.config return its value, +%% otherwise return []. +%% @spec warnings(Config::#config{}) -> list(). +-spec warnings(Config::#config{}) -> list(). +warnings(Config) -> + DialyzerOpts = rebar_config:get(Config, dialyzer_opts, []), + proplists:get_value(warnings, DialyzerOpts, []). -- cgit v1.2.1