ranges: simplify and robustify str_to_rl_helper() a bit
[smatch.git] / check_or_vs_and.c
blob496d8ed6e8e0fd6b7f3fe7c861370023a8c6aed8
1 /*
2 * Copyright (C) 2012 Oracle.
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.
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.
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
18 #include "smatch.h"
19 #include "smatch_function_hashtable.h"
21 static int my_id;
23 DEFINE_STRING_HASHTABLE_STATIC(unconstant_macros);
25 static int does_inc_dec(struct expression *expr)
27 if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) {
28 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
29 return 1;
30 return does_inc_dec(expr->unop);
32 return 0;
35 static int expr_equiv(struct expression *one, struct expression *two)
37 struct symbol *one_sym, *two_sym;
38 char *one_name = NULL;
39 char *two_name = NULL;
40 int ret = 0;
42 if (does_inc_dec(one) || does_inc_dec(two))
43 return 0;
45 one_name = expr_to_str_sym(one, &one_sym);
46 if (!one_name || !one_sym)
47 goto free;
48 two_name = expr_to_str_sym(two, &two_sym);
49 if (!two_name || !two_sym)
50 goto free;
51 if (one_sym != two_sym)
52 goto free;
53 if (strcmp(one_name, two_name) == 0)
54 ret = 1;
55 free:
56 free_string(one_name);
57 free_string(two_name);
58 return ret;
61 static int inconsistent_check(struct expression *left, struct expression *right)
63 sval_t sval;
65 if (get_value(left->left, &sval)) {
66 if (get_value(right->left, &sval))
67 return expr_equiv(left->right, right->right);
68 if (get_value(right->right, &sval))
69 return expr_equiv(left->right, right->left);
70 return 0;
72 if (get_value(left->right, &sval)) {
73 if (get_value(right->left, &sval))
74 return expr_equiv(left->left, right->right);
75 if (get_value(right->right, &sval))
76 return expr_equiv(left->left, right->left);
77 return 0;
80 return 0;
83 static void check_or(struct expression *expr)
85 struct expression *left, *right;
87 left = strip_expr(expr->left);
88 right = strip_expr(expr->right);
90 if (left->type != EXPR_COMPARE ||
91 left->op != SPECIAL_NOTEQUAL)
92 return;
93 if (right->type != EXPR_COMPARE ||
94 right->op != SPECIAL_NOTEQUAL)
95 return;
96 if (!inconsistent_check(left, right))
97 return;
99 sm_msg("warn: was && intended here instead of ||?");
102 static void check_and(struct expression *expr)
104 struct expression *left, *right;
106 left = strip_expr(expr->left);
107 right = strip_expr(expr->right);
109 if (left->type != EXPR_COMPARE ||
110 left->op != SPECIAL_EQUAL)
111 return;
112 if (right->type != EXPR_COMPARE ||
113 right->op != SPECIAL_EQUAL)
114 return;
115 if (!inconsistent_check(left, right))
116 return;
118 sm_msg("warn: was || intended here instead of &&?");
121 static void match_logic(struct expression *expr)
123 if (expr->type != EXPR_LOGICAL)
124 return;
126 if (expr->op == SPECIAL_LOGICAL_OR)
127 check_or(expr);
128 if (expr->op == SPECIAL_LOGICAL_AND)
129 check_and(expr);
132 static int is_unconstant_macro(struct expression *expr)
134 char *macro;
136 macro = get_macro_name(expr->pos);
137 if (!macro)
138 return 0;
139 if (search_unconstant_macros(unconstant_macros, macro))
140 return 1;
141 return 0;
144 static void match_condition(struct expression *expr)
146 sval_t sval;
148 if (expr->type != EXPR_BINOP)
149 return;
150 if (expr->op == '|') {
151 if (get_value(expr->left, &sval) || get_value(expr->right, &sval))
152 sm_msg("warn: suspicious bitop condition");
153 return;
156 if (expr->op != '&')
157 return;
159 if (get_macro_name(expr->pos))
160 return;
161 if (is_unconstant_macro(expr->left) || is_unconstant_macro(expr->right))
162 return;
164 if ((get_value(expr->left, &sval) && sval.value == 0) ||
165 (get_value(expr->right, &sval) && sval.value == 0))
166 sm_msg("warn: bitwise AND condition is false here");
169 static void match_binop(struct expression *expr)
171 sval_t left, right, sval;
173 if (expr->op != '&')
174 return;
175 if (!get_value(expr, &sval) || sval.value != 0)
176 return;
177 if (get_macro_name(expr->pos))
178 return;
179 if (!get_value(expr->left, &left) || !get_value(expr->right, &right))
180 return;
181 sm_msg("warn: odd binop '0x%llx & 0x%llx'", left.uvalue, right.uvalue);
184 void check_or_vs_and(int id)
186 my_id = id;
188 unconstant_macros = create_function_hashtable(100);
189 load_strings("unconstant_macros", unconstant_macros);
191 add_hook(&match_logic, LOGIC_HOOK);
192 add_hook(&match_condition, CONDITION_HOOK);
193 if (option_spammy)
194 add_hook(&match_binop, BINOP_HOOK);