Skip to content

Commit

Permalink
Merge branch 'ks/dialyzer/support-multiple-plts' into dev
Browse files Browse the repository at this point in the history
* ks/dialyzer/support-multiple-plts:
  dialyzer: Add support for multiple PLTs

OTP-8962
  • Loading branch information
psyeugenic committed Dec 2, 2010
2 parents 1333819 + f1d81c8 commit 4c24c02
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 79 deletions.
12 changes: 9 additions & 3 deletions lib/dialyzer/doc/manual.txt
Expand Up @@ -123,9 +123,10 @@ The exit status of the command line version is:


Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose]
[-pa dir]* [--plt plt] [-Ddefine]* [-I include_dir]*
[--output_plt file] [-Wwarn]* [--src] [--gui | --wx]
[files_or_dirs] [-r dirs] [--apps applications] [-o outfile]
[-pa dir]* [--plt plt] [--plts plts] [-Ddefine]*
[-I include_dir]* [--output_plt file] [-Wwarn]*
[--src] [--gui | --wx] [files_or_dirs] [-r dirs]
[--apps applications] [-o outfile]
[--build_plt] [--add_to_plt] [--remove_from_plt]
[--check_plt] [--no_check_plt] [--plt_info] [--get_warnings]
[--no_native]
Expand Down Expand Up @@ -167,6 +168,10 @@ Options:
--plt plt
Use the specified plt as the initial plt (if the plt was built
during setup the files will be checked for consistency)
--plts plts
Merges the specified plts to create the initial plt -- requires
that the plts are disjoint (i.e., do not have any module
appearing in more than one plt)
-Wwarn
A family of options which selectively turn on/off warnings
(for help on the names of warnings use dialyzer -Whelp)
Expand Down Expand Up @@ -294,6 +299,7 @@ Option :: {files, [Filename :: string()]}
| {defines, [{Macro :: atom(), Value :: term()}]}
| {from, src_code | byte_code} %% Defaults to byte_code
| {init_plt, FileName :: string()} %% If changed from default
| {plts, [FileName :: string()]} %% If changed from default
| {include_dirs, [DirName :: string()]}
| {output_file, FileName :: string()}
| {output_plt, FileName :: string()}
Expand Down
20 changes: 14 additions & 6 deletions lib/dialyzer/src/dialyzer.erl
Expand Up @@ -106,27 +106,35 @@ cl_print_plt_info(Opts) ->
end,
doit(F).

