erl_lint.erl

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

ERL
1,705
字号
    case deprecated_flag(Flg) of        false -> [{invalid_deprecated,D}];        true -> depr_fa(F, A, X, Mod)    end;depr_cat({F, A}, X, Mod) ->    depr_fa(F, A, X, Mod);depr_cat(module, _X, _Mod) ->    [];depr_cat(D, _X, _Mod) ->    [{invalid_deprecated,D}].depr_fa('_', '_', _X, _Mod) ->    [];depr_fa(F, '_', X, _Mod) when is_atom(F) ->    %% Don't use this syntax for built-in functions.    case lists:filter(fun({F1,_}) -> F1 =:= F end, X) of        [] -> [{bad_deprecated,{F,'_'}}];        _ -> []    end;depr_fa(F, A, X, Mod) when is_atom(F), is_integer(A), A >= 0 ->    case lists:member({F,A}, X) of        true -> [];        false ->            case erlang:is_builtin(Mod, F, A) of                true -> [];                false -> [{bad_deprecated,{F,A}}]            end    end;depr_fa(F, A, _X, _Mod) ->    [{invalid_deprecated,{F,A}}].deprecated_flag(next_version) -> true;deprecated_flag(next_major_release) -> true;deprecated_flag(eventually) -> true;deprecated_flag(_) -> false.%% check_imports(Forms, State0) -> Statecheck_imports(Forms, St0) ->    case is_warn_enabled(unused_import, St0) of        false ->            St0;        true ->            Usage = St0#lint.usage,            Unused = ordsets:subtract(St0#lint.imports, Usage#usage.imported),            Imports = [{{FA,list_to_atom(package_to_string(Mod))},L}                        || {attribute,L,import,{Mod,Fs}} <- Forms,                          FA <- lists:usort(Fs)],            Bad = [{FM,L} || FM <- Unused, {FM2,L} <- Imports, FM =:= FM2],            func_line_warning(unused_import, Bad, St0)    end.%% check_inlines(Forms, State0) -> Statecheck_inlines(Forms, St0) ->    check_option_functions(Forms, inline, bad_inline, St0).%% check_unused_functions(Forms, State0) -> Statecheck_unused_functions(Forms, St0) ->    St1 = check_option_functions(Forms, nowarn_unused_function,                                 bad_nowarn_unused_function, St0),    Opts = St1#lint.compile,    case member(export_all, Opts) orelse	not is_warn_enabled(unused_function, St1) of        true ->             St1;        false ->            Nowarn = nowarn_function(nowarn_unused_function, Opts),            Usage = St1#lint.usage,            Used = reached_functions(gb_sets:to_list(St1#lint.exports),				     Usage#usage.calls),            UsedOrNowarn = ordsets:union(Used, Nowarn),            Unused = ordsets:subtract(gb_sets:to_list(St1#lint.defined),				      UsedOrNowarn),            Functions = [{{N,A},L} || {function,L,N,A,_} <- Forms],            Bad = [{FA,L} || FA <- Unused, {FA2,L} <- Functions, FA =:= FA2],            func_line_warning(unused_function, Bad, St1)    end.%% reached_functions(RootSet, CallRef) -> [ReachedFunc].%% reached_functions(RootSet, CallRef, [ReachedFunc]) -> [ReachedFunc].reached_functions(Root, Ref) ->    reached_functions(Root, [], Ref, gb_sets:empty()).reached_functions([R|Rs], More0, Ref, Reached0) ->    case gb_sets:is_element(R, Reached0) of        true -> reached_functions(Rs, More0, Ref, Reached0);        false ->            Reached = gb_sets:add_element(R, Reached0), %It IS reached            case dict:find(R, Ref) of                {ok,More} -> reached_functions(Rs, [More|More0], Ref, Reached);                error -> reached_functions(Rs, More0, Ref, Reached)            end    end;reached_functions([], [_|_]=More, Ref, Reached) ->    reached_functions(lists:append(More), [], Ref, Reached);reached_functions([], [], _Ref, Reached) -> gb_sets:to_list(Reached).%% check_undefined_functions(State0) -> Statecheck_undefined_functions(#lint{called=Called0,defined=Def0}=St0) ->    Called = sofs:relation(Called0, [{func,location}]),    Def = sofs:from_external(gb_sets:to_list(Def0), [func]),    Undef = sofs:to_external(sofs:drestriction(Called, Def)),    foldl(fun ({NA,L}, St) ->		  add_error(L, {undefined_function,NA}, St)	  end, St0, Undef).%% check_bif_clashes(Forms, State0) -> Statecheck_bif_clashes(Forms, St0) ->    %% St0#lint.defined is now complete.    check_option_functions(Forms, nowarn_bif_clash,                           bad_nowarn_bif_clash, St0).check_option_functions(Forms, Tag0, Type, St0) ->    %% There are no line numbers in St0#lint.compile.    FAsL = [{FA,L} || {attribute, L, compile, Args} <- Forms,                      {Tag, FAs0} <- lists:flatten([Args]),                      Tag0 =:= Tag,                      FA <- lists:flatten([FAs0])],    DefFunctions = gb_sets:to_list(St0#lint.defined) -- pseudolocals(),    Bad = [{FA,L} || {FA,L} <- FAsL, not member(FA, DefFunctions)],    func_line_error(Type, Bad, St0).nowarn_function(Tag, Opts) ->    ordsets:from_list([FA || {Tag1,FAs} <- Opts,                              Tag1 =:= Tag,                             FA <- lists:flatten([FAs])]).func_line_warning(Type, Fs, St) ->    foldl(fun ({F,Line}, St0) -> add_warning(Line, {Type,F}, St0) end, St, Fs).func_line_error(Type, Fs, St) ->    foldl(fun ({F,Line}, St0) -> add_error(Line, {Type,F}, St0) end, St, Fs).check_unused_records(Forms, St0) ->    AttrFiles = [File || {attribute,_L,file,{File,_Line}} <- Forms],    case {is_warn_enabled(unused_record, St0),AttrFiles} of        {true,[FirstFile|_]} ->            %% The check is a bit imprecise in that uses from unused            %% functions count.            Usage = St0#lint.usage,            UsedRecords = sets:to_list(Usage#usage.used_records),            URecs = foldl(fun (Used, Recs) ->                                   dict:erase(Used, Recs)                           end, St0#lint.records, UsedRecords),            Unused = [{Name,Line} ||                          {Name,{Line,_Fields}} <- dict:to_list(URecs),                         element(1, Line) =:= FirstFile],            foldl(fun ({N,L}, St) ->                          add_warning(L, {unused_record,N}, St)                  end, St0, Unused);        _ ->            St0    end.%% For storing the import list we use the orddict module. %% We know an empty set is [].%% export(Line, Exports, State) -> State.%%  Mark functions as exported, also as called from the export line.export(Line, Es, #lint{exports=Es0}=St0) ->    {Es1,C1,St1} =         foldl(fun (NA, {E,C,St2}) ->                      St = case gb_sets:is_element(NA, E) of                               true ->                                   add_warning(Line, {duplicated_export, NA}, St2);                               false ->                                   St2                           end,                      {gb_sets:add_element(NA, E),                       [{NA,Line}|C],                       St}              end,              {Es0,St0#lint.called,St0}, Es),    St1#lint{exports=Es1,called=C1}.%% import(Line, Imports, State) -> State.%% imported(Name, Arity, State) -> {yes,Module} | no.import(Line, {Mod,Fs}, St) ->    Mod1 = package_to_string(Mod),    case packages:is_valid(Mod1) of        true ->            Mfs = ordsets:from_list(Fs),            case check_imports(Line, Mfs, St#lint.imports) of                [] ->                    St#lint{imports=add_imports(list_to_atom(Mod1), Mfs,                                                St#lint.imports)};                Efs ->                    foldl(fun (Ef, St0) ->                                  add_error(Line, {redefine_import,Ef},                                            St0)                          end,                          St, Efs)            end;        false ->            add_error(Line, {bad_module_name, Mod1}, St)    end;import(Line, Mod, St) ->    Mod1 = package_to_string(Mod),    case packages:is_valid(Mod1) of        true ->            Key = list_to_atom(packages:last(Mod1)),            Imps = St#lint.mod_imports,%%%         case dict:is_key(Key, Imps) of%%%             true ->%%%                 M = packages:last(Mod1),%%%                 P = packages:strip_last(Mod1),%%%                 add_error(Line, {redefine_mod_import, M, P}, St);%%%             false ->%%%                 St#lint{mod_imports =%%%                         dict:store(Key, list_to_atom(Mod1), Imps)}%%%         end;            St#lint{mod_imports = dict:store(Key, list_to_atom(Mod1),                                             Imps)};        false ->            add_error(Line, {bad_module_name, Mod1}, St)    end.check_imports(_Line, Fs, Is) ->    foldl(fun (F, Efs) ->              case orddict:find(F, Is) of                  {ok,Mod} -> [{F,Mod}|Efs];                  error ->                      {N,A} = F,                      case erl_internal:bif(N, A) of                          true ->                              [{bif,F,erlang}|Efs];                          false ->                              Efs                      end              end end, [], Fs).add_imports(Mod, Fs, Is) ->    foldl(fun (F, Is0) -> orddict:store(F, Mod, Is0) end, Is, Fs).imported(F, A, St) ->    case orddict:find({F,A}, St#lint.imports) of        {ok,Mod} -> {yes,Mod};        error -> no    end.%% call_function(Line, Name, Arity, State) -> State.%%  Add to both called and calls.call_function(Line, F, A, #lint{usage=Usage0,called=Cd,func=Func}=St) ->    #usage{calls = Cs} = Usage0,    NA = {F,A},    Usage = case Cs of		undefined -> Usage0;		_ -> Usage0#usage{calls=dict:append(Func, NA, Cs)}	    end,    St#lint{called=[{NA,Line}|Cd],usage = Usage}.%% is_function_exported(Name, Arity, State) -> false|true.is_function_exported(Name, Arity, #lint{exports=Exports,compile=Compile}) ->    gb_sets:is_element({Name,Arity}, Exports) orelse        member(export_all, Compile).    %% function(Line, Name, Arity, Clauses, State) -> State.function(Line, Name, Arity, Cs, St0) ->    St1 = define_function(Line, Name, Arity, St0#lint{func={Name,Arity}}),    clauses(Cs, St1#lint.global_vt, St1).%% define_function(Line, Name, Arity, State) -> State.define_function(Line, Name, Arity, St0) ->    St1 = keyword_warning(Line, Name, St0),    NA = {Name,Arity},    case gb_sets:is_member(NA, St1#lint.defined) of        true ->            add_error(Line, {redefine_function,NA}, St1);        false ->            St2 = St1#lint{defined=gb_sets:add_element(NA, St1#lint.defined)},            St = case erl_internal:bif(Name, Arity) andalso		     not is_function_exported(Name, Arity, St2) of		     true -> add_warning(Line, {redefine_bif,NA}, St2);                     false -> St2                  end,            case imported(Name, Arity, St) of                {yes,_M} -> add_error(Line, {define_import,NA}, St);                no -> St            end    end.%% clauses([Clause], VarTable, State) -> {VarTable, State}.clauses(Cs, Vt, St) ->    foldl(fun (C, St0) ->                  {_,St1} = clause(C, Vt, St0),                  St1          end, St, Cs).clause({clause,_Line,H,G,B}, Vt0, St0) ->    {Hvt,Binvt,St1} = head(H, Vt0, St0),    %% Cannot ignore BinVt since "binsize variables" may have been used.    Vt1 = vtupdate(Hvt, vtupdate(Binvt, Vt0)),    {Gvt,St2} = guard(G, Vt1, St1),    Vt2 = vtupdate(Gvt, Vt1),    {Bvt,St3} = exprs(B, Vt2, St2),    Upd = vtupdate(Bvt, Vt2),    check_unused_vars(Upd, Vt0, St3).%% head([HeadPattern], VarTable, State) ->%%      {VarTable,BinVarTable,State}%%  Check a patterns in head returning "all" variables. Not updating the%%  known variable list will result in multiple error messages/warnings.head(Ps, Vt, St0) ->    head(Ps, Vt, Vt, St0).    % Old = Vthead([P|Ps], Vt, Old, St0) ->    {Pvt,Bvt1,St1} = pattern(P, Vt, Old, [], St0),    {Psvt,Bvt2,St2} = head(Ps, Vt, Old, St1),    {vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt1,Bvt2),St2};head([], _Vt, _Env, St) -> {[],[],St}.%% pattern(Pattern, VarTable, Old, BinVarTable, State) -> %%                  {UpdVarTable,BinVarTable,State}.%%  Check pattern return variables. Old is the set of variables used for%%  deciding whether an occurrence is a binding occurrence or a use, and%%  VarTable is the set of variables used for arguments to binary%%  patterns. UpdVarTable is updated when same variable in VarTable is%%  used in the size part of a bit segment. All other information about%%  used variables are recorded in BinVarTable. The caller can then decide%%  what to do with it depending on whether variables in the pattern shadow%%  variabler or not. This separation is one way of dealing with these:%%  A = 4, fun(<<A:A>>) -> % A #2 unused%%  A = 4, fun(<<A:8,16:A>>) -> % A #1 unusedpattern(P, Vt, St) ->    pattern(P, Vt, Vt, [], St).    % Old = Vtpattern({var,_Line,'_'}, _Vt, _Old, _Bvt, St) ->

⌨️ 快捷键说明

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