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 } 143