Add known_condition_false()
[smatch.git] / smatch_extra.c
blobd88d47d504a7cee6479bdf3f0872f2d120908799
1 /*
2 * sparse/smatch_extra.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include "parse.h"
12 #include "smatch.h"
14 static int my_id;
16 static int _zero = 0;
17 static int _one = 1;
19 static struct smatch_state zero = {
20 .name = "zero",
21 .data = &_zero,
24 static struct smatch_state one = {
25 .name = "one",
26 .data = &_one,
29 static struct smatch_state *alloc_state(int val)
31 struct smatch_state *state;
33 if (val == 0)
34 return &zero;
35 if (val == 1)
36 return &one;
37 if (val == UNDEFINED)
38 return &undefined;
40 state = malloc(sizeof(*state));
41 state->name = "value";
42 state->data = malloc(sizeof(int));
43 *(int *)state->data = val;
44 return state;
47 static void match_function_call_after(struct expression *expr)
49 struct expression *tmp;
50 struct symbol *sym;
51 char *name;
52 int i = 0;
54 FOR_EACH_PTR(expr->args, tmp) {
55 if (tmp->op == '&') {
56 name = get_variable_from_expr(tmp->unop, &sym);
57 if (name) {
58 set_state(name, my_id, sym, &undefined);
61 i++;
62 } END_FOR_EACH_PTR(tmp);
65 static void match_assign(struct expression *expr)
67 struct expression *left;
68 struct symbol *sym;
69 char *name;
71 left = strip_expr(expr->left);
72 name = get_variable_from_expr(left, &sym);
73 if (!name)
74 return;
75 set_state(name, my_id, sym, alloc_state(get_value(expr->right)));
78 static void undef_expr(struct expression *expr)
80 struct symbol *sym;
81 char *name;
83 name = get_variable_from_expr(expr->unop, &sym);
84 if (!name)
85 return;
86 if (!get_state(name, my_id, sym)) {
87 free_string(name);
88 return;
90 set_state(name, my_id, sym, &undefined);
93 static void match_declarations(struct symbol *sym)
95 const char *name;
97 if (sym->ident) {
98 name = sym->ident->name;
99 if (sym->initializer) {
100 set_state(name, my_id, sym, alloc_state(get_value(sym->initializer)));
105 static void match_unop(struct expression *expr)
107 struct symbol *sym;
108 char *name;
109 const char *tmp;
112 name = get_variable_from_expr(expr->unop, &sym);
113 if (!name)
114 return;
116 tmp = show_special(expr->op);
117 if ((!strcmp(tmp, "--")) || (!strcmp(tmp, "++")))
118 set_state(name, my_id, sym, &undefined);
121 void register_smatch_extra(int id)
123 my_id = id;
124 add_hook(&undef_expr, OP_HOOK);
125 add_hook(&match_function_call_after, FUNCTION_CALL_AFTER_HOOK);
126 add_hook(&match_assign, ASSIGNMENT_AFTER_HOOK);
127 add_hook(&match_declarations, DECLARATION_HOOK);
128 add_hook(&match_unop, OP_HOOK);
131 static int expr_to_val(struct expression *expr)
133 struct smatch_state *state;
134 int val;
135 struct symbol *sym;
136 char *name;
138 val = get_value(expr);
139 if (val != UNDEFINED)
140 return val;
142 name = get_variable_from_expr(expr, &sym);
143 if (!name)
144 return UNDEFINED;
145 state = get_state(name, my_id, sym);
146 free_string(name);
147 if (!state || !state->data)
148 return UNDEFINED;
149 return *(int *)state->data;
152 static int true_comparison(int left, int comparison, int right)
154 switch(comparison){
155 case '<':
156 case SPECIAL_UNSIGNED_LT:
157 if (left < right)
158 return 1;
159 return 0;
160 case SPECIAL_UNSIGNED_LTE:
161 case SPECIAL_LTE:
162 if (left < right)
163 return 1;
164 case SPECIAL_EQUAL:
165 if (left == right)
166 return 1;
167 return 0;
168 case SPECIAL_UNSIGNED_GTE:
169 case SPECIAL_GTE:
170 if (left == right)
171 return 1;
172 case '>':
173 case SPECIAL_UNSIGNED_GT:
174 if (left > right)
175 return 1;
176 return 0;
177 case SPECIAL_NOTEQUAL:
178 if (left != right)
179 return 1;
180 return 0;
181 default:
182 smatch_msg("unhandled comparison %d\n", comparison);
183 return UNDEFINED;
185 return 0;
188 static int do_comparison(struct expression *expr)
190 int left, right, ret;
192 if ((left = expr_to_val(expr->left)) == UNDEFINED)
193 return UNDEFINED;
195 if ((right = expr_to_val(expr->right)) == UNDEFINED)
196 return UNDEFINED;
198 ret = true_comparison(left, expr->op, right);
199 if (ret == 1) {
200 SM_DEBUG("%d known condition: %d %s %d => true\n",
201 get_lineno(), left, show_special(expr->op), right);
202 } else if (ret == 0) {
203 SM_DEBUG("%d known condition: %d %s %d => false\n",
204 get_lineno(), left, show_special(expr->op), right);
206 return ret;
209 struct statement *get_block_thing(struct expression *expr)
211 /* What are those things called? if (({....; ret;})) { ...*/
213 if (expr->type != EXPR_PREOP)
214 return NULL;
215 if (expr->op != '(')
216 return NULL;
217 if (expr->unop->type != EXPR_STATEMENT)
218 return NULL;
219 if (expr->unop->statement->type != STMT_COMPOUND)
220 return NULL;
221 return expr->unop->statement;
224 int last_stmt_val(struct statement *stmt)
226 struct expression *expr;
228 stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
229 if (stmt->type != STMT_EXPRESSION)
230 return UNDEFINED;
231 expr = stmt->expression;
232 return get_value(expr);
235 int known_condition_true(struct expression *expr)
237 if (!expr)
238 return 0;
240 switch(expr->type) {
241 case EXPR_COMPARE:
242 if (do_comparison(expr) == 1)
243 return 1;
244 case EXPR_PREOP: {
245 struct statement *stmt;
246 struct expression *tmp;
248 stmt = get_block_thing(expr);
249 if (stmt && (last_stmt_val(stmt) == 1))
250 return 1;
251 tmp = strip_expr(expr);
252 if (tmp != expr)
253 return known_condition_true(tmp);
254 break;
257 return 0;
260 int known_condition_false(struct expression *expr)
262 if (!expr)
263 return 0;
265 if (is_zero(expr))
266 return 1;
268 switch(expr->type) {
269 case EXPR_COMPARE:
270 if (do_comparison(expr) == 0)
271 return 1;
272 case EXPR_PREOP: {
273 struct statement *stmt;
274 struct expression *tmp;
276 stmt = get_block_thing(expr);
277 if (stmt && (last_stmt_val(stmt) == 0))
278 return 1;
279 tmp = strip_expr(expr);
280 if (tmp != expr)
281 return known_condition_false(tmp);
282 break;
285 return 0;