diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/typer/src/Makefile | 9 | ||||
-rw-r--r-- | lib/typer/src/typer.erl | 176 | ||||
-rw-r--r-- | lib/typer/src/typer_options.erl | 194 |
3 files changed, 169 insertions, 210 deletions
diff --git a/lib/typer/src/Makefile b/lib/typer/src/Makefile index 76cd557cc8..f814e943ea 100644 --- a/lib/typer/src/Makefile +++ b/lib/typer/src/Makefile @@ -47,8 +47,7 @@ DIALYZER_DIR = $(ERL_TOP)/lib/dialyzer # ---------------------------------------------------- MODULES = typer \ typer_annotator \ - typer_info \ - typer_options + typer_info HRL_FILES= typer.hrl ERL_FILES= $(MODULES:%=%.erl) @@ -84,8 +83,8 @@ clean: # Special Build Targets # ---------------------------------------------------- -$(EBIN)/typer_options.$(EMULATOR): typer_options.erl ../vsn.mk Makefile - erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) typer_options.erl +$(EBIN)/typer.$(EMULATOR): typer.erl ../vsn.mk Makefile + erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) typer.erl $(APP_TARGET): $(APP_SRC) ../vsn.mk sed -e 's;%VSN%;$(VSN);' $< > $@ @@ -100,8 +99,6 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk $(EBIN)/typer.beam: typer.hrl $(EBIN)/typer_annotator.beam: typer.hrl $(EBIN)/typer_info.beam: typer.hrl -$(EBIN)/typer_options.beam: typer.hrl -$(EBIN)/typer_preprocess.beam: typer.hrl # ---------------------------------------------------- # Release Target diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl index 3f1302ecc9..54818553da 100644 --- a/lib/typer/src/typer.erl +++ b/lib/typer/src/typer.erl @@ -80,7 +80,7 @@ -spec start() -> no_return(). start() -> - {Args, Analysis} = typer_options:process(), + {Args, Analysis} = process_cl_args(), %% io:format("Args: ~p\n", [Args]), %% io:format("Analysis: ~p\n", [Analysis]), TrustedFiles = filter_fd(Args#args.trusted, [], fun is_erl_file/1), @@ -189,8 +189,7 @@ remove_external(CallGraph, PLT) -> ExtTypes = rcv_ext_types(), case ExtTypes of [] -> ok; - _ -> - msg(io_lib:format(" Unknown types: ~p\n", [ExtTypes])) + _ -> msg(io_lib:format(" Unknown types: ~p\n", [ExtTypes])) end end, StrippedCG. @@ -211,12 +210,113 @@ get_external(Exts, Plt) -> lists:foldl(Fun, [], Exts). %%-------------------------------------------------------------------- +%% Processing of command-line options and arguments. +%%-------------------------------------------------------------------- + +-spec process_cl_args() -> {#args{}, #typer_analysis{}}. + +process_cl_args() -> + ArgList = init:get_plain_arguments(), + %% io:format("Args is ~p\n", [ArgList]), + {Args, Analysis} = analyze_args(ArgList, #args{}, #typer_analysis{}), + %% if the mode has not been set, set it to the default mode (show) + {Args, case Analysis#typer_analysis.mode of + undefined -> Analysis#typer_analysis{mode = ?SHOW}; + Mode when is_atom(Mode) -> Analysis + end}. + +analyze_args([], Args, Analysis) -> + {Args, Analysis}; +analyze_args(ArgList, Args, Analysis) -> + {Result, Rest} = cl(ArgList), + {NewArgs, NewAnalysis} = analyze_result(Result, Args, Analysis), + analyze_args(Rest, NewArgs, NewAnalysis). + +cl(["-h"|_]) -> help_message(); +cl(["--help"|_]) -> help_message(); +cl(["-v"|_]) -> version_message(); +cl(["--version"|_]) -> version_message(); +cl(["--comments"|Opts]) -> {comments, Opts}; +cl(["--show"|Opts]) -> {{mode, ?SHOW}, Opts}; +cl(["--show_exported"|Opts]) -> {{mode, ?SHOW_EXPORTED}, Opts}; +cl(["--show-exported"|Opts]) -> {{mode, ?SHOW_EXPORTED}, Opts}; +cl(["--annotate"|Opts]) -> {{mode, ?ANNOTATE}, Opts}; +cl(["--annotate-inc-files"|Opts]) -> {{mode, ?ANNOTATE_INC_FILES}, Opts}; +cl(["--no_spec"|Opts]) -> {no_spec, Opts}; +cl(["--plt",Plt|Opts]) -> {{plt, Plt}, Opts}; +cl(["-D"++Def|Opts]) -> + case Def of + "" -> fatal_error("no variable name specified after -D"); + _ -> + DefPair = process_def_list(re:split(Def, "=", [{return, list}])), + {{def, DefPair}, Opts} + end; +cl(["-I",Dir|Opts]) -> {{inc, Dir}, Opts}; +cl(["-I"++Dir|Opts]) -> + case Dir of + "" -> fatal_error("no include directory specified after -I"); + _ -> {{inc, Dir}, Opts} + end; +cl(["-T"|Opts]) -> + {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), + case Files of + [] -> fatal_error("no file or directory specified after -T"); + [_|_] -> {{trusted, Files}, RestOpts} + end; +cl(["-r"|Opts]) -> + {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), + {{files_r, Files}, RestOpts}; +cl(["-"++H|_]) -> fatal_error("unknown option -"++H); +cl(Opts) -> + {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), + {{files, Files}, RestOpts}. + +process_def_list(L) -> + case L of + [Name, Value] -> + {ok, Tokens, _} = erl_scan:string(Value ++ "."), + {ok, ErlValue} = erl_parse:parse_term(Tokens), + {list_to_atom(Name), ErlValue}; + [Name] -> + {list_to_atom(Name), true} + end. + +%% Get information about files that the user trusts and wants to analyze +analyze_result({files, Val}, Args, Analysis) -> + NewVal = Args#args.files ++ Val, + {Args#args{files = NewVal}, Analysis}; +analyze_result({files_r, Val}, Args, Analysis) -> + NewVal = Args#args.files_r ++ Val, + {Args#args{files_r = NewVal}, Analysis}; +analyze_result({trusted, Val}, Args, Analysis) -> + NewVal = Args#args.trusted ++ Val, + {Args#args{trusted = NewVal}, Analysis}; +analyze_result(comments, Args, Analysis) -> + {Args, Analysis#typer_analysis{contracts = false}}; +%% Get useful information for actual analysis +analyze_result({mode, Mode}, Args, Analysis) -> + case Analysis#typer_analysis.mode of + undefined -> {Args, Analysis#typer_analysis{mode = Mode}}; + OldMode -> mode_error(OldMode, Mode) + end; +analyze_result({def, Val}, Args, Analysis) -> + NewVal = Analysis#typer_analysis.macros ++ [Val], + {Args, Analysis#typer_analysis{macros = NewVal}}; +analyze_result({inc, Val}, Args, Analysis) -> + NewVal = Analysis#typer_analysis.includes ++ [Val], + {Args, Analysis#typer_analysis{includes = NewVal}}; +analyze_result({plt, Plt}, Args, Analysis) -> + {Args, Analysis#typer_analysis{plt = Plt}}; +analyze_result(no_spec, Args, Analysis) -> + {Args, Analysis#typer_analysis{no_spec = true}}. + +%%-------------------------------------------------------------------- %% File processing. %%-------------------------------------------------------------------- -spec get_all_files(#args{}) -> files(). -get_all_files(#args{files = Fs,files_r = Ds}) -> +get_all_files(#args{files = Fs, files_r = Ds}) -> case filter_fd(Fs, Ds, fun test_erl_file_exclude_ann/1) of [] -> fatal_error("no file(s) to analyze"); AllFiles -> AllFiles @@ -313,12 +413,7 @@ split_dirs_and_files(Elems, Dir) -> {Dirs, Files} = lists:foldl(Test_Fun, {[], []}, Elems), {lists:reverse(Dirs), lists:reverse(Files)}. -%%----------------------------------------------------------------------- -%% Utilities -%%----------------------------------------------------------------------- - -%% Removes duplicate filenames but it keeps the order of the input list - +%% Removes duplicate filenames but keeps the order of the input list -spec remove_dup(files()) -> files(). remove_dup(Files) -> @@ -341,6 +436,13 @@ fatal_error(Slogan) -> msg(io_lib:format("typer: ~s\n", [Slogan])), erlang:halt(1). +-spec mode_error(mode(), mode()) -> no_return(). +mode_error(OldMode, NewMode) -> + Msg = io_lib:format("Mode was previously set to '~s'; " + "can not set it to '~s' now", + [OldMode, NewMode]), + fatal_error(Msg). + -spec compile_error([string()]) -> no_return(). compile_error(Reason) -> @@ -362,6 +464,60 @@ msg(Msg) -> end. %%-------------------------------------------------------------------- +%% Version and help messages. +%%-------------------------------------------------------------------- + +-spec version_message() -> no_return(). +version_message() -> + io:format("TypEr version "++?VSN++"\n"), + erlang:halt(0). + +-spec help_message() -> no_return(). +help_message() -> + S = " Usage: typer [--help] [--version] [--comments] [--plt PLT] + [--show | --show-exported | --annotate | --annotate-inc-files] + [-Ddefine]* [-I include_dir]* [-T application]* [-r] file* + + Options: + -r dir* + search directories recursively for .erl files below them + --show + Prints type specifications for all functions on stdout. + (this is the default behaviour; this option is not really needed) + --show-exported (or --show_exported) + Same as --show, but prints specifications for exported functions only + Specs are displayed sorted alphabetically on the function's name + --annotate + Annotates the specified files with type specifications + --annotate-inc-files + Same as --annotate but annotates all -include() files as well as + all .erl files (use this option with caution - has not been tested much) + --comments + Prints type information using Edoc comments, not type specs + --plt PLT + Use the specified dialyzer PLT file rather than the default one + -T file* + The specified file(s) already contain type specifications and these + are to be trusted in order to print specs for the rest of the files + (Multiple files or dirs, separated by spaces, can be specified.) + -Dname (or -Dname=value) + pass the defined name(s) to TypEr + (The syntax of defines is the same as that used by \"erlc\".) + -I include_dir + pass the include_dir to TypEr + (The syntax of includes is the same as that used by \"erlc\".) + --version (or -v) + prints the Typer version and exits + --help (or -h) + prints this message and exits + + Note: + * denotes that multiple occurrences of these options are possible. +", + io:put_chars(S), + erlang:halt(0). + +%%-------------------------------------------------------------------- %% Handle messages. %%-------------------------------------------------------------------- diff --git a/lib/typer/src/typer_options.erl b/lib/typer/src/typer_options.erl deleted file mode 100644 index b041052cd2..0000000000 --- a/lib/typer/src/typer_options.erl +++ /dev/null @@ -1,194 +0,0 @@ -%% -*- erlang-indent-level: 2 -*- -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2011. 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 : typer_options.erl -%% Author : Bingwen He <[email protected]> -%% Description : Handles all command-line options given to TypEr -%%=========================================================================== - --module(typer_options). - --export([process/0]). - -%%--------------------------------------------------------------------------- - --include("typer.hrl"). - -%%--------------------------------------------------------------------------- -%% Exported functions -%%--------------------------------------------------------------------------- - --spec process() -> {#args{}, #typer_analysis{}}. - -process() -> - ArgList = init:get_plain_arguments(), - %% io:format("Args is ~p\n", [ArgList]), - {Args, Analysis} = analyze_args(ArgList, #args{}, #typer_analysis{}), - %% if the mode has not been set, set it to the default mode (show) - {Args, case Analysis#typer_analysis.mode of - undefined -> Analysis#typer_analysis{mode = ?SHOW}; - Mode when is_atom(Mode) -> Analysis - end}. - -%%--------------------------------------------------------------------------- -%% Internal functions -%%--------------------------------------------------------------------------- - -analyze_args([], Args, Analysis) -> - {Args, Analysis}; -analyze_args(ArgList, Args, Analysis) -> - {Result, Rest} = cl(ArgList), - {NewArgs, NewAnalysis} = analyze_result(Result, Args, Analysis), - analyze_args(Rest, NewArgs, NewAnalysis). - -cl(["-h"|_]) -> help_message(); -cl(["--help"|_]) -> help_message(); -cl(["-v"|_]) -> version_message(); -cl(["--version"|_]) -> version_message(); -cl(["--comments"|Opts]) -> {comments, Opts}; -cl(["--show"|Opts]) -> {{mode, ?SHOW}, Opts}; -cl(["--show_exported"|Opts]) -> {{mode, ?SHOW_EXPORTED}, Opts}; -cl(["--show-exported"|Opts]) -> {{mode, ?SHOW_EXPORTED}, Opts}; -cl(["--annotate"|Opts]) -> {{mode, ?ANNOTATE}, Opts}; -cl(["--annotate-inc-files"|Opts]) -> {{mode, ?ANNOTATE_INC_FILES}, Opts}; -cl(["--no_spec"|Opts]) -> {no_spec, Opts}; -cl(["--plt",Plt|Opts]) -> {{plt, Plt}, Opts}; -cl(["-D"++Def|Opts]) -> - case Def of - "" -> typer:fatal_error("no variable name specified after -D"); - _ -> - DefPair = process_def_list(re:split(Def, "=", [{return, list}])), - {{def, DefPair}, Opts} - end; -cl(["-I",Dir|Opts]) -> {{inc, Dir}, Opts}; -cl(["-I"++Dir|Opts]) -> - case Dir of - "" -> typer:fatal_error("no include directory specified after -I"); - _ -> {{inc, Dir}, Opts} - end; -cl(["-T"|Opts]) -> - {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), - case Files of - [] -> typer:fatal_error("no file or directory specified after -T"); - [_|_] -> {{trusted, Files}, RestOpts} - end; -cl(["-r"|Opts]) -> - {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), - {{files_r, Files}, RestOpts}; -cl(["-"++H|_]) -> typer:fatal_error("unknown option -"++H); -cl(Opts) -> - {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), - {{files, Files}, RestOpts}. - -process_def_list(L) -> - case L of - [Name, Value] -> - {ok, Tokens, _} = erl_scan:string(Value ++ "."), - {ok, ErlValue} = erl_parse:parse_term(Tokens), - {list_to_atom(Name), ErlValue}; - [Name] -> - {list_to_atom(Name), true} - end. - -%% Get information about files that the user trusts and wants to analyze -analyze_result({files, Val}, Args, Analysis) -> - NewVal = Args#args.files ++ Val, - {Args#args{files = NewVal}, Analysis}; -analyze_result({files_r, Val}, Args, Analysis) -> - NewVal = Args#args.files_r ++ Val, - {Args#args{files_r = NewVal}, Analysis}; -analyze_result({trusted, Val}, Args, Analysis) -> - NewVal = Args#args.trusted ++ Val, - {Args#args{trusted = NewVal}, Analysis}; -analyze_result(comments, Args, Analysis) -> - {Args, Analysis#typer_analysis{contracts = false}}; -%% Get useful information for actual analysis -analyze_result({mode, Val}, Args, Analysis) -> - case Analysis#typer_analysis.mode of - undefined -> {Args, Analysis#typer_analysis{mode = Val}}; - _ -> mode_error() - end; -analyze_result({def, Val}, Args, Analysis) -> - NewVal = Analysis#typer_analysis.macros ++ [Val], - {Args, Analysis#typer_analysis{macros = NewVal}}; -analyze_result({inc, Val}, Args, Analysis) -> - NewVal = Analysis#typer_analysis.includes ++ [Val], - {Args, Analysis#typer_analysis{includes = NewVal}}; -analyze_result({plt, Plt}, Args, Analysis) -> - {Args, Analysis#typer_analysis{plt = Plt}}; -analyze_result(no_spec, Args, Analysis) -> - {Args, Analysis#typer_analysis{no_spec = true}}. - - -%%-------------------------------------------------------------------- - --spec mode_error() -> no_return(). -mode_error() -> - typer:fatal_error("can not do \"show\", \"show-exported\", \"annotate\", and \"annotate-inc-files\" at the same time"). - --spec version_message() -> no_return(). -version_message() -> - io:format("TypEr version "++?VSN++"\n"), - erlang:halt(0). - --spec help_message() -> no_return(). -help_message() -> - S = " Usage: typer [--help] [--version] [--comments] [--plt PLT] - [--show | --show-exported | --annotate | --annotate-inc-files] - [-Ddefine]* [-I include_dir]* [-T application]* [-r] file* - - Options: - -r dir* - search directories recursively for .erl files below them - --show - Prints type specifications for all functions on stdout. - (this is the default behaviour; this option is not really needed) - --show-exported (or --show_exported) - Same as --show, but prints specifications for exported functions only - Specs are displayed sorted alphabetically on the function's name - --annotate - Annotates the specified files with type specifications - --annotate-inc-files - Same as --annotate but annotates all -include() files as well as - all .erl files (use this option with caution - has not been tested much) - --comments - Prints type information using Edoc comments, not type specs - --plt PLT - Use the specified dialyzer PLT file rather than the default one - -T file* - The specified file(s) already contain type specifications and these - are to be trusted in order to print specs for the rest of the files - (Multiple files or dirs, separated by spaces, can be specified.) - -Dname (or -Dname=value) - pass the defined name(s) to TypEr - (The syntax of defines is the same as that used by \"erlc\".) - -I include_dir - pass the include_dir to TypEr - (The syntax of includes is the same as that used by \"erlc\".) - --version (or -v) - prints the Typer version and exits - --help (or -h) - prints this message and exits - - Note: - * denotes that multiple occurrences of these options are possible. -", - io:put_chars(S), - erlang:halt(0). |