From 0dca20e5881ba0d04529672d4bfbf3fb2f1d4632 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Mar 2013 13:31:37 +0300 Subject: [PATCH] extra: handle MOD_ASSIGN better MOD_ASSIGN has a known upper limit, preserve it. Probably this should be expanded to other kinds of assignments as well. Signed-off-by: Dan Carpenter --- smatch_expressions.c | 11 +++++++++++ smatch_extra.c | 39 +++++++++++++++++++++++++++++++++++++++ smatch_extra.h | 1 + 3 files changed, 51 insertions(+) diff --git a/smatch_expressions.c b/smatch_expressions.c index 90f567ee..cc06dd8f 100644 --- a/smatch_expressions.c +++ b/smatch_expressions.c @@ -58,6 +58,17 @@ struct expression *assign_expression(struct expression *left, struct expression return expr; } +struct expression *binop_expression(struct expression *left, int op, struct expression *right) +{ + struct expression *expr; + + expr = alloc_expression(right->pos, EXPR_BINOP); + expr->op = op; + expr->left = left; + expr->right = right; + return expr; +} + struct expression *symbol_expression(struct symbol *sym) { struct expression *expr; diff --git a/smatch_extra.c b/smatch_extra.c index 5cb9d03a..3f6a9b2d 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -454,11 +454,40 @@ static int types_equiv_or_pointer(struct symbol *one, struct symbol *two) return types_equiv(one, two); } +static int op_remove_assign(int op) +{ + switch (op) { + case SPECIAL_ADD_ASSIGN: + return '+'; + case SPECIAL_SUB_ASSIGN: + return '-'; + case SPECIAL_MUL_ASSIGN: + return '*'; + case SPECIAL_DIV_ASSIGN: + return '/'; + case SPECIAL_MOD_ASSIGN: + return '%'; + case SPECIAL_AND_ASSIGN: + return '&'; + case SPECIAL_OR_ASSIGN: + return '|'; + case SPECIAL_XOR_ASSIGN: + return '^'; + case SPECIAL_SHL_ASSIGN: + return SPECIAL_LEFTSHIFT; + case SPECIAL_SHR_ASSIGN: + return SPECIAL_RIGHTSHIFT; + default: + return op; + } +} + static void match_assign(struct expression *expr) { struct range_list *rl = NULL; struct expression *left; struct expression *right; + struct expression *binop_expr; struct symbol *right_sym; char *right_name = NULL; struct symbol *sym; @@ -529,6 +558,16 @@ static void match_assign(struct expression *expr) if (!inside_loop() && known && get_implied_min(left, &tmp)) right_min = sval_binop(tmp, '-', value); break; + case SPECIAL_AND_ASSIGN: + case SPECIAL_MOD_ASSIGN: + binop_expr = binop_expression(expr->left, + op_remove_assign(expr->op), + expr->right); + if (get_implied_rl(binop_expr, &rl)) { + rl = cast_rl(get_type(expr->left), rl); + set_extra_mod(name, sym, alloc_estate_rl(rl)); + goto free; + } } if (!sval_is_min(right_min) || !sval_is_max(right_max)) rl = cast_rl(get_type(expr->left), alloc_rl(right_min, right_max)); diff --git a/smatch_extra.h b/smatch_extra.h index 07435f7e..9719b154 100644 --- a/smatch_extra.h +++ b/smatch_extra.h @@ -148,6 +148,7 @@ struct expression *value_expr(long long val); struct expression *member_expression(struct expression *deref, int op, struct ident *member); struct expression *deref_expression(struct expression *expr); struct expression *assign_expression(struct expression *left, struct expression *right); +struct expression *binop_expression(struct expression *left, int op, struct expression *right); struct expression *symbol_expression(struct symbol *sym); -- 2.11.4.GIT