erl_lint.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,705 行 · 第 1/5 页
ERL
1,705 行
{[],[],St}; %Ignore anonymous variablepattern({var,Line,V}, _Vt, Old, Bvt, St) -> pat_var(V, Line, Old, Bvt, St);pattern({char,_Line,_C}, _Vt, _Old, _Bvt, St) -> {[],[],St};pattern({integer,_Line,_I}, _Vt, _Old, _Bvt, St) -> {[],[],St};pattern({float,_Line,_F}, _Vt, _Old, _Bvt, St) -> {[],[],St};pattern({atom,Line,A}, _Vt, _Old, _Bvt, St) -> {[],[],keyword_warning(Line, A, St)};pattern({string,_Line,_S}, _Vt, _Old, _Bvt, St) -> {[],[],St};pattern({nil,_Line}, _Vt, _Old, _Bvt, St) -> {[],[],St};pattern({cons,_Line,H,T}, Vt, Old, Bvt, St0) -> {Hvt,Bvt1,St1} = pattern(H, Vt, Old, Bvt, St0), {Tvt,Bvt2,St2} = pattern(T, Vt, Old, Bvt, St1), {vtmerge_pat(Hvt, Tvt),vtmerge_pat(Bvt1,Bvt2),St2};pattern({tuple,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St);%%pattern({struct,_Line,_Tag,Ps}, Vt, Old, Bvt, St) ->%% pattern_list(Ps, Vt, Old, Bvt, St);pattern({record_index,Line,Name,Field}, _Vt, _Old, _Bvt, St) -> {Vt1,St1} = check_record(Line, Name, St, fun (Dfs, St1) -> pattern_field(Field, Name, Dfs, St1) end), {Vt1,[],St1};pattern({record_field,Line,_,_}=M, _Vt, _Old, _Bvt, St0) -> case expand_package(M, St0) of {error, St1} -> {[],[],add_error(Line, illegal_expr, St1)}; {_, St1} -> {[],[],St1} end;pattern({record,Line,Name,Pfs}, Vt, Old, Bvt, St) -> case dict:find(Name, St#lint.records) of {ok,{_Line,Fields}} -> St1 = used_record(Name, St), pattern_fields(Pfs, Name, Fields, Vt, Old, Bvt, St1); error -> {[],[],add_error(Line, {undefined_record,Name}, St)} end;pattern({bin,Line,Fs}, Vt, Old, Bvt, St) -> pattern_bin(Line, Fs, Vt, Old, Bvt, St);pattern({op,_Line,'++',{nil,_},R}, Vt, Old, Bvt, St) -> pattern(R, Vt, Old, Bvt, St);pattern({op,_Line,'++',{cons,Li,{char,_L2,_C},T},R}, Vt, Old, Bvt, St) -> pattern({op,Li,'++',T,R}, Vt, Old, Bvt, St); %Char unimportant herepattern({op,_Line,'++',{cons,Li,{integer,_L2,_I},T},R}, Vt, Old, Bvt, St) -> pattern({op,Li,'++',T,R}, Vt, Old, Bvt, St); %Weird, but compatible!pattern({op,_Line,'++',{string,_Li,_S},R}, Vt, Old, Bvt, St) -> pattern(R, Vt, Old, Bvt, St); %String unimportant herepattern({match,_Line,Pat1,Pat2}, Vt, Old, Bvt, St0) -> {Lvt,Bvt1,St1} = pattern(Pat1, Vt, Old, Bvt, St0), {Rvt,Bvt2,St2} = pattern(Pat2, Vt, Old, Bvt, St1), St3 = reject_bin_alias(Pat1, Pat2, St2), {vtmerge_pat(Lvt, Rvt),vtmerge_pat(Bvt1,Bvt2),St3};%% Catch legal constant expressions, including unary +,-.pattern(Pat, _Vt, _Old, _Bvt, St) -> case is_pattern_expr(Pat) of true -> {[],[],St}; false -> {[],[],add_error(element(2, Pat), illegal_pattern, St)} end.pattern_list(Ps, Vt, Old, Bvt0, St) -> foldl(fun (P, {Psvt,Bvt,St0}) -> {Pvt,Bvt1,St1} = pattern(P, Vt, Old, Bvt0, St0), {vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt,Bvt1),St1} end, {[],[],St}, Ps).%% reject_bin_alias(Pat1, Pat2, St) -> St'%% Aliases of binary patterns, such as <<A:8>> = <<B:4,C:4>> or even%% <<A:8>> = <<A:8>>, are not allowed. Traverse the patterns in parallel%% and generate an error if any error binary aliases are found.%% We generate an error even if is obvious that the overall pattern can't%% possibly match, for instance, {a,<<A:8>>,c}={x,<<A:8>>} WILL generate an%% error.reject_bin_alias({bin,Line,_}, {bin,_,_}, St) -> add_error(Line, illegal_bin_pattern, St);reject_bin_alias({cons,_,H1,T1}, {cons,_,H2,T2}, St0) -> St = reject_bin_alias(H1, H2, St0), reject_bin_alias(T1, T2, St);reject_bin_alias({tuple,_,Es1}, {tuple,_,Es2}, St) -> reject_bin_alias_list(Es1, Es2, St);reject_bin_alias({record,_,Name1,Pfs1}, {record,_,Name2,Pfs2}, #lint{records=Recs}=St) -> case {dict:find(Name1, Recs),dict:find(Name2, Recs)} of {{ok,{_Line1,Fields1}},{ok,{_Line2,Fields2}}} -> reject_bin_alias_rec(Pfs1, Pfs2, Fields1, Fields2, St); {_,_} -> %% One or more non-existing records. (An error messages has %% already been generated, so we are done here.) St end;reject_bin_alias(_, _, St) -> St.reject_bin_alias_list([E1|Es1], [E2|Es2], St0) -> St = reject_bin_alias(E1, E2, St0), reject_bin_alias_list(Es1, Es2, St);reject_bin_alias_list(_, _, St) -> St.reject_bin_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, St) -> %% We treat records as if they have been converted to tuples. PfsA1 = rbia_field_vars(PfsA0), PfsB1 = rbia_field_vars(PfsB0), FieldsA1 = rbia_fields(lists:reverse(FieldsA0), 0, []), FieldsB1 = rbia_fields(lists:reverse(FieldsB0), 0, []), FieldsA = sofs:relation(FieldsA1), PfsA = sofs:relation(PfsA1), A = sofs:join(FieldsA, 1, PfsA, 1), FieldsB = sofs:relation(FieldsB1), PfsB = sofs:relation(PfsB1), B = sofs:join(FieldsB, 1, PfsB, 1), C = sofs:join(A, 2, B, 2), D = sofs:projection({external,fun({_,_,P1,_,P2}) -> {P1,P2} end}, C), E = sofs:to_external(D), {Ps1,Ps2} = lists:unzip(E), reject_bin_alias_list(Ps1, Ps2, St).rbia_field_vars(Fs) -> [{Name,Pat} || {record_field,_,{atom,_,Name},Pat} <- Fs].rbia_fields([{record_field,_,{atom,_,Name},_}|Fs], I, Acc) -> rbia_fields(Fs, I+1, [{Name,I}|Acc]);rbia_fields([_|Fs], I, Acc) -> rbia_fields(Fs, I+1, Acc);rbia_fields([], _, Acc) -> Acc.%% is_pattern_expr(Expression) ->%% true | false.%% Test if a general expression is a valid pattern expression.is_pattern_expr(Expr) -> case is_pattern_expr_1(Expr) of false -> false; true -> %% Expression is syntactically correct - make sure that it %% also can be evaluated. case erl_eval:partial_eval(Expr) of {integer,_,_} -> true; {char,_,_} -> true; {float,_,_} -> true; {atom,_,_} -> true; _ -> false end end.is_pattern_expr_1({char,_Line,_C}) -> true;is_pattern_expr_1({integer,_Line,_I}) -> true;is_pattern_expr_1({float,_Line,_F}) -> true;is_pattern_expr_1({atom,_Line,_A}) -> true;is_pattern_expr_1({tuple,_Line,Es}) -> all(fun is_pattern_expr/1, Es);is_pattern_expr_1({nil,_Line}) -> true;is_pattern_expr_1({cons,_Line,H,T}) -> case is_pattern_expr_1(H) of true -> is_pattern_expr_1(T); false -> false end;is_pattern_expr_1({op,_Line,Op,A}) -> case erl_internal:arith_op(Op, 1) of true -> is_pattern_expr_1(A); false -> false end;is_pattern_expr_1({op,_Line,Op,A1,A2}) -> case erl_internal:arith_op(Op, 2) of true -> all(fun is_pattern_expr/1, [A1,A2]); false -> false end;is_pattern_expr_1(_Other) -> false.%% pattern_bin(Line, [Element], VarTable, Old, BinVarTable, State) -> %% {UpdVarTable,UpdBinVarTable,State}.%% Check a pattern group. BinVarTable are used binsize variables.pattern_bin(Line, Es, Vt, Old, Bvt0, St0) -> {Sz,Esvt,Bvt,St1} = foldl(fun (E, Acc) -> pattern_element(E, Vt, Old, Acc) end, {0,[],Bvt0,St0}, Es), St2 = if is_integer(Sz), Sz rem 8 =/= 0 -> case bitlevel_binaries(St1) of true -> St1; false -> add_warning(Line,unaligned_bitpat, St1) end; true -> St1 end, {Esvt,Bvt,St2}.pattern_element({bin_element,Line,E,Sz0,Ts}, Vt, Old, {Size0,Esvt,Bvt,St0}) -> {Pevt,Bvt1,St1} = pat_bit_expr(E, Old, Bvt, St0), %% vtmerge or vtmerge_pat doesn't matter here {Sz1,Szvt,Bvt2,St2} = pat_bit_size(Sz0, vtmerge(Vt, Esvt), Bvt, St1), {Sz2,Bt,St3} = bit_type(Line, Sz1, Ts, St2), {Sz3,St4} = bit_size_check(Line, Sz2, Bt, St3), {Size1,St5} = add_bit_size(Line, Sz3, Size0, false, St4), {Size1,vtmerge(Szvt,vtmerge(Pevt, Esvt)), vtmerge(Bvt2,vtmerge(Bvt, Bvt1)), St5}.%% pat_bit_expr(Pattern, OldVarTable, BinVarTable,State) -> %% {UpdVarTable,UpdBinVarTable,State}.%% Check pattern bit expression, only allow really valid patterns!pat_bit_expr({var,_,'_'}, _Old, _Bvt, St) -> {[],[],St};pat_bit_expr({var,Ln,V}, Old, Bvt, St) -> pat_var(V, Ln, Old, Bvt, St);pat_bit_expr({string,_,_}, _Old, _Bvt, St) -> {[],[],St};pat_bit_expr({bin,L,_}, _Old, _Bvt, St) -> {[],[],add_error(L, illegal_pattern, St)};pat_bit_expr(P, _Old, _Bvt, St) -> case is_pattern_expr(P) of true -> {[],[],St}; false -> {[],[],add_error(element(2, P), illegal_pattern, St)} end.%% pat_bit_size(Size, VarTable, BinVarTable, State) -> %% {Value,UpdVarTable,UpdBinVarTable,State}.%% Check pattern size expression, only allow really valid sizes!pat_bit_size(default, _Vt, _Bvt, St) -> {default,[],[],St};pat_bit_size({atom,_Line,all}, _Vt, _Bvt, St) -> {all,[],[],St};pat_bit_size({var,Lv,V}, Vt0, Bvt0, St0) -> {Vt,Bvt,St1} = pat_binsize_var(V, Lv, Vt0, Bvt0, St0), {unknown,Vt,Bvt,St1};pat_bit_size(Size, _Vt, _Bvt, St) -> Line = element(2, Size), case is_pattern_expr(Size) of true -> case erl_eval:partial_eval(Size) of {integer,Line,I} -> {I,[],[],St}; _Other -> {unknown,[],[],add_error(Line, illegal_bitsize, St)} end; false -> {unknown,[],[],add_error(Line, illegal_bitsize, St)} end.%% expr_bin(Line, [Element], VarTable, State, CheckFun) -> {UpdVarTable,State}.%% Check an expression group.expr_bin(Line, Es, Vt, St0, Check) -> {Sz,Esvt,St1} = foldl(fun (E, Acc) -> bin_element(E, Vt, Acc, Check) end, {0,[],St0}, Es), St2 = if is_integer(Sz), Sz rem 8 =/= 0 -> case bitlevel_binaries(St1) of true -> St1; false -> add_warning(Line,unaligned_bitpat, St1) end; true -> St1 end, {Esvt,St2}.bin_element({bin_element,Line,E,Sz0,Ts}, Vt, {Size0,Esvt,St0}, Check) -> {Vt1,St1} = Check(E, Vt, St0), {Sz1,Vt2,St2} = bit_size(Sz0, Vt, St1, Check), {Sz2,Bt,St3} = bit_type(Line, Sz1, Ts, St2), {Sz3,St4} = bit_size_check(Line, Sz2, Bt, St3), {Size1,St5} = add_bit_size(Line, Sz3, Size0, true, St4), {Size1,vtmerge([Vt2,Vt1,Esvt]),St5}.bit_size(default, _Vt, St, _Check) -> {default,[],St};bit_size({atom,_Line,all}, _Vt, St, _Check) -> {all,[],St};bit_size(Size, Vt, St, Check) -> %% Try to safely evaluate Size if constant to get size, %% otherwise just treat it as an expression. case is_gexpr(Size, St#lint.records) of true -> case erl_eval:partial_eval(Size) of {integer,_ILn,I} -> {I,[],St}; _Other -> {Evt,St1} = Check(Size, Vt, St), {unknown,Evt,St1} end; false -> {Evt,St1} = Check(Size, Vt, St), {unknown,Evt,St1} end.%% bit_type(Line, Size, TypeList, State) -> {Size,#bittype,St}.%% Perform warning check on type and size.bit_type(Line, Size0, Type, St) -> case erl_bits:set_bit_type(Size0, Type) of {ok,Size1,Bt} -> {Size1,Bt,St}; {error,What} -> %% Flag error and generate a default. {ok,Size1,Bt} = erl_bits:set_bit_type(default, []), {Size1,Bt,add_error(Line, What, St)} end.%% bit_size_check(Line, Size, BitType, State) -> {BitSize,State}.%% Do some checking & warnings on types%% float == 32 or 64%% list/binary sizes must be multiple of 8 bit_size_check(_Line, unknown, _, St) -> {unknown,St};bit_size_check(Line, all, #bittype{type=Type}, St) -> if Type =:= binary -> {all,St}; true -> {unknown,add_error(Line, illegal_bitsize, St)} end;bit_size_check(Line, Size, #bittype{type=Type,unit=Unit}, St) -> Sz = Unit * Size, %Total number of bits! St2 = elemtype_check(Line, Type, Sz, St), {Sz,St2}. elemtype_check(_Line, float, 32, St) -> St;elemtype_check(_Line, float, 64, St) -> St;elemtype_check(Line, float, _Size, St) -> add_warning(Line, {bad_bitsize,"float"}, St);elemtype_check(Line, binary, N, St) when (N rem 8) =/= 0 -> case bitlevel_binaries(St) of true -> St; false -> add_warning(Line, {bad_bitsize,"binary"}, St) end;elemtype_check(_Line, _Type, _Size, St) -> St.%% add_bit_size(Line, ElementSize, BinSize, Build, State) -> {Size,State}.%% Add bits to group size.add_bit_size(_Line, all, _Sz2, _B, St) -> {all,St};add_bit_size(Line, Sz1, all, B, St) -> {all, if B =:= false, is_integer(Sz1), Sz1 =/= 0 -> add_error(Line, illegal_bitsize, St); true -> St end};add_bit_size(_Line, unknown, _Sz2, _B, St) -> {unknown,St};add_bit_size(_Line, _Sz1, unknown, _B, St) -> {unknown,St};add_bit_size(_Line, Sz1, Sz2, _B, St) -> {Sz1 + Sz2,St}.%% guard([GuardTest], VarTable, State) ->%% {UsedVarTable,State}%% Check a guard, return all variables.%% Disjunction of guard conjunctionsguard([L|R], Vt, St0) when is_list(L) -> {Gvt, St1} = guard_tests(L, Vt, St0), {Gsvt, St2} = guard(R, vtupdate(Gvt, Vt), St1), {vtupdate(Gvt, Gsvt),St2};guard(L, Vt, St0) -> guard_tests(L, Vt, St0).%% guard conjunctionguard_tests([G|Gs], Vt, St0) -> {Gvt,St1} = guard_test(G, Vt, St0),
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?