diff --git a/infer/src/erlang/ErlangTranslator.ml b/infer/src/erlang/ErlangTranslator.ml index 563f6fe44..5d19b1c05 100644 --- a/infer/src/erlang/ErlangTranslator.ml +++ b/infer/src/erlang/ErlangTranslator.ml @@ -280,6 +280,18 @@ let rec translate_pattern env (value : Ident.t) {Ast.line; simple_expression} : let exit_failure = Node.make_if env false (Var id) in start |~~> [exit_success; exit_failure] ; {start; exit_success; exit_failure} + | UnaryOperator _ -> + (* Unary op pattern must evaluate to number, so just delegate to expression translation *) + let id = Ident.create_fresh Ident.knormal in + let expr_block = + translate_expression {env with result= Present (Exp.Var id)} {Ast.line; simple_expression} + in + let cond = Exp.BinOp (Eq, Var value, Var id) in + let start = Node.make_nop env in + let exit_success = Node.make_if env true cond in + let exit_failure = Node.make_if env false cond in + start |~~> [exit_success; exit_failure] ; + Block.all env [expr_block; {start; exit_success; exit_failure}] | Variable vname when String.equal vname "_" -> Block.make_success env | Variable vname -> @@ -298,7 +310,7 @@ let rec translate_pattern env (value : Ident.t) {Ast.line; simple_expression} : Block.make_failure env -let rec translate_expression env {Ast.line; simple_expression} = +and translate_expression env {Ast.line; simple_expression} = let env = update_location line env in let any = ptr_typ_of_name Any in let (Present result) = env.result in @@ -432,6 +444,25 @@ let rec translate_expression env {Ast.line; simple_expression} = let fun_exp = Exp.Const (Cfun BuiltinDecl.__erlang_make_nil) in let instruction = Sil.Call ((ret_var, any), fun_exp, [], env.location, CallFlags.default) in Block.make_instruction env [instruction] + | UnaryOperator (op, e) -> + let id = Ident.create_fresh Ident.knormal in + let block = translate_expression {env with result= Present (Exp.Var id)} e in + let make_simple_op_block sil_op = + Block.make_load env ret_var (Exp.UnOp (sil_op, Var id, None)) any + in + let op_block = + match op with + | UMinus -> + make_simple_op_block Neg + | UNot -> + make_simple_op_block LNot + | todo -> + L.debug Capture Verbose + "@[todo ErlangTranslator.translate_expression(UnaryOperator) %s@." + (Sexp.to_string (Ast.sexp_of_unary_operator todo)) ; + Block.make_success env + in + Block.all env [block; op_block] | Variable vname -> let e = Exp.Lvar (Pvar.mk (Mangled.from_string vname) procname) in let load_instr = Sil.Load {id= ret_var; e; root_typ= any; typ= any; loc= env.location} in diff --git a/infer/tests/codetoanalyze/erlang/features/issues.exp b/infer/tests/codetoanalyze/erlang/features/issues.exp index 0e3399d67..4a7bb55ec 100644 --- a/infer/tests/codetoanalyze/erlang/features/issues.exp +++ b/infer/tests/codetoanalyze/erlang/features/issues.exp @@ -1,7 +1,13 @@ -codetoanalyze/erlang/features/src/arithmetic.erl, test_add_Bad/0, -9, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] -codetoanalyze/erlang/features/src/arithmetic.erl, test_idiv1_Bad/0, -54, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] -codetoanalyze/erlang/features/src/arithmetic.erl, test_mul_Bad/0, -39, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] -codetoanalyze/erlang/features/src/arithmetic.erl, test_multiple_Bad/0, -98, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] -codetoanalyze/erlang/features/src/arithmetic.erl, test_rem_Bad/0, -85, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] -codetoanalyze/erlang/features/src/arithmetic.erl, test_sub_Bad/0, -24, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_add1_Bad/0, -9, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_add2_Bad/0, -24, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_idiv1_Bad/0, -114, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_mul1_Bad/0, -69, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_mul2_Bad/0, -84, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_mul3_Bad/0, -99, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_multiple_Bad/0, -158, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_rem_Bad/0, -145, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_sub1_Bad/0, -39, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_sub2_Bad/0, -54, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_uminus1_Bad/0, -170, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] +codetoanalyze/erlang/features/src/arithmetic.erl, test_uminus2_Bad/0, -183, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [calling context starts here,in call to `warn/1`,no pattern match here] codetoanalyze/erlang/features/src/arithmetic.erl, warn/1, 0, NONEXHAUSTIVE_PATTERN_MATCH, no_bucket, ERROR, [*** LATENT ***,no pattern match here] diff --git a/infer/tests/codetoanalyze/erlang/features/src/arithmetic.erl b/infer/tests/codetoanalyze/erlang/features/src/arithmetic.erl index 722359188..47057b3c1 100644 --- a/infer/tests/codetoanalyze/erlang/features/src/arithmetic.erl +++ b/infer/tests/codetoanalyze/erlang/features/src/arithmetic.erl @@ -6,12 +6,20 @@ -module(arithmetic). -export([ - test_add_Ok/0, - test_add_Bad/0, - test_sub_Ok/0, - test_sub_Bad/0, - test_mul_Ok/0, - test_mul_Bad/0, + test_add1_Ok/0, + test_add1_Bad/0, + test_add2_Ok/0, + test_add2_Bad/0, + test_sub1_Ok/0, + test_sub1_Bad/0, + test_sub2_Ok/0, + test_sub2_Bad/0, + test_mul1_Ok/0, + test_mul1_Bad/0, + test_mul2_Ok/0, + test_mul2_Bad/0, + test_mul3_Ok/0, + test_mul3_Bad/0, test_idiv1_Ok/0, test_idiv1_Bad/0, test_idiv2_Ok/0, @@ -19,20 +27,24 @@ test_rem_Ok/0, test_rem_Bad/0, test_multiple_Ok/0, - test_multiple_Bad/0 + test_multiple_Bad/0, + test_uminus1_Ok/0, + test_uminus1_Bad/0, + test_uminus2_Ok/0, + test_uminus2_Bad/0 ]). % Call this method with warn(1) to trigger a warning to expect warn(0) -> ok. -test_add_Ok() -> +test_add1_Ok() -> X = 2, Y = 3, case X + Y of 5 -> ok; _ -> warn(1) end. -test_add_Bad() -> +test_add1_Bad() -> X = 2, Y = 3, case X + Y of @@ -40,14 +52,29 @@ test_add_Bad() -> _ -> ok end. -test_sub_Ok() -> +test_add2_Ok() -> + X = 2, + Y = -3, + case X + Y of + -1 -> ok; + _ -> warn(1) + end. +test_add2_Bad() -> + X = 2, + Y = -3, + case X + Y of + -1 -> warn(1); + _ -> ok + end. + +test_sub1_Ok() -> X = 5, Y = 3, case X - Y of 2 -> ok; _ -> warn(1) end. -test_sub_Bad() -> +test_sub1_Bad() -> X = 5, Y = 3, case X - Y of @@ -55,14 +82,29 @@ test_sub_Bad() -> _ -> ok end. -test_mul_Ok() -> +test_sub2_Ok() -> + X = 3, + Y = 5, + case X - Y of + -2 -> ok; + _ -> warn(1) + end. +test_sub2_Bad() -> + X = 3, + Y = 5, + case X - Y of + -2 -> warn(1); + _ -> ok + end. + +test_mul1_Ok() -> X = 5, Y = 3, case X * Y of 15 -> ok; _ -> warn(1) end. -test_mul_Bad() -> +test_mul1_Bad() -> X = 5, Y = 3, case X * Y of @@ -70,6 +112,36 @@ test_mul_Bad() -> _ -> ok end. +test_mul2_Ok() -> + X = -5, + Y = 3, + case X * Y of + -15 -> ok; + _ -> warn(1) + end. +test_mul2_Bad() -> + X = -5, + Y = 3, + case X * Y of + -15 -> warn(1); + _ -> ok + end. + +test_mul3_Ok() -> + X = -5, + Y = -3, + case X * Y of + 15 -> ok; + _ -> warn(1) + end. +test_mul3_Bad() -> + X = -5, + Y = -3, + case X * Y of + 15 -> warn(1); + _ -> ok + end. + test_idiv1_Ok() -> X = 21, Y = 3, @@ -126,3 +198,29 @@ test_multiple_Bad() -> 30 -> warn(1); _ -> ok end. + +test_uminus1_Ok() -> + X = -3, + case -X of + 3 -> ok; + _ -> warn(1) + end. +test_uminus1_Bad() -> + X = -3, + case -X of + 3 -> warn(1); + _ -> ok + end. + +test_uminus2_Ok() -> + X = 5, + case -X of + -5 -> ok; + _ -> warn(1) + end. +test_uminus2_Bad() -> + X = 5, + case -X of + -5 -> warn(1); + _ -> ok + end.