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 
is_bool(struct expression * expr)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 
is_bool_from_context(struct expression * expr)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 
is_bool_op(struct expression * expr)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 
match_condition(struct expression * expr)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 
match_binop(struct expression * expr)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 
match_mask(struct expression * expr)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 
match_mask_compare(struct expression * expr)123 static void match_mask_compare(struct expression *expr)
124 {
125 	if (expr->op != '&')
126 		return;
127 	if (expr->right->type != EXPR_COMPARE)
128 		return;
129 
130 	sm_warning("compare has higher precedence than mask");
131 }
132 
match_subtract_shift(struct expression * expr)133 static void match_subtract_shift(struct expression *expr)
134 {
135 	if (expr->op != SPECIAL_LEFTSHIFT)
136 		return;
137 	if (expr->right->type != EXPR_BINOP)
138 		return;
139 	if (expr->right->op != '-')
140 		return;
141 	sm_warning("subtract is higher precedence than shift");
142 }
143 
check_precedence(int id)144 void check_precedence(int id)
145 {
146 	my_id = id;
147 
148 	add_hook(&match_condition, CONDITION_HOOK);
149 	add_hook(&match_binop, BINOP_HOOK);
150 	add_hook(&match_mask, BINOP_HOOK);
151 	add_hook(&match_mask_compare, BINOP_HOOK);
152 	add_hook(&match_subtract_shift, BINOP_HOOK);
153 }
154