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