Small clean up. Move the passing the whole condition into the new
[smatch.git] / smatch_flow.c
blob443671aa3f8ee9d638ae728f661571c0548f87e7
1 /*
2 * sparse/smatch_flow.c
4 * Copyright (C) 2006,2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdio.h>
11 #include "token.h"
12 #include "smatch.h"
14 int __smatch_lineno = 0;
16 static char *filename;
17 static char *cur_func;
18 static int line_func_start;
19 static unsigned int path_id = 0;
20 static unsigned int path_id_next = 1;
22 char *get_filename() { return filename; }
23 char *get_function() { return cur_func; }
24 int get_lineno() { return __smatch_lineno; }
25 int get_func_pos() { return __smatch_lineno - line_func_start; }
27 static void split_statements(struct statement *stmt);
28 static void split_symlist(struct symbol_list *sym_list);
29 static void split_expr_list(struct expression_list *expr_list);
31 unsigned int get_path_id()
33 return path_id;
36 unsigned int __split_path_id()
38 int tmp = path_id;
40 path_id = path_id_next++;
41 return tmp;
44 void __restore_path_id(int old_id)
46 path_id = old_id;
51 void __split_expr(struct expression *expr)
53 if (!expr)
54 return;
56 __smatch_lineno = expr->pos.line;
57 __pass_to_client(expr, EXPR_HOOK);
59 // printf("%d Debug expr_type %d\n", get_lineno(), expr->type);
61 switch (expr->type) {
62 case EXPR_PREOP:
63 case EXPR_POSTOP:
64 if (expr->op == '*')
65 __pass_to_client(expr, DEREF_HOOK);
66 __split_expr(expr->unop);
67 return;
68 case EXPR_STATEMENT:
69 split_statements(expr->statement);
70 return;
71 case EXPR_BINOP:
72 case EXPR_COMMA:
73 case EXPR_COMPARE:
74 case EXPR_LOGICAL:
75 case EXPR_ASSIGNMENT:
76 if (expr->type == EXPR_ASSIGNMENT)
77 __pass_to_client(expr, ASSIGNMENT_HOOK);
78 __split_expr(expr->left);
79 __split_expr(expr->right);
80 if (expr->type == EXPR_ASSIGNMENT)
81 __pass_to_client(expr, ASSIGNMENT_AFTER_HOOK);
82 return;
83 case EXPR_DEREF:
84 __pass_to_client(expr, DEREF_HOOK);
85 __split_expr(expr->deref);
86 return;
87 case EXPR_SLICE:
88 __split_expr(expr->base);
89 return;
90 case EXPR_CAST:
91 __split_expr(expr->cast_expression);
92 return;
93 case EXPR_SIZEOF:
94 /* there isn't anything to pass a client from inside a sizeof() */
95 return;
96 case EXPR_CONDITIONAL:
97 case EXPR_SELECT:
98 __split_true_false_paths();
99 __split_whole_condition(expr->conditional);
100 __use_true_states();
101 __split_expr(expr->cond_true);
102 __use_false_states();
103 __split_expr(expr->cond_false);
104 __merge_true_states();
105 return;
106 case EXPR_CALL:
107 __pass_to_client(expr, FUNCTION_CALL_HOOK);
108 __split_expr(expr->fn);
109 split_expr_list(expr->args);
110 __pass_to_client(expr, FUNCTION_CALL_AFTER_HOOK);
111 #ifdef KERNEL
112 if (expr->fn->type == EXPR_SYMBOL &&
113 !strcmp(expr->fn->symbol_name->name, "panic"))
114 nullify_path();
115 #endif
116 return;
117 case EXPR_INITIALIZER:
118 split_expr_list(expr->expr_list);
119 return;
120 case EXPR_IDENTIFIER:
121 __split_expr(expr->ident_expression);
122 return;
123 case EXPR_INDEX:
124 __split_expr(expr->idx_expression);
125 return;
126 case EXPR_POS:
127 __split_expr(expr->init_expr);
128 return;
129 default:
130 return;
134 static int is_forever_loop(struct statement *stmt)
137 struct expression *expr;
139 expr = stmt->iterator_pre_condition;
140 if (!expr)
141 expr = stmt->iterator_post_condition;
142 if (!expr) {
143 // this is a for(;;) loop...
144 return 1;
147 if (expr->type == EXPR_VALUE && expr->value == 1) {
148 return 1;
151 return 0;
155 * Pre Loops are while and for loops.
158 static void handle_pre_loop(struct statement *stmt)
160 unsigned int path_orig;
162 split_statements(stmt->iterator_pre_statement);
164 __split_true_false_paths();
165 __push_continues();
166 __push_breaks();
167 if (stmt->iterator_pre_condition) {
168 __split_whole_condition(stmt->iterator_pre_condition);
170 path_orig = __split_path_id();
171 __use_true_states();
173 split_statements(stmt->iterator_statement);
174 split_statements(stmt->iterator_post_statement);
175 if (is_forever_loop(stmt)) {
176 __pop_continues();
177 __pop_false_states();
178 nullify_path();
179 } else {
180 __merge_false_states();
181 __merge_continues();
183 __merge_breaks();
184 __restore_path_id(path_orig);
188 * Post loops are do {} while();
190 static void handle_post_loop(struct statement *stmt)
192 __push_continues();
193 __push_breaks();
194 split_statements(stmt->iterator_statement);
196 __split_true_false_paths();
197 __split_whole_condition(stmt->iterator_post_condition);
198 /* It would prossibly be cleaner to make this all one function */
199 __use_true_states();
200 __use_false_states();
201 __pop_true_states();
203 if (is_forever_loop(stmt)) {
204 __pop_continues();
205 nullify_path();
206 } else {
207 __merge_continues();
209 __merge_breaks();
212 static void split_statements(struct statement *stmt)
214 unsigned int path_orig;
216 if (!stmt)
217 return;
219 __smatch_lineno = stmt->pos.line;
220 __pass_to_client(stmt, STMT_HOOK);
222 switch (stmt->type) {
223 case STMT_DECLARATION:
224 __pass_declarations_to_client(stmt->declaration);
225 split_symlist(stmt->declaration);
226 return;
227 case STMT_RETURN:
228 __pass_to_client(stmt, RETURN_HOOK);
229 __split_expr(stmt->ret_value);
230 nullify_path();
231 return;
232 case STMT_EXPRESSION:
233 __split_expr(stmt->expression);
234 return;
235 case STMT_COMPOUND: {
236 struct statement *s;
237 FOR_EACH_PTR(stmt->stmts, s) {
238 split_statements(s);
239 } END_FOR_EACH_PTR(s);
240 return;
242 case STMT_IF:
243 __split_true_false_paths();
244 __split_whole_condition(stmt->if_conditional);
245 path_orig = __split_path_id();
246 __use_true_states();
247 split_statements(stmt->if_true);
248 __split_path_id();
249 __use_false_states();
250 split_statements(stmt->if_false);
251 __merge_true_states();
252 __restore_path_id(path_orig);
253 return;
254 case STMT_ITERATOR:
255 if (stmt->iterator_pre_condition)
256 handle_pre_loop(stmt);
257 else if (stmt->iterator_post_condition)
258 handle_post_loop(stmt);
259 else {
260 // these are for(;;) type loops.
261 handle_pre_loop(stmt);
263 return;
264 case STMT_SWITCH:
265 __split_expr(stmt->switch_expression);
266 __save_switch_states();
267 __push_default();
268 __push_breaks();
269 nullify_path();
270 path_orig = get_path_id();
271 split_statements(stmt->switch_statement);
272 if (!__pop_default())
273 __merge_switches();
274 __pop_switches();
275 __merge_breaks();
276 __restore_path_id(path_orig);
277 return;
278 case STMT_CASE:
279 __split_path_id();
280 __merge_switches();
281 if (!stmt->case_expression)
282 __set_default();
283 __split_expr(stmt->case_expression);
284 __split_expr(stmt->case_to);
285 split_statements(stmt->case_statement);
286 return;
287 case STMT_LABEL:
288 if (stmt->label &&
289 stmt->label->type == SYM_LABEL &&
290 stmt->label->ident) {
291 __merge_gotos(stmt->label->ident->name);
293 split_statements(stmt->label_statement);
294 return;
295 case STMT_GOTO:
296 __split_expr(stmt->goto_expression);
297 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
298 if (!strcmp(stmt->goto_label->ident->name, "break")) {
299 __process_breaks();
300 } else if (!strcmp(stmt->goto_label->ident->name,
301 "continue")) {
302 __process_continues();
304 } else if (stmt->goto_label &&
305 stmt->goto_label->type == SYM_LABEL &&
306 stmt->goto_label->ident) {
307 __save_gotos(stmt->goto_label->ident->name);
309 nullify_path();
310 return;
311 case STMT_NONE:
312 return;
313 case STMT_ASM:
314 __split_expr(stmt->asm_string);
315 //__split_expr(stmt->asm_outputs);
316 //__split_expr(stmt->asm_inputs);
317 //__split_expr(stmt->asm_clobbers);
318 return;
319 case STMT_CONTEXT:
320 return;
321 case STMT_RANGE:
322 __split_expr(stmt->range_expression);
323 __split_expr(stmt->range_low);
324 __split_expr(stmt->range_high);
325 return;
329 static void split_expr_list(struct expression_list *expr_list)
331 struct expression *expr;
332 FOR_EACH_PTR(expr_list, expr) {
333 __split_expr(expr);
334 } END_FOR_EACH_PTR(expr);
338 static void split_sym(struct symbol *sym)
340 if (!sym)
341 return;
342 if (!(sym->namespace & NS_SYMBOL))
343 return;
345 __pass_to_client(sym, SYM_HOOK);
346 split_statements(sym->stmt);
347 __split_expr(sym->array_size);
348 split_symlist(sym->arguments);
349 split_symlist(sym->symbol_list);
350 split_statements(sym->inline_stmt);
351 split_symlist(sym->inline_symbol_list);
352 __split_expr(sym->initializer);
355 static void split_symlist(struct symbol_list *sym_list)
357 struct symbol *sym;
359 FOR_EACH_PTR(sym_list, sym) {
360 split_sym(sym);
361 } END_FOR_EACH_PTR(sym);
364 static void split_functions(struct symbol_list *sym_list)
366 struct symbol *sym;
368 FOR_EACH_PTR(sym_list, sym) {
369 struct symbol *base_type;
370 base_type = get_base_type(sym);
371 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
372 if (base_type->stmt)
373 line_func_start = base_type->stmt->pos.line;
374 if (sym->ident)
375 cur_func = sym->ident->name;
376 __smatch_lineno = sym->pos.line;
377 __pass_to_client(sym, FUNC_DEF_HOOK);
378 split_statements(base_type->stmt);
379 __pass_to_client(sym, END_FUNC_HOOK);
380 cur_func = NULL;
381 line_func_start = 0;
382 clear_all_states();
384 } else {
385 __pass_to_client(sym, BASE_HOOK);
387 } END_FOR_EACH_PTR(sym);
390 void smatch (int argc, char **argv)
393 struct string_list *filelist = NULL;
394 struct symbol_list *sym_list;
396 if (argc < 2) {
397 printf("Usage: smatch <filename.c>\n");
398 exit(1);
400 sparse_initialize(argc, argv, &filelist);
401 FOR_EACH_PTR_NOTAG(filelist, filename) {
402 sym_list = __sparse(filename);
403 split_functions(sym_list);
404 } END_FOR_EACH_PTR_NOTAG(filename);