print_plt_info(#options{init_plt = PLT, output_file = OutputFile}) ->
print_plt_info(#options{init_plts = PLTs, output_file = OutputFile}) ->
PLTInfo = get_plt_info(PLTs),
do_print_plt_info(PLTInfo, OutputFile).

get_plt_info([PLT|PLTs]) ->
String =
case dialyzer_plt:included_files(PLT) of
{ok, Files} ->
io_lib:format("The PLT ~s includes the following files:\n~p\n",
io_lib:format("The PLT ~s includes the following files:\n~p\n\n",
[PLT, Files]);
{error, read_error} ->
Msg = io_lib:format("Could not read the PLT file ~p\n", [PLT]),
Msg = io_lib:format("Could not read the PLT file ~p\n\n", [PLT]),
throw({dialyzer_error, Msg});
{error, no_such_file} ->
Msg = io_lib:format("The PLT file ~p does not exist\n", [PLT]),
Msg = io_lib:format("The PLT file ~p does not exist\n\n", [PLT]),
throw({dialyzer_error, Msg})
end,
String ++ get_plt_info(PLTs);
get_plt_info([]) -> "".

do_print_plt_info(PLTInfo, OutputFile) ->
case OutputFile =:= none of
true ->
io:format("~s", [String]),
io:format("~s", [PLTInfo]),
?RET_NOTHING_SUSPICIOUS;
false ->
case file:open(OutputFile, [write]) of
{ok, FileDesc} ->
io:format(FileDesc, "~s", [String]),
io:format(FileDesc, "~s", [PLTInfo]),
ok = file:close(FileDesc),
?RET_NOTHING_SUSPICIOUS;
{error, Reason} ->
Expand Down
2 changes: 1 addition & 1 deletion lib/dialyzer/src/dialyzer.hrl
Expand Up @@ -129,7 +129,7 @@
defines = [] :: [dial_define()],
from = byte_code :: start_from(),
get_warnings = maybe :: boolean() | 'maybe',
init_plt = none :: 'none' | file:filename(),
init_plts = [] :: [file:filename()],
include_dirs = [] :: [file:filename()],
output_plt = none :: 'none' | file:filename(),
legal_warnings = ordsets:new() :: ordset(dial_warn_tag()),
Expand Down
120 changes: 80 additions & 40 deletions lib/dialyzer/src/dialyzer_cl.erl
Expand Up @@ -81,11 +81,15 @@ build_plt(Opts) ->
init_opts_for_build(Opts) ->
case Opts#options.output_plt =:= none of
true ->
case Opts#options.init_plt of
none -> Opts#options{init_plt = none, output_plt = get_default_plt()};
Plt -> Opts#options{init_plt = none, output_plt = Plt}
case Opts#options.init_plts of
[] -> Opts#options{output_plt = get_default_output_plt()};
[Plt] -> Opts#options{init_plts = [], output_plt = Plt};
Plts ->
Msg = io_lib:format("Could not build multiple PLT files: ~s\n",
[format_plts(Plts)]),
error(Msg)
end;
false -> Opts#options{init_plt = none}
false -> Opts#options{init_plts = []}
end.

%%--------------------------------------------------------------------
Expand All @@ -98,39 +102,58 @@ add_to_plt(Opts) ->
init_opts_for_add(Opts) ->
case Opts#options.output_plt =:= none of
true ->
case Opts#options.init_plt of
none -> Opts#options{output_plt = get_default_plt(),
init_plt = get_default_plt()};
Plt -> Opts#options{output_plt = Plt}
case Opts#options.init_plts of
[] -> Opts#options{output_plt = get_default_output_plt(),
init_plts = get_default_init_plt()};
[Plt] -> Opts#options{output_plt = Plt};
Plts ->
Msg = io_lib:format("Could not add to multiple PLT files: ~s\n",
[format_plts(Plts)]),
error(Msg)
end;
false ->
case Opts#options.init_plt =:= none of
true -> Opts#options{init_plt = get_default_plt()};
case Opts#options.init_plts =:= [] of
true -> Opts#options{init_plts = get_default_init_plt()};
false -> Opts
end
end.

%%--------------------------------------------------------------------

check_plt(Opts) ->
check_plt(#options{init_plts = []} = Opts) ->
Opts1 = init_opts_for_check(Opts),
report_check(Opts),
plt_common(Opts1, [], []).
report_check(Opts1),
plt_common(Opts1, [], []);
check_plt(#options{init_plts = Plts} = Opts) ->
check_plt_aux(Plts, Opts).

check_plt_aux([_] = Plt, Opts) ->
Opts1 = Opts#options{init_plts = Plt},
Opts2 = init_opts_for_check(Opts1),
report_check(Opts2),
plt_common(Opts2, [], []);
check_plt_aux([Plt|Plts], Opts) ->
Opts1 = Opts#options{init_plts = [Plt]},
Opts2 = init_opts_for_check(Opts1),
report_check(Opts2),
plt_common(Opts2, [], []),
check_plt_aux(Plts, Opts).

init_opts_for_check(Opts) ->
Plt =
case Opts#options.init_plt of
none -> get_default_plt();
Plt0 -> Plt0
InitPlt =
case Opts#options.init_plts of
[]-> get_default_init_plt();
Plt -> Plt
end,
[OutputPlt] = InitPlt,
Opts#options{files = [],
files_rec = [],
analysis_type = plt_check,
defines = [],
from = byte_code,
init_plt = Plt,
init_plts = InitPlt,
include_dirs = [],
output_plt = Plt,
output_plt = OutputPlt,
use_contracts = true
}.

Expand All @@ -144,21 +167,25 @@ remove_from_plt(Opts) ->
init_opts_for_remove(Opts) ->
case Opts#options.output_plt =:= none of
true ->
case Opts#options.init_plt of
none -> Opts#options{output_plt = get_default_plt(),
init_plt = get_default_plt()};
Plt -> Opts#options{output_plt = Plt}
case Opts#options.init_plts of
[] -> Opts#options{output_plt = get_default_output_plt(),
init_plts = get_default_init_plt()};
[Plt] -> Opts#options{output_plt = Plt};
Plts ->
Msg = io_lib:format("Could not remove from multiple PLT files: ~s\n",
[format_plts(Plts)]),
error(Msg)
end;
false ->
case Opts#options.init_plt =:= none of
true -> Opts#options{init_plt = get_default_plt()};
case Opts#options.init_plts =:= [] of
true -> Opts#options{init_plts = get_default_init_plt()};
false -> Opts
end
end.

%%--------------------------------------------------------------------

