1 /*
   2  * Copyright (C) 2010 Dan Carpenter.
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public License
   6  * as published by the Free Software Foundation; either version 2
   7  * of the License, or (at your option) any later version.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  * GNU General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public License
  15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
  16  */
  17 
  18 #include "smatch.h"
  19 #include "smatch_extra.h"
  20 
  21 static int my_id;
  22 
  23 static int is_bool(struct expression *expr)
  24 {
  25         struct symbol *type;
  26 
  27         type = get_type(expr);
  28         if (!type)
  29                 return 0;
  30         if (type_bits(type) == 1 && type->ctype.modifiers & MOD_UNSIGNED)
  31                 return 1;
  32         return 0;
  33 }
  34 
  35 static int is_bool_from_context(struct expression *expr)
  36 {
  37         sval_t sval;
  38 
  39         if (!get_implied_max(expr, &sval) || sval.uvalue > 1)
  40                 return 0;
  41         if (!get_implied_min(expr, &sval) || sval.value < 0)
  42                 return 0;
  43         return 1;
  44 }
  45 
  46 static int is_bool_op(struct expression *expr)
  47 {
  48         expr = strip_expr(expr);
  49 
  50         if (expr->type == EXPR_PREOP && expr->op == '!')
  51                 return 1;
  52         if (expr->type == EXPR_COMPARE)
  53                 return 1;
  54         if (expr->type == EXPR_LOGICAL)
  55                 return 1;
  56         return is_bool(expr);
  57 }
  58 
  59 static void match_condition(struct expression *expr)
  60 {
  61         int print = 0;
  62 
  63         if (expr->type == EXPR_COMPARE) {
  64                 if (expr->left->type == EXPR_COMPARE || expr->right->type == EXPR_COMPARE)
  65                         print = 1;
  66                 if (expr->left->type == EXPR_PREOP && expr->left->op == '!') {
  67                         if (expr->left->unop->type == EXPR_PREOP && expr->left->unop->op == '!')
  68                                 return;
  69                         if (expr->right->op == '!')
  70                                 return;
  71                         if (is_bool(expr->right))
  72                                 return;
  73                         if (is_bool(expr->left->unop))
  74                                 return;
  75                         if (is_bool_from_context(expr->left->unop))
  76                                 return;
  77                         print = 1;
  78                 }
  79         }
  80 
  81         if (expr->type == EXPR_BINOP) {
  82                 if (expr->left->type == EXPR_COMPARE || expr->right->type == EXPR_COMPARE)
  83                         print = 1;
  84         }
  85 
  86         if (print) {
  87                 sm_warning("add some parenthesis here?");
  88                 return;
  89         }
  90 
  91         if (expr->type == EXPR_BINOP && expr->op == '&') {
  92                 int i = 0;
  93 
  94                 if (is_bool_op(expr->left))
  95                         i++;
  96                 if (is_bool_op(expr->right))
  97                         i++;
  98                 if (i == 1)
  99                         sm_warning("maybe use && instead of &");
 100         }
 101 }
 102 
 103 static void match_binop(struct expression *expr)
 104 {
 105         if (expr->op != '&')
 106                 return;
 107         if (expr->left->op == '!')
 108                 sm_warning("add some parenthesis here?");
 109 }
 110 
 111 static void match_mask(struct expression *expr)
 112 {
 113         if (expr->op != '&')
 114                 return;
 115         if (expr->right->type != EXPR_BINOP)
 116                 return;
 117         if (expr->right->op != SPECIAL_RIGHTSHIFT)
 118                 return;
 119 
 120         sm_warning("shift has higher precedence than mask");
 121 }
 122 
 123 static void match_subtract_shift(struct expression *expr)
 124 {
 125         if (expr->op != SPECIAL_LEFTSHIFT)
 126                 return;
 127         if (expr->right->type != EXPR_BINOP)
 128                 return;
 129         if (expr->right->op != '-')
 130                 return;
 131         sm_warning("subtract is higher precedence than shift");
 132 }
 133 
 134 void check_precedence(int id)
 135 {
 136         my_id = id;
 137 
 138         add_hook(&match_condition, CONDITION_HOOK);
 139         add_hook(&match_binop, BINOP_HOOK);
 140         add_hook(&match_mask, BINOP_HOOK);
 141         add_hook(&match_subtract_shift, BINOP_HOOK);
 142 }