erl_lint.erl

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

ERL
1,705
字号
		      true, Opts)},	 {unused_record,	  bool_option(warn_unused_record, nowarn_unused_record,		      true, Opts)},	 {deprecated_function,	  bool_option(warn_deprecated_function, nowarn_deprecated_function,		      true, Opts)},	 {bitlevel_binaries,	  bool_option(bitlevel_binaries, nobit_level_binaries, false, Opts)},	 {binary_comprehension,	  bool_option(binary_comprehension, nobinary_comprehension, false, Opts)},         {obsolete_guard,          bool_option(warn_obsolete_guard, nowarn_obsolete_guard,                      false, Opts)}	],    Enabled1 = [Category || {Category,true} <- Enabled0],    Enabled = ordsets:from_list(Enabled1),    Calls = case ordsets:is_element(unused_function, Enabled) of		true ->		    dict:from_list([{{module_info,1},pseudolocals()}]);		false ->		    undefined	    end,    #lint{state=start,          exports=gb_sets:from_list([{module_info,0},                                     {module_info,1}]),          mod_imports=dict:from_list([{erlang,erlang}]),          compile=Opts,          %% Internal pseudo-functions must appear as defined/reached.          defined=gb_sets:from_list(pseudolocals()),	  called = [{F,0} || F <- pseudolocals()],          usage = #usage{calls=Calls},          warn_format=value_option(warn_format, 1, warn_format, 1,                                   nowarn_format, 0, Opts),	  enabled_warnings = Enabled,          file = File         }.%% is_warn_enabled(Category, St) -> true|false.%%  Check whether a warning of category Category is enabled.is_warn_enabled(Type, #lint{enabled_warnings=Enabled}) ->    ordsets:is_element(Type, Enabled).%% return_status(State) ->%%      {ok,[Warning]} | {error,[Error],[Warning]}%%  Pack errors and warnings properly and return ok | error.return_status(St) ->    Ws = pack_warnings(St#lint.warnings),    case pack_errors(St#lint.errors) of        [] -> {ok,Ws};        Es -> {error,Es,Ws}    end.%% pack_errors([{File,ErrD}]) -> [{File,[ErrD]}].%%  Sort on (reversed) insertion order.pack_errors(Es) ->    {Es1,_} = mapfoldl(fun ({File,E}, I) -> {{File,{I,E}}, I-1} end, -1, Es),    map(fun ({File,EIs}) -> {File, map(fun ({_I,E}) -> E end, EIs)} end,        pack_warnings(Es1)).%% pack_warnings([{File,ErrD}]) -> [{File,[ErrD]}]%%  Sort on line number.pack_warnings(Ws) ->    [{File,lists:sort([W || {F,W} <- Ws, F =:= File])} ||         File <- lists:usort([F || {F,_} <- Ws])].%% add_error(ErrorDescriptor, State) -> State'%% add_error(Line, Error, State) -> State'%% add_warning(ErrorDescriptor, State) -> State'%% add_warning(Line, Error, State) -> State'add_error(E, St) -> St#lint{errors=[{St#lint.file,E}|St#lint.errors]}.add_error({File,Line}, E, St) ->     add_error({Line,erl_lint,E}, St#lint{file = File}).add_warning(W, St) -> St#lint{warnings=[{St#lint.file,W}|St#lint.warnings]}.add_warning({File,Line}, W, St) ->     add_warning({Line,erl_lint,W}, St#lint{file = File}).%% forms([Form], State) -> State'forms(Forms0, St0) ->    Forms = eval_file_attribute(Forms0, St0),    %% Line numbers are from now on pairs {File,Line}.    St1 = includes_qlc_hrl(Forms, St0),    St2 = bif_clashes(Forms, St1),    St3 = not_deprecated(Forms, St2),    St4 = foldl(fun form/2, St3, Forms),    post_traversal_check(Forms, St4).includes_qlc_hrl(Forms, St) ->    %% QLC calls erl_lint several times, sometimes with the compile    %% attribute removed. The file attribute, however, is left as is.    QH = [File || {attribute,_,file,{File,_line}} <- Forms,                  filename:basename(File) =:= "qlc.hrl"],    St#lint{xqlc = QH =/= []}.eval_file_attribute(Forms, St) ->    eval_file_attr(Forms, St#lint.file).eval_file_attr([{attribute,_L,file,{File,_Line}}=Form | Forms], _File) ->    [Form | eval_file_attr(Forms, File)];eval_file_attr([Form0 | Forms], File) ->    Form = zip_file_and_line(Form0, File),    [Form | eval_file_attr(Forms, File)];eval_file_attr([], _File) ->    [].zip_file_and_line(T, File) ->    modify_line(T, fun(Line) -> {File,Line} end).%% form(Form, State) -> State'%%  Check a form returning the updated State. Handle generic cases here.form({error,E}, St)   -> add_error(E, St);form({warning,W}, St) -> add_warning(W, St);form({attribute,_L,file,{File,_Line}}, St) ->    St#lint{file = File};form({attribute,_L,compile,_}, St) ->    St;form(Form, #lint{state=State}=St) ->    case State of	start -> start_state(Form, St);	attribute -> attribute_state(Form, St);	function -> function_state(Form, St)    end.%% start_state(Form, State) -> State'start_state({attribute,L,module,{M,Ps}}, St) ->    St1 = set_module(M, L, St),    F = {new, length(Ps)},    Vt = orddict:from_list([{V, {bound, used, []}} || V <- ['THIS' | Ps]]),    St1#lint{state = attribute,	     exports = gb_sets:add_element(F, St#lint.exports),	     defined = gb_sets:add_element(F, St#lint.defined),	     global_vt = Vt};start_state({attribute,L,module,M}, St) ->    St1 = set_module(M, L, St),    St1#lint{state = attribute};start_state(Form, St) ->    St1 = add_error(element(2, Form), undefined_module, St),    attribute_state(Form, St1#lint{state=attribute}).set_module(M, L, St) ->    M1 = package_to_string(M),    case packages:is_valid(M1) of	true ->	    St#lint{module=list_to_atom(M1),		    package=packages:strip_last(M1)};	false ->	    add_error(L, {bad_module_name, M1}, St)    end.%% attribute_state(Form, State) ->%%      State'attribute_state({attribute,L,module,_M}, St) ->    add_error(L, redefine_module, St);attribute_state({attribute,L,export,Es}, St) ->    export(L, Es, St);attribute_state({attribute,L,import,Is}, St) ->    import(L, Is, St);attribute_state({attribute,L,record,{Name,Fields}}, St) ->    record_def(L, Name, Fields, St);attribute_state({attribute,La,behaviour,Behaviour}, St) ->    St#lint{behaviour=St#lint.behaviour ++ [{La,Behaviour}]};attribute_state({attribute,La,behavior,Behaviour}, St) ->    St#lint{behaviour=[{La,Behaviour}|St#lint.behaviour]};attribute_state({attribute,_L,_Other,_Val}, St) -> %Ignore others    St;attribute_state(Form, St) ->    function_state(Form, St#lint{state=function}).%% function_state(Form, State) ->%%      State'%%  Allow record definitions here!function_state({attribute,L,record,{Name,Fields}}, St) ->    record_def(L, Name, Fields, St);function_state({attribute,La,Attr,_Val}, St) ->    add_error(La, {attribute,Attr}, St);function_state({function,L,N,A,Cs}, St) ->    function(L, N, A, Cs, St);function_state({rule,L,_N,_A,_Cs}, St) ->    add_error(L, {mnemosyne,"rule"}, St);function_state({eof,L}, St) -> eof(L, St).%% eof(LastLine, State) ->%%      State'eof(_Line, St0) ->    St0.%% bif_clashes(Forms, State0) -> State.bif_clashes(Forms, St) ->    Nowarn = nowarn_function(nowarn_bif_clash, St#lint.compile),    Clashes0 = [{Name,Arity} || {function,_L,Name,Arity,_Cs} <- Forms,                                erl_internal:bif(Name, Arity)],    Clashes = ordsets:subtract(ordsets:from_list(Clashes0), Nowarn),    St#lint{clashes=Clashes}.%% is_bif_clash(Name, Arity, State) -> false|true.is_bif_clash(_Name, _Arity, #lint{clashes=[]}) ->    false;is_bif_clash(Name, Arity, #lint{clashes=Clashes}) ->    ordsets:is_element({Name,Arity}, Clashes).%% not_deprecated(Forms, State0) -> Statenot_deprecated(Forms, St0) ->    %% There are no line numbers in St0#lint.compile.    MFAsL = [{MFA,L} ||                 {attribute, L, compile, Args} <- Forms,                {nowarn_deprecated_function, MFAs0} <- lists:flatten([Args]),                MFA <- lists:flatten([MFAs0])],    Nowarn = [MFA || {MFA,_L} <- MFAsL],    Bad = [MFAL || {{M,F,A},_L}=MFAL <- MFAsL,                    otp_internal:obsolete(M, F, A) =:= false],    St1 = func_line_warning(bad_nowarn_deprecated_function, Bad, St0),    St1#lint{not_deprecated = ordsets:from_list(Nowarn)}.%% post_traversal_check(Forms, State0) -> State.%% Do some further checking after the forms have been traversed and%% data about calls etc. have been collected.post_traversal_check(Forms, St0) ->    St1 = check_behaviour(St0),    St2 = check_deprecated(Forms, St1),    St3 = check_imports(Forms, St2),    St4 = check_inlines(Forms, St3),    St5 = check_undefined_functions(St4),    St6 = check_unused_functions(Forms, St5),    St7 = check_bif_clashes(Forms, St6),    check_unused_records(Forms, St7).%% check_behaviour(State0) -> State%% Check that the behaviour attribute is valid.check_behaviour(St0) ->    behaviour_check(St0#lint.behaviour, St0).%% behaviour_check([{Line,Behaviour}], State) -> State'%%  Check behaviours for existence and defined functions.behaviour_check(Bs, St0) ->    {AllBfs,St1} = all_behaviour_callbacks(Bs, [], St0),    St = behaviour_missing_callbacks(AllBfs, St1),    behaviour_conflicting(AllBfs, St).all_behaviour_callbacks([{Line,B}|Bs], Acc, St0) ->    {Bfs0,St} = behaviour_callbacks(Line, B, St0),    all_behaviour_callbacks(Bs, [{{Line,B},Bfs0}|Acc], St);all_behaviour_callbacks([], Acc, St) -> {reverse(Acc),St}.behaviour_callbacks(Line, B, St0) ->    case catch B:behaviour_info(callbacks) of        {'EXIT', _Reason} ->            St1 = add_warning(Line, {undefined_behaviour,B}, St0),            {[], St1};        Funcs when is_list(Funcs) ->            All = all(fun({FuncName, Arity}) ->                              if                                  is_atom(FuncName), is_integer(Arity) ->                                      true;                                  true ->                                      false                              end;                         (_Other) ->                              false                      end,                      Funcs),            if                All =:= true ->                    {Funcs, St0};                true ->                    St1 = add_warning(Line,                                      {ill_defined_behaviour_callbacks,B},                                      St0),                    {[], St1}            end;        undefined ->            St1 = add_warning(Line, {undefined_behaviour_callbacks,B}, St0),            {[], St1};        _Other ->            St1 = add_warning(Line, {ill_defined_behaviour_callbacks,B}, St0),            {[], St1}    end.behaviour_missing_callbacks([{{Line,B},Bfs}|T], #lint{exports=Exp}=St0) ->    Missing = ordsets:subtract(ordsets:from_list(Bfs), gb_sets:to_list(Exp)),    St = foldl(fun (F, S0) ->		       add_warning(Line, {undefined_behaviour_func,F,B}, S0)	       end, St0, Missing),    behaviour_missing_callbacks(T, St);behaviour_missing_callbacks([], St) -> St.behaviour_conflicting(AllBfs, St) ->    R0 = sofs:relation(AllBfs, [{item,[callback]}]),    R1 = sofs:family_to_relation(R0),    R2 = sofs:converse(R1),    R3 = sofs:relation_to_family(R2),    R4 = sofs:family_specification(fun(S) -> sofs:no_elements(S) > 1 end, R3),    R = sofs:to_external(R4),    behaviour_add_conflicts(R, St).behaviour_add_conflicts([{Cb,[{{_,FirstL},FirstB}|Cs]}|T], St0) ->    St = behaviour_add_conflict(Cs, Cb, FirstL, FirstB, St0),    behaviour_add_conflicts(T, St);behaviour_add_conflicts([], St) -> St.behaviour_add_conflict([{Line,B}|Cs], Cb, FirstL, FirstB, St0) ->    St = add_warning(Line, {conflicting_behaviours,Cb,B,FirstL,FirstB}, St0),    behaviour_add_conflict(Cs, Cb, FirstL, FirstB, St);behaviour_add_conflict([], _, _, _, St) -> St.%% check_deprecated(Forms, State0) -> Statecheck_deprecated(Forms, St0) ->    %% Get the correct list of exported functions.    Exports = case member(export_all, St0#lint.compile) of		  true -> St0#lint.defined;		  false -> St0#lint.exports	      end,    X = gb_sets:to_list(Exports),    #lint{module = Mod} = St0,    Bad = [{E,L} || {attribute, L, deprecated, Depr} <- Forms,                    D <- lists:flatten([Depr]),                    E <- depr_cat(D, X, Mod)],    foldl(fun ({E,L}, St1) ->                   add_error(L, E, St1)          end, St0, Bad).depr_cat({F, A, Flg}=D, X, Mod) ->

⌨️ 快捷键说明

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