plt_common(Opts, RemoveFiles, AddFiles) ->
plt_common(#options{init_plts = [InitPlt]} = Opts, RemoveFiles, AddFiles) ->
case check_plt(Opts, RemoveFiles, AddFiles) of
ok ->
case Opts#options.report_mode of
Expand All @@ -174,7 +201,7 @@ plt_common(Opts, RemoveFiles, AddFiles) ->
report_failed_plt_check(Opts, DiffMd5),
{AnalFiles, RemovedMods, ModDeps1} =
expand_dependent_modules(Md5, DiffMd5, ModDeps),
Plt = clean_plt(Opts#options.init_plt, RemovedMods),
Plt = clean_plt(InitPlt, RemovedMods),
case AnalFiles =:= [] of
true ->
%% Only removed stuff. Just write the PLT.
Expand All @@ -186,19 +213,19 @@ plt_common(Opts, RemoveFiles, AddFiles) ->
end;
{error, no_such_file} ->
Msg = io_lib:format("Could not find the PLT: ~s\n~s",
[Opts#options.init_plt, default_plt_error_msg()]),
[InitPlt, default_plt_error_msg()]),
error(Msg);
{error, not_valid} ->
Msg = io_lib:format("The file: ~s is not a valid PLT file\n~s",
[Opts#options.init_plt, default_plt_error_msg()]),
[InitPlt, default_plt_error_msg()]),
error(Msg);
{error, read_error} ->
Msg = io_lib:format("Could not read the PLT: ~s\n~s",
[Opts#options.init_plt, default_plt_error_msg()]),
[InitPlt, default_plt_error_msg()]),
error(Msg);
{error, {no_file_to_remove, F}} ->
Msg = io_lib:format("Could not remove the file ~s from the PLT: ~s\n",
[F, Opts#options.init_plt]),
[F, InitPlt]),
error(Msg)
end.

Expand All @@ -218,8 +245,7 @@ default_plt_error_msg() ->

%%--------------------------------------------------------------------

check_plt(Opts, RemoveFiles, AddFiles) ->
Plt = Opts#options.init_plt,
check_plt(#options{init_plts = [Plt]} = Opts, RemoveFiles, AddFiles) ->
case dialyzer_plt:check_plt(Plt, RemoveFiles, AddFiles) of
{old_version, _MD5} = OldVersion ->
report_old_version(Opts),
Expand All @@ -234,14 +260,14 @@ check_plt(Opts, RemoveFiles, AddFiles) ->

%%--------------------------------------------------------------------

report_check(#options{report_mode = ReportMode, init_plt = InitPlt}) ->
report_check(#options{report_mode = ReportMode, init_plts = [InitPlt]}) ->
case ReportMode of
quiet -> ok;
_ ->
io:format(" Checking whether the PLT ~s is up-to-date...", [InitPlt])
end.

report_old_version(#options{report_mode = ReportMode, init_plt = InitPlt}) ->
report_old_version(#options{report_mode = ReportMode, init_plts = [InitPlt]}) ->
case ReportMode of
quiet -> ok;
_ ->
Expand All @@ -264,14 +290,15 @@ report_failed_plt_check(#options{analysis_type = AnalType,

report_analysis_start(#options{analysis_type = Type,
report_mode = ReportMode,
init_plt = InitPlt,
init_plts = InitPlts,
output_plt = OutputPlt}) ->
case ReportMode of
quiet -> ok;
_ ->
io:format(" "),
case Type of
plt_add ->
[InitPlt] = InitPlts,
case InitPlt =:= OutputPlt of
true -> io:format("Adding information to ~s...", [OutputPlt]);
false -> io:format("Adding information from ~s to ~s...",
Expand All @@ -282,6 +309,7 @@ report_analysis_start(#options{analysis_type = Type,
plt_check ->
io:format("Rebuilding the information in ~s...", [OutputPlt]);
plt_remove ->
[InitPlt] = InitPlts,
case InitPlt =:= OutputPlt of
true -> io:format("Removing information from ~s...", [OutputPlt]);
false -> io:format("Removing information from ~s to ~s...",
Expand Down Expand Up @@ -320,16 +348,28 @@ report_md5_diff(List) ->

%%--------------------------------------------------------------------

get_default_plt() ->
get_default_init_plt() ->
[dialyzer_plt:get_default_plt()].

get_default_output_plt() ->
dialyzer_plt:get_default_plt().

%%--------------------------------------------------------------------

format_plts([Plt]) -> Plt;
format_plts([Plt|Plts]) ->
Plt ++ ", " ++ format_plts(Plts).

%%--------------------------------------------------------------------

do_analysis(Options) ->
Files = get_files_from_opts(Options),
case Options#options.init_plt of
none -> do_analysis(Files, Options, dialyzer_plt:new(), none);
File -> do_analysis(Files, Options, dialyzer_plt:from_file(File), none)
case Options#options.init_plts of
[] -> do_analysis(Files, Options, dialyzer_plt:new(), none);
PltFiles ->
Plts = [dialyzer_plt:from_file(F) || F <- PltFiles],
Plt = dialyzer_plt:merge_plts_or_report_conflicts(PltFiles, Plts),
do_analysis(Files, Options, Plt, none)
end.

do_analysis(Files, Options, Plt, PltInfo) ->
Expand Down

0 comments on commit 4c24c02

Please sign in to comment.