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 + -
显示快捷键?