aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/src/dialyzer_options.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/src/dialyzer_options.erl')
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl269
1 files changed, 269 insertions, 0 deletions
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
new file mode 100644
index 0000000000..6531073072
--- /dev/null
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -0,0 +1,269 @@
+%% -*- erlang-indent-level: 2 -*-
+%%-----------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%----------------------------------------------------------------------
+%%% File : dialyzer_options.erl
+%%% Authors : Richard Carlsson <[email protected]>
+%%% Description : Provides a better way to start Dialyzer from a script.
+%%%
+%%% Created : 17 Oct 2004 by Richard Carlsson <[email protected]>
+%%%----------------------------------------------------------------------
+
+-module(dialyzer_options).
+
+-export([build/1]).
+
+-include("dialyzer.hrl").
+
+%%-----------------------------------------------------------------------
+
+-spec build(dial_options()) -> #options{} | {'error', string()}.
+
+build(Opts) ->
+ DefaultWarns = [?WARN_RETURN_NO_RETURN,
+ ?WARN_NOT_CALLED,
+ ?WARN_NON_PROPER_LIST,
+ ?WARN_FUN_APP,
+ ?WARN_MATCHING,
+ ?WARN_OPAQUE,
+ ?WARN_CALLGRAPH,
+ ?WARN_FAILING_CALL,
+ ?WARN_BIN_CONSTRUCTION,
+ ?WARN_CALLGRAPH,
+ ?WARN_CONTRACT_TYPES,
+ ?WARN_CONTRACT_SYNTAX],
+ DefaultWarns1 = ordsets:from_list(DefaultWarns),
+ InitPlt = dialyzer_plt:get_default_plt(),
+ DefaultOpts = #options{},
+ DefaultOpts1 = DefaultOpts#options{legal_warnings = DefaultWarns1,
+ init_plt = InitPlt},
+ try
+ NewOpts = build_options(Opts, DefaultOpts1),
+ postprocess_opts(NewOpts)
+ catch
+ throw:{dialyzer_options_error, Msg} -> {error, Msg}
+ end.
+
+postprocess_opts(Opts = #options{}) ->
+ Opts1 = check_output_plt(Opts),
+ adapt_get_warnings(Opts1).
+
+check_output_plt(Opts = #options{analysis_type = Mode, from = From,
+ output_plt = OutPLT}) ->
+ case is_plt_mode(Mode) of
+ true ->
+ case From =:= byte_code of
+ true -> Opts;
+ false ->
+ Msg = "Byte code compiled with debug_info is needed to build the PLT",
+ throw({dialyzer_error, Msg})
+ end;
+ false ->
+ case OutPLT =:= none of
+ true -> Opts;
+ false ->
+ Msg = io_lib:format("Output PLT cannot be specified "
+ "in analysis mode ~w", [Mode]),
+ throw({dialyzer_error, lists:flatten(Msg)})
+ end
+ end.
+
+adapt_get_warnings(Opts = #options{analysis_type = Mode,
+ get_warnings = Warns}) ->
+ %% Warnings are off by default in plt mode, and on by default in
+ %% success typings mode. User defined warning mode overrides the
+ %% default.
+ case is_plt_mode(Mode) of
+ true ->
+ case Warns =:= maybe of
+ true -> Opts#options{get_warnings = false};
+ false -> Opts
+ end;
+ false ->
+ case Warns =:= maybe of
+ true -> Opts#options{get_warnings = true};
+ false -> Opts
+ end
+ end.
+
+-spec bad_option(string(), term()) -> no_return().
+
+bad_option(String, Term) ->
+ Msg = io_lib:format("~s: ~P", [String, Term, 25]),
+ throw({dialyzer_options_error, lists:flatten(Msg)}).
+
+build_options([{OptName, undefined}|Rest], Options) when is_atom(OptName) ->
+ build_options(Rest, Options);
+build_options([{OptionName, Value} = Term|Rest], Options) ->
+ case OptionName of
+ files ->
+ assert_filenames(Term, Value),
+ build_options(Rest, Options#options{files = Value});
+ files_rec ->
+ assert_filenames(Term, Value),
+ build_options(Rest, Options#options{files_rec = Value});
+ analysis_type ->
+ NewOptions =
+ case Value of
+ succ_typings -> Options#options{analysis_type = Value};
+ plt_add -> Options#options{analysis_type = Value};
+ plt_build -> Options#options{analysis_type = Value};
+ plt_check -> Options#options{analysis_type = Value};
+ plt_remove -> Options#options{analysis_type = Value};
+ dataflow -> bad_option("Analysis type is no longer supported", Term);
+ old_style -> bad_option("Analysis type is no longer supported", Term);
+ Other -> bad_option("Unknown analysis type", Other)
+ end,
+ assert_plt_op(Options, NewOptions),
+ build_options(Rest, NewOptions);
+ check_plt when is_boolean(Value) ->
+ build_options(Rest, Options#options{check_plt = Value});
+ defines ->
+ assert_defines(Term, Value),
+ OldVal = Options#options.defines,
+ NewVal = ordsets:union(ordsets:from_list(Value), OldVal),
+ build_options(Rest, Options#options{defines = NewVal});
+ from when Value =:= byte_code; Value =:= src_code ->
+ build_options(Rest, Options#options{from = Value});
+ get_warnings ->
+ build_options(Rest, Options#options{get_warnings = Value});
+ init_plt ->
+ assert_filenames([Term], [Value]),
+ build_options(Rest, Options#options{init_plt = Value});
+ include_dirs ->
+ assert_filenames(Term, Value),
+ OldVal = Options#options.include_dirs,
+ NewVal = ordsets:union(ordsets:from_list(Value), OldVal),
+ build_options(Rest, Options#options{include_dirs = NewVal});
+ use_spec ->
+ build_options(Rest, Options#options{use_contracts = Value});
+ old_style ->
+ bad_option("Analysis type is no longer supported", old_style);
+ output_file ->
+ assert_filename(Value),
+ build_options(Rest, Options#options{output_file = Value});
+ output_format ->
+ assert_output_format(Value),
+ build_options(Rest, Options#options{output_format = Value});
+ output_plt ->
+ assert_filename(Value),
+ build_options(Rest, Options#options{output_plt = Value});
+ report_mode ->
+ build_options(Rest, Options#options{report_mode = Value});
+ erlang_mode ->
+ build_options(Rest, Options#options{erlang_mode = true});
+ warnings ->
+ NewWarnings = build_warnings(Value, Options#options.legal_warnings),
+ build_options(Rest, Options#options{legal_warnings = NewWarnings});
+ callgraph_file ->
+ assert_filename(Value),
+ build_options(Rest, Options#options{callgraph_file = Value});
+ _ ->
+ bad_option("Unknown dialyzer command line option", Term)
+ end;
+build_options([], Options) ->
+ Options.
+
+assert_filenames(Term, [FileName|Left]) when length(FileName) >= 0 ->
+ case filelib:is_file(FileName) orelse filelib:is_dir(FileName) of
+ true -> ok;
+ false -> bad_option("No such file or directory", FileName)
+ end,
+ assert_filenames(Term, Left);
+assert_filenames(_Term, []) ->
+ ok;
+assert_filenames(Term, [_|_]) ->
+ bad_option("Malformed or non-existing filename", Term).
+
+assert_filename(FileName) when length(FileName) >= 0 ->
+ ok;
+assert_filename(FileName) ->
+ bad_option("Malformed or non-existing filename", FileName).
+
+assert_defines(Term, [{Macro, _Value}|Defs]) when is_atom(Macro) ->
+ assert_defines(Term, Defs);
+assert_defines(_Term, []) ->
+ ok;
+assert_defines(Term, [_|_]) ->
+ bad_option("Malformed define", Term).
+
+assert_output_format(raw) ->
+ ok;
+assert_output_format(formatted) ->
+ ok;
+assert_output_format(Term) ->
+ bad_option("Illegal value for output_format", Term).
+
+assert_plt_op(#options{analysis_type = OldVal},
+ #options{analysis_type = NewVal}) ->
+ case is_plt_mode(OldVal) andalso is_plt_mode(NewVal) of
+ true -> bad_option("Options cannot be combined", [OldVal, NewVal]);
+ false -> ok
+ end.
+
+is_plt_mode(plt_add) -> true;
+is_plt_mode(plt_build) -> true;
+is_plt_mode(plt_remove) -> true;
+is_plt_mode(plt_check) -> true;
+is_plt_mode(succ_typings) -> false.
+
+-spec build_warnings([atom()], [dial_warning()]) -> [dial_warning()].
+
+build_warnings([Opt|Opts], Warnings) ->
+ NewWarnings =
+ case Opt of
+ no_return ->
+ ordsets:del_element(?WARN_RETURN_NO_RETURN, Warnings);
+ no_unused ->
+ ordsets:del_element(?WARN_NOT_CALLED, Warnings);
+ no_improper_lists ->
+ ordsets:del_element(?WARN_NON_PROPER_LIST, Warnings);
+ no_fun_app ->
+ ordsets:del_element(?WARN_FUN_APP, Warnings);
+ no_match ->
+ ordsets:del_element(?WARN_MATCHING, Warnings);
+ no_opaque ->
+ ordsets:del_element(?WARN_OPAQUE, Warnings);
+ no_fail_call ->
+ ordsets:del_element(?WARN_FAILING_CALL, Warnings);
+ no_contracts ->
+ Warnings1 = ordsets:del_element(?WARN_CONTRACT_SYNTAX, Warnings),
+ ordsets:del_element(?WARN_CONTRACT_TYPES, Warnings1);
+ unmatched_returns ->
+ ordsets:add_element(?WARN_UNMATCHED_RETURN, Warnings);
+ error_handling ->
+ ordsets:add_element(?WARN_RETURN_ONLY_EXIT, Warnings);
+ race_conditions ->
+ ordsets:add_element(?WARN_RACE_CONDITION, Warnings);
+ specdiffs ->
+ S = ordsets:from_list([?WARN_CONTRACT_SUBTYPE,
+ ?WARN_CONTRACT_SUPERTYPE,
+ ?WARN_CONTRACT_NOT_EQUAL]),
+ ordsets:union(S, Warnings);
+ overspecs ->
+ ordsets:add_element(?WARN_CONTRACT_SUBTYPE, Warnings);
+ underspecs ->
+ ordsets:add_element(?WARN_CONTRACT_SUPERTYPE, Warnings);
+ OtherAtom ->
+ bad_option("Unknown dialyzer warning option", OtherAtom)
+ end,
+ build_warnings(Opts, NewWarnings);
+build_warnings([], Warnings) ->
+ Warnings.