More range fixes. (Delete and merge duplicates)
[smatch.git] / smatch_conditions.c
blob48986267f7ee541c4970b95a013c57000007bf0c
1 /*
2 * sparse/smatch_conditions.c
4 * Copyright (C) 2006,2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * The simplest type of condition is
12 * if (a) { ...
14 * The next simplest kind of conditions is
15 * if (a && b) { c;
16 * In that case 'a' is true when we get to 'b' and both are true
17 * when we get to c.
19 * Or's are a little more complicated.
20 * if (a || b) { c;
21 * We know 'a' is not true when we get to 'b' but it may be true
22 * when we get to c.
24 * If we mix and's and or's that's even more complicated.
25 * if (a && b && c || a && d) { d ;
26 * 'a' is true when we get to 'b', 'c' and 'd'.
27 * 'b' is true when we reach 'c' but otherwise we don't know.
29 * The other thing that complicates matters is if we negate
30 * some if conditions.
31 * if (!a) { ...
32 * We pass the un-negated version to the client and flip the true
33 * and false values internally.
35 * And negations can be part of a compound.
36 * if (a && !(b || c)) { d;
37 * In that situation we multiply the negative through to simplify
38 * stuff so that we can remove the parens like this:
39 * if (a && !b && !c) { d;
41 * One other thing is that:
42 * if ((a) != 0){ ...
43 * that's basically the same as testing for just 'a' so we simplify
44 * it before passing it to the script.
47 #include "smatch.h"
49 static void split_conditions(struct expression *expr);
51 static int is_logical_and(struct expression *expr)
53 if (expr->op == SPECIAL_LOGICAL_AND)
54 return 1;
55 return 0;
58 static int handle_zero_comparisons(struct expression *expr)
60 struct expression *tmp = NULL;
62 // if left is zero or right is zero
63 if (is_zero(expr->left))
64 tmp = expr->right;
65 else if (is_zero(expr->right))
66 tmp = expr->left;
67 else
68 return 0;
70 // "if (foo != 0)" is the same as "if (foo)"
71 if (expr->op == SPECIAL_NOTEQUAL) {
72 split_conditions(tmp);
73 return 1;
76 // "if (foo == 0)" is the same as "if (!foo)"
77 if (expr->op == SPECIAL_EQUAL) {
78 split_conditions(tmp);
79 __negate_cond_stacks();
80 return 1;
83 return 0;
87 * This function is for handling calls to likely/unlikely
90 static int ignore_builtin_expect(struct expression *expr)
92 if (sym_name_is("__builtin_expect", expr->fn)) {
93 split_conditions(first_ptr_list((struct ptr_list *) expr->args));
94 return 1;
96 if (sym_name_is("__builtin_constant_p", expr->fn)) {
97 split_conditions(first_ptr_list((struct ptr_list *) expr->args));
98 return 1;
100 return 0;
104 * handle_compound_stmt() is for: foo = ({blah; blah; blah; 1})
107 static void handle_compound_stmt(struct statement *stmt)
109 struct expression *expr = NULL;
110 struct statement *last;
111 struct statement *s;
113 last = last_ptr_list((struct ptr_list *)stmt->stmts);
114 if (last->type != STMT_EXPRESSION) {
115 last = NULL;
116 } else {
117 expr = last->expression;
119 FOR_EACH_PTR(stmt->stmts, s) {
120 if (s != last)
121 __split_statements(s);
122 } END_FOR_EACH_PTR(s);
123 split_conditions(expr);
124 return;
127 static int handle_preop(struct expression *expr)
129 struct statement *stmt;
131 if (expr->op == '!') {
132 split_conditions(expr->unop);
133 __negate_cond_stacks();
134 return 1;
136 stmt = get_block_thing(expr);
137 if (stmt) {
138 handle_compound_stmt(stmt);
139 return 1;
141 return 0;
144 static void handle_logical(struct expression *expr)
147 * If we come to an "and" expr then:
148 * We split the left side.
149 * We keep all the current states.
150 * We split the right side.
151 * We keep all the states from both true sides.
153 * If it's an "or" expr then:
154 * We save the current slist.
155 * We split the left side.
156 * We use the false states for the right side.
157 * We split the right side.
158 * We save all the states that are the same on both sides.
161 split_conditions(expr->left);
163 if (!is_logical_and(expr))
164 __use_cond_false_states();
166 __push_cond_stacks();
168 __save_pre_cond_states();
169 split_conditions(expr->right);
170 __pop_pre_cond_states();
172 if (is_logical_and(expr)) {
173 __and_cond_states();
174 } else {
175 __or_cond_states();
177 __use_cond_true_states();
180 static int handle_rostedt_if(struct expression *expr)
182 if (expr->type != EXPR_CALL)
183 return 0;
184 if (!sym_name_is("__builtin_constant_p", expr->fn))
185 return 0;
186 split_conditions(expr);
187 return 1;
190 static void handle_select(struct expression *expr)
193 * if ((aaa()?bbb():ccc())) { ...
195 * This is almost the same as:
196 * if ((aaa() && bbb()) || (!aaa() && ccc())) { ...
198 * It's a bit complicated because we shouldn't pass aaa()
199 * to the clients more than once.
202 if (handle_rostedt_if(expr->conditional))
203 return;
205 split_conditions(expr->conditional);
207 __save_false_states_for_later();
209 if (implied_condition_true(expr->cond_true)) {
210 __split_expr(expr->cond_true);
211 } else {
212 __push_cond_stacks();
213 split_conditions(expr->cond_true);
214 __and_cond_states();
217 if (implied_condition_false(expr->cond_false)) {
218 __split_expr(expr->cond_false);
219 __pop_pre_cond_states();
220 return;
223 __use_previously_stored_false_states();
225 __save_pre_cond_states();
226 __push_cond_stacks();
227 split_conditions(expr->cond_false);
228 __or_cond_states();
229 __pop_pre_cond_states();
231 __use_cond_true_states();
234 static void split_conditions(struct expression *expr)
237 sm_debug("%d in split_conditions type=%d\n", get_lineno(), expr->type);
239 expr = strip_expr(expr);
240 if (!expr)
241 return;
243 switch(expr->type) {
244 case EXPR_LOGICAL:
245 handle_logical(expr);
246 return;
247 case EXPR_COMPARE:
248 if (handle_zero_comparisons(expr))
249 return;
250 break;
251 case EXPR_CALL:
252 if (ignore_builtin_expect(expr))
253 return;
254 break;
255 case EXPR_PREOP:
256 if (handle_preop(expr))
257 return;
258 break;
259 case EXPR_CONDITIONAL:
260 case EXPR_SELECT:
261 handle_select(expr);
262 return;
265 /* fixme: this should be in smatch_flow.c
266 but because of the funny stuff we do with conditions
267 it's awkward to put it there. We would need to
268 call CONDITION_HOOK in smatch_flow as well.
270 if (expr->type == EXPR_COMPARE) {
271 if (expr->left->type != EXPR_POSTOP)
272 __split_expr(expr->left);
273 if (expr->right->type != EXPR_POSTOP)
274 __split_expr(expr->right);
275 } else {
276 __split_expr(expr);
278 __pass_to_client(expr, CONDITION_HOOK);
279 if (expr->type == EXPR_COMPARE) {
280 if (expr->left->type == EXPR_POSTOP)
281 __split_expr(expr->left);
282 if (expr->right->type == EXPR_POSTOP)
283 __split_expr(expr->right);
287 static int inside_condition;
288 void __split_whole_condition(struct expression *expr)
290 sm_debug("%d in __split_whole_condition\n", get_lineno());
291 inside_condition++;
292 __save_pre_cond_states();
293 __push_cond_stacks();
294 if (expr)
295 split_conditions(expr);
296 __use_cond_states();
297 __pass_to_client(expr, WHOLE_CONDITION_HOOK);
298 inside_condition--;
301 int in_condition()
303 return inside_condition;