erl_lint.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,705 行 · 第 1/5 页

ERL
1,705
字号
%% -*- erlang-indent-level: 4 -*-%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id $%%%% Do necessary checking of Erlang code.%% N.B. All the code necessary for checking structs (tagged tuples) is%% here. Just comment out the lines in pattern/2, gexpr/3 and expr/3.-module(erl_lint).-export([module/1,module/2,module/3,format_error/1]).-export([exprs/2,exprs_opt/3,used_vars/2]). % Used from erl_eval.erl.-export([is_pattern_expr/1,is_guard_test/1,is_guard_test/2]).-export([is_guard_expr/1]).-export([bool_option/4,value_option/3,value_option/7]).-export([modify_line/2]).-import(lists, [member/2,map/2,foldl/3,foldr/3,mapfoldl/3,all/2,reverse/1]).%% bool_option(OnOpt, OffOpt, Default, Options) -> true | false.%% value_option(Flag, Default, Options) -> Value.%% value_option(Flag, Default, OnOpt, OnVal, OffOpt, OffVal, Options) ->%%              Value.%%  The option handling functions.bool_option(On, Off, Default, Opts) ->    foldl(fun (Opt, _Def) when Opt =:= On -> true;              (Opt, _Def) when Opt =:= Off -> false;              (_Opt, Def) -> Def          end, Default, Opts).value_option(Flag, Default, Opts) ->    foldl(fun ({Opt,Val}, _Def) when Opt =:= Flag -> Val;              (_Opt, Def) -> Def          end, Default, Opts).value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->    foldl(fun ({Opt,Val}, _Def) when Opt =:= Flag -> Val;              (Opt, _Def) when Opt =:= On -> OnVal;              (Opt, _Def) when Opt =:= Off -> OffVal;              (_Opt, Def) -> Def          end, Default, Opts).%% The error and warning info structures, {Line,Module,Descriptor},%% are kept in their seperate fields in the lint state record together%% with the name of the file (when a new file is entered, marked by%% the 'file' attribute, then the field 'file' of the lint record is%% set). At the end of the run these lists are packed into a list of%% {FileName,ErrorDescList} pairs which are returned.-include_lib("stdlib/include/erl_bits.hrl").%%-define(DEBUGF(X,Y), io:format(X, Y)).-define(DEBUGF(X,Y), void).%% Usage of records, functions, and imports. The variable table, which%% is passed on as an argument, holds the usage of variables.-record(usage, {          calls = dict:new(),                   %Who calls who          imported = [],                        %Actually imported functions          used_records=sets:new()               %Used record definitions         }).%% Define the lint state record.%% 'called' and 'exports' contain {Line, {Function, Arity}},%% the other function collections contain {Function, Arity}.-record(lint, {state=start,                     %start | attribute | function               module=[],                       %Module               package="",                      %Module package               behaviour=[],                    %Behaviour               exports=gb_sets:empty(),		%Exports               imports=[],                      %Imports               mod_imports=dict:new(),          %Module Imports               compile=[],                      %Compile flags               records=dict:new(),		%Record definitions               defined=gb_sets:empty(),		%Defined fuctions	       clashes=[],			%Exported functions named as BIFs               not_deprecated=[],               %Not considered deprecated               func=[],                         %Current function               warn_format=0,                   %Warn format calls	       enabled_warnings=[],		%All enabled warnings (ordset).               errors=[],                       %Current errors               warnings=[],                     %Current warnings	       global_vt=[],                    %The global VarTable               file=[],                         %From last file attribute               recdef_top=false,                %true in record initialisation                                                %outside any fun or lc               xqlc=false,                      %true if qlc.hrl included               called=[],			%Called functions               usage = #usage{}              }).%% format_error(Error)%%  Return a string describing the error.format_error(undefined_module) ->    "no module definition";format_error({bad_module_name, M}) ->    io_lib:format("bad module name '~s'", [M]);format_error(redefine_module) ->    "redefining module";%%% format_error({redefine_mod_import, M, P}) ->%%%     io_lib:format("module '~s' already imported from package '~s'",%%%               [M, P]);format_error(invalid_call) ->    "invalid function call";format_error(invalid_record) ->    "invalid record expression";format_error(no_generator) ->    "list comprehension has no generator (perhaps \"|\" mistyped as \"||\"?)";format_error({attribute,A}) ->    io_lib:format("attribute '~w' after function definitions", [A]);format_error({missing_qlc_hrl,A}) ->    io_lib:format("qlc:q/~w called, but \"qlc.hrl\" not included", [A]);format_error({redefine_import,{bif,{F,A},M}}) ->    io_lib:format("function ~w/~w already auto-imported from ~w",                  [F,A,M]);format_error({redefine_import,{{F,A},M}}) ->    io_lib:format("function ~w/~w already imported from ~w", [F,A,M]);format_error({bad_inline,{F,A}}) ->    io_lib:format("inlined function ~w/~w undefined", [F,A]);format_error({invalid_deprecated,D}) ->    io_lib:format("badly formed deprecated attribute ~w", [D]);format_error({bad_deprecated,{F,A}}) ->    io_lib:format("deprecated function ~w/~w undefined or not exported",                   [F, A]);format_error({bad_nowarn_unused_function,{F,A}}) ->    io_lib:format("function ~w/~w undefined", [F,A]);format_error({bad_nowarn_bif_clash,{F,A}}) ->    io_lib:format("function ~w/~w undefined", [F,A]);format_error({bad_nowarn_deprecated_function,{M,F,A}}) ->    io_lib:format("~w:~w/~w is not a deprecated function", [M,F,A]);format_error({duplicated_export, {F,A}}) ->    io_lib:format("function ~w/~w already exported", [F,A]);format_error({unused_import,{{F,A},M}}) ->    io_lib:format("import ~w:~w/~w is unused", [M,F,A]);format_error({undefined_function,{F,A}}) ->    io_lib:format("function ~w/~w undefined", [F,A]);format_error({redefine_function,{F,A}}) ->    io_lib:format("function ~w/~w already defined", [F,A]);format_error({define_import,{F,A}}) ->    io_lib:format("defining imported function ~w/~w", [F,A]);format_error({unused_function,{F,A}}) ->    io_lib:format("function ~w/~w is unused", [F,A]);format_error({redefine_bif,{F,A}}) ->    io_lib:format("defining BIF ~w/~w", [F,A]);format_error({call_to_redefined_bif,{F,A}}) ->    io_lib:format("call to ~w/~w will call erlang:~w/~w; "		  "not ~w/~w in this module \n"		  "  (add an explicit module name to the call to avoid this warning)",		  [F,A,F,A,F,A]);format_error({deprecated, {M1, F1, A1}, {M2, F2, A2}}) ->    io_lib:format("~p:~p/~p deprecated; use ~p:~p/~p", [M1, F1, A1, M2, F2, A2]);format_error({obsolete_guard, {F, A}}) ->    io_lib:format("~p/~p obsolete", [F, A]);format_error({deprecated, {M1, F1, A1}, String}) when is_list(String) ->    io_lib:format("~p:~p/~p: ~s", [M1, F1, A1, String]);format_error({reserved_for_future,K}) ->    io_lib:format("atom ~w: future reserved keyword - rename or quote", [K]);format_error(illegal_pattern) -> "illegal pattern";format_error(illegal_bin_pattern) ->    "binary patterns cannot be matched in parallel using '='";format_error(illegal_expr) -> "illegal expression";format_error(illegal_guard_expr) -> "illegal guard expression";format_error({explicit_export,F,A}) ->    io_lib:format("in this release, the call to ~w/~w must be written "		  "like this: erlang:~w/~w",		  [F,A,F,A]);format_error({undefined_record,T}) ->    io_lib:format("record ~w undefined", [T]);format_error({redefine_record,T}) ->    io_lib:format("record ~w already defined", [T]);format_error({redefine_field,T,F}) ->    io_lib:format("field ~w already defined in record ~w", [F,T]);format_error({undefined_field,T,F}) ->    io_lib:format("field ~w undefined in record ~w", [F,T]);format_error(illegal_record_info) ->    "illegal record info";format_error({field_name_is_variable,T,F}) ->    io_lib:format("field ~w is not an atom or _ in record ~w", [F,T]);format_error({wildcard_in_update,T}) ->    io_lib:format("meaningless use of _ in update of record ~w", [T]);format_error({unused_record,T}) ->    io_lib:format("record ~w is unused", [T]);format_error({unbound_var,V}) ->    io_lib:format("variable ~w is unbound", [V]);format_error({unsafe_var,V,{What,Where}}) ->    io_lib:format("variable ~w unsafe in ~w (line ~w)", [V,What,Where]);format_error({exported_var,V,{What,Where}}) ->    io_lib:format("variable ~w exported from ~w (line ~w)", [V,What,Where]);format_error({shadowed_var,V,In}) ->    io_lib:format("variable ~w shadowed in ~w", [V,In]);format_error({unused_var, V}) ->    io_lib:format("variable ~w is unused", [V]);format_error({variable_in_record_def,V}) ->    io_lib:format("variable ~w in record definition", [V]);format_error({undefined_bittype,Type}) ->    io_lib:format("bit type ~w undefined", [Type]);format_error({bittype_mismatch,T1,T2,What}) ->    io_lib:format("bit type mismatch (~s) between ~p and ~p", [What,T1,T2]);format_error(bittype_unit) ->    "a bit unit size must not be specified unless a size is specified too";format_error(illegal_bitsize) ->    "illegal bit size";format_error({bad_bitsize,Type}) ->    io_lib:format("bad ~s bit size", [Type]);format_error(unaligned_bitpat) ->    "bit pattern not byte aligned";format_error(binary_comprehension) ->    "binary comprehension in code not compiled with the binary comprehension flag";format_error(binary_generator) ->    "binary generator in code not compiled with the binary comprehension flag";format_error({format_error,{Fmt,Args}}) ->    io_lib:format(Fmt, Args);format_error({mnemosyne,What}) ->    "mnemosyne " ++ What ++ ", missing transformation";format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) ->    io_lib:format("conflicting behaviours - callback ~w/~w required by both '~p' "		  "and '~p' (line ~p)", [Name,Arity,B,FirstB,FirstL]);format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}) ->    io_lib:format("undefined callback function ~w/~w (behaviour '~w')",		  [Func,Arity,Behaviour]);format_error({undefined_behaviour,Behaviour}) ->    io_lib:format("behaviour ~w undefined", [Behaviour]);format_error({undefined_behaviour_callbacks,Behaviour}) ->    io_lib:format("behaviour ~w callback functions are undefined",                  [Behaviour]);format_error({ill_defined_behaviour_callbacks,Behaviour}) ->    io_lib:format("behaviour ~w callback functions erroneously defined",                  [Behaviour]).%% Local functions that are somehow automatically generated.pseudolocals() ->    [{module_info,0}, {module_info,1}, {record_info,2}].%%%% Used by erl_eval.erl to check commands.%% exprs(Exprs, BindingsList) ->    exprs_opt(Exprs, BindingsList, []).exprs_opt(Exprs, BindingsList, Opts) ->    {St0,Vs} = foldl(fun({{record,_SequenceNumber,_Name},Attr0}, {St1,Vs1}) ->                             Attr = zip_file_and_line(Attr0, "none"),			     {attribute_state(Attr, St1),Vs1};                        ({V,_}, {St1,Vs1}) -> 			     {St1,[{V,{bound,unused,[]}} | Vs1]}		     end, {start("nofile",Opts),[]}, BindingsList),    Vt = orddict:from_list(Vs),    {_Evt,St} = exprs(zip_file_and_line(Exprs, "nofile"), Vt, St0),    return_status(St).used_vars(Exprs, BindingsList) ->    Vs = foldl(fun({{record,_SequenceNumber,_Name},_Attr}, Vs0) -> Vs0;		  ({V,_Val}, Vs0) -> [{V,{bound,unused,[]}} | Vs0]	       end, [], BindingsList),    Vt = orddict:from_list(Vs),    {Evt,_St} = exprs(zip_file_and_line(Exprs, "nofile"), Vt, start()),    {ok, foldl(fun({V,{_,used,_}}, L) -> [V | L];                  (_, L) -> L end, [], Evt)}.%% module([Form]) ->%% module([Form], FileName) ->%% module([Form], FileName, [CompileOption]) ->%%      {ok,[Warning]} | {error,[Error],[Warning]}%%  Start processing a module. Define predefined functions and exports and%%  apply_lambda/2 has been called to shut lint up. N.B. these lists are%%  really all ordsets!module(Forms) ->    Opts = compiler_options(Forms),    St = forms(Forms, start("nofile", Opts)),    return_status(St).    module(Forms, FileName) ->    Opts = compiler_options(Forms),    St = forms(Forms, start(FileName, Opts)),    return_status(St).module(Forms, FileName, Opts0) ->    %% We want the options given on the command line to take    %% precedence over options in the module.    Opts = compiler_options(Forms) ++ Opts0,    St = forms(Forms, start(FileName, Opts)),    return_status(St).compiler_options(Forms) ->    lists:flatten([C || {attribute,_,compile,C} <- Forms]).%% start() -> State%% start(FileName, [Option]) -> Statestart() ->    start("nofile", []).start(File, Opts) ->    Enabled0 =	[{unused_vars,	  bool_option(warn_unused_vars, nowarn_unused_vars,		      true, Opts)},	 {export_vars,	  bool_option(warn_export_vars, nowarn_export_vars,		      false, Opts)},	 {shadow_vars,	  bool_option(warn_shadow_vars, nowarn_shadow_vars,		      true, Opts)},	 {unused_import,	  bool_option(warn_unused_import, nowarn_unused_import,		      false, Opts)},	 {unused_function,	  bool_option(warn_unused_function, nowarn_unused_function,		      true, Opts)},	 {bif_clash,	  bool_option(warn_bif_clash, nowarn_bif_clash,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?