ranges: function_hooks: move in_list_exact() to function hooks
[smatch.git] / smatch_function_hooks.c
blobb0f01bd2cf9decb23b7d2fa137f9550465251465
1 /*
2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * There are several types of function hooks:
12 * add_function_hook() - For any time a function is called.
13 * add_function_assign_hook() - foo = the_function().
14 * add_implied_return_hook() - Calculates the implied return value.
15 * add_macro_assign_hook() - foo = the_macro().
16 * return_implies_state() - For when a return value of 1 implies locked
17 * and 0 implies unlocked. etc. etc.
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
26 #include "smatch_function_hashtable.h"
28 struct fcall_back {
29 int type;
30 struct data_range *range;
31 union {
32 func_hook *call_back;
33 implication_hook *ranged;
34 implied_return_hook *implied_return;
35 } u;
36 void *info;
39 ALLOCATOR(fcall_back, "call backs");
40 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
42 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
43 static struct hashtable *func_hash;
45 #define REGULAR_CALL 0
46 #define RANGED_CALL 1
47 #define ASSIGN_CALL 2
48 #define IMPLIED_RETURN 3
49 #define MACRO_ASSIGN 4
50 #define MACRO_ASSIGN_EXTRA 5
52 struct return_implies_callback {
53 int type;
54 return_implies_hook *callback;
56 ALLOCATOR(return_implies_callback, "return_implies callbacks");
57 DECLARE_PTR_LIST(db_implies_list, struct return_implies_callback);
58 static struct db_implies_list *db_implies_list;
59 static struct db_implies_list *db_return_states_list;
61 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
62 void *info)
64 struct fcall_back *cb;
66 cb = __alloc_fcall_back(0);
67 cb->type = type;
68 cb->u.call_back = call_back;
69 cb->info = info;
70 return cb;
73 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
75 struct fcall_back *cb;
77 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
78 add_callback(func_hash, look_for, cb);
81 void add_function_assign_hook(const char *look_for, func_hook *call_back,
82 void *info)
84 struct fcall_back *cb;
86 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
87 add_callback(func_hash, look_for, cb);
90 void add_implied_return_hook(const char *look_for,
91 implied_return_hook *call_back,
92 void *info)
94 struct fcall_back *cb;
96 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
97 add_callback(func_hash, look_for, cb);
100 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
101 void *info)
103 struct fcall_back *cb;
105 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
106 add_callback(func_hash, look_for, cb);
109 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
110 void *info)
112 struct fcall_back *cb;
114 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
115 add_callback(func_hash, look_for, cb);
118 void return_implies_state(const char *look_for, long long start, long long end,
119 implication_hook *call_back, void *info)
121 struct fcall_back *cb;
123 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
124 cb->range = alloc_range_perm(start, end);
125 add_callback(func_hash, look_for, cb);
128 void add_db_return_implies_callback(int type, return_implies_hook *callback)
130 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
132 cb->type = type;
133 cb->callback = callback;
134 add_ptr_list(&db_implies_list, cb);
137 void add_db_return_states_callback(int type, return_implies_hook *callback)
139 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
141 cb->type = type;
142 cb->callback = callback;
143 add_ptr_list(&db_return_states_list, cb);
146 static int call_call_backs(struct call_back_list *list, int type,
147 const char *fn, struct expression *expr)
149 struct fcall_back *tmp;
150 int handled = 0;
152 FOR_EACH_PTR(list, tmp) {
153 if (tmp->type == type) {
154 (tmp->u.call_back)(fn, expr, tmp->info);
155 handled = 1;
157 } END_FOR_EACH_PTR(tmp);
159 return handled;
162 static void call_ranged_call_backs(struct call_back_list *list,
163 const char *fn, struct expression *call_expr,
164 struct expression *assign_expr)
166 struct fcall_back *tmp;
168 FOR_EACH_PTR(list, tmp) {
169 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
170 } END_FOR_EACH_PTR(tmp);
173 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
174 struct data_range *drange)
176 struct call_back_list *ret = NULL;
177 struct fcall_back *tmp;
179 FOR_EACH_PTR(list, tmp) {
180 if (tmp->type != RANGED_CALL)
181 continue;
182 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
183 add_ptr_list(&ret, tmp);
184 } END_FOR_EACH_PTR(tmp);
185 return ret;
188 static int in_list_exact(struct range_list *list, struct data_range *drange)
190 struct data_range *tmp;
192 FOR_EACH_PTR(list, tmp) {
193 if (tmp->min == drange->min && tmp->max == drange->max)
194 return 1;
195 } END_FOR_EACH_PTR(tmp);
196 return 0;
199 static int assign_ranged_funcs(const char *fn, struct expression *expr,
200 struct call_back_list *call_backs)
202 struct fcall_back *tmp;
203 struct sm_state *sm;
204 char *var_name;
205 struct symbol *sym;
206 struct smatch_state *estate;
207 struct state_list *tmp_slist;
208 struct state_list *final_states = NULL;
209 struct range_list *handled_ranges = NULL;
210 struct call_back_list *same_range_call_backs = NULL;
211 int handled = 0;
213 if (!call_backs)
214 return 0;
216 var_name = get_variable_from_expr(expr->left, &sym);
217 if (!var_name || !sym)
218 goto free;
220 FOR_EACH_PTR(call_backs, tmp) {
221 if (tmp->type != RANGED_CALL)
222 continue;
223 if (in_list_exact(handled_ranges, tmp->range))
224 continue;
225 __push_fake_cur_slist();
226 tack_on(&handled_ranges, tmp->range);
228 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
229 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
230 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
232 estate = alloc_estate_range(tmp->range->min, tmp->range->max);
233 set_extra_mod(var_name, sym, estate);
235 tmp_slist = __pop_fake_cur_slist();
236 merge_slist(&final_states, tmp_slist);
237 free_slist(&tmp_slist);
238 handled = 1;
239 } END_FOR_EACH_PTR(tmp);
241 FOR_EACH_PTR(final_states, sm) {
242 __set_sm(sm);
243 } END_FOR_EACH_PTR(sm);
245 free_slist(&final_states);
246 free:
247 free_string(var_name);
248 return handled;
251 int call_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
253 struct call_back_list *call_backs;
254 struct fcall_back *tmp;
255 const char *fn;
256 struct data_range *value_range;
257 struct state_list *true_states = NULL;
258 struct state_list *false_states = NULL;
259 struct state_list *tmp_slist;
260 struct sm_state *sm;
262 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
263 return 0;
264 fn = expr->fn->symbol->ident->name;
265 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
266 if (!call_backs)
267 return 0;
268 value_range = alloc_range(value, value);
270 /* set true states */
271 __push_fake_cur_slist();
272 FOR_EACH_PTR(call_backs, tmp) {
273 if (tmp->type != RANGED_CALL)
274 continue;
275 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
276 continue;
277 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
278 } END_FOR_EACH_PTR(tmp);
279 tmp_slist = __pop_fake_cur_slist();
280 merge_slist(&true_states, tmp_slist);
281 free_slist(&tmp_slist);
283 /* set false states */
284 __push_fake_cur_slist();
285 FOR_EACH_PTR(call_backs, tmp) {
286 if (tmp->type != RANGED_CALL)
287 continue;
288 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
289 continue;
290 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
291 } END_FOR_EACH_PTR(tmp);
292 tmp_slist = __pop_fake_cur_slist();
293 merge_slist(&false_states, tmp_slist);
294 free_slist(&tmp_slist);
296 FOR_EACH_PTR(true_states, sm) {
297 __set_true_false_sm(sm, NULL);
298 } END_FOR_EACH_PTR(sm);
299 FOR_EACH_PTR(false_states, sm) {
300 __set_true_false_sm(NULL, sm);
301 } END_FOR_EACH_PTR(sm);
303 free_slist(&true_states);
304 free_slist(&false_states);
305 return 1;
308 struct db_callback_info {
309 int true_side;
310 int comparison;
311 struct expression *expr;
312 struct range_list *rl;
313 int left;
314 struct state_list *slist;
315 struct db_implies_list *callbacks;
317 static struct db_callback_info db_info;
318 static int db_compare_callback(void *unused, int argc, char **argv, char **azColName)
320 struct range_list *ret_range;
321 int type, param;
322 char *key, *value;
323 struct return_implies_callback *tmp;
325 if (argc != 5)
326 return 0;
328 get_value_ranges(argv[0], &ret_range);
329 type = atoi(argv[1]);
330 param = atoi(argv[2]);
331 key = argv[3];
332 value = argv[4];
334 if (db_info.true_side) {
335 if (!possibly_true_range_lists_rl(db_info.comparison,
336 ret_range, db_info.rl,
337 db_info.left))
338 return 0;
339 } else {
340 if (!possibly_false_range_lists_rl(db_info.comparison,
341 ret_range, db_info.rl,
342 db_info.left))
343 return 0;
346 FOR_EACH_PTR(db_info.callbacks, tmp) {
347 if (tmp->type == type)
348 tmp->callback(db_info.expr, param, key, value);
349 } END_FOR_EACH_PTR(tmp);
350 return 0;
353 void compare_db_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
355 struct symbol *sym;
356 static char sql_filter[1024];
357 struct state_list *true_states;
358 struct state_list *false_states;
359 struct sm_state *sm;
361 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
362 return;
364 sym = expr->fn->symbol;
365 if (!sym)
366 return;
368 if (sym->ctype.modifiers & MOD_STATIC) {
369 snprintf(sql_filter, 1024,
370 "file = '%s' and function = '%s' and static = '1';",
371 get_filename(), sym->ident->name);
372 } else {
373 snprintf(sql_filter, 1024,
374 "function = '%s' and static = '0';", sym->ident->name);
377 db_info.comparison = comparison;
378 db_info.expr = expr;
379 db_info.rl = alloc_range_list(value, value);
380 db_info.left = left;
381 db_info.callbacks = db_implies_list;
383 db_info.true_side = 1;
384 __push_fake_cur_slist();
385 run_sql(db_compare_callback,
386 "select return, type, parameter, key, value from return_implies where %s",
387 sql_filter);
388 true_states = __pop_fake_cur_slist();
390 db_info.true_side = 0;
391 __push_fake_cur_slist();
392 run_sql(db_compare_callback,
393 "select return, type, parameter, key, value from return_implies where %s",
394 sql_filter);
395 false_states = __pop_fake_cur_slist();
397 FOR_EACH_PTR(true_states, sm) {
398 __set_true_false_sm(sm, NULL);
399 } END_FOR_EACH_PTR(sm);
400 FOR_EACH_PTR(false_states, sm) {
401 __set_true_false_sm(NULL, sm);
402 } END_FOR_EACH_PTR(sm);
404 free_slist(&true_states);
405 free_slist(&false_states);
408 void compare_db_return_states_callbacks(int comparison, struct expression *expr, long long value, int left)
410 struct symbol *sym;
411 static char sql_filter[1024];
412 struct state_list *true_states;
413 struct state_list *false_states;
414 struct sm_state *sm;
416 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
417 return;
419 sym = expr->fn->symbol;
420 if (!sym)
421 return;
423 if (sym->ctype.modifiers & MOD_STATIC) {
424 snprintf(sql_filter, 1024,
425 "file = '%s' and function = '%s' and static = '1';",
426 get_filename(), sym->ident->name);
427 } else {
428 snprintf(sql_filter, 1024,
429 "function = '%s' and static = '0';", sym->ident->name);
432 db_info.comparison = comparison;
433 db_info.expr = expr;
434 db_info.rl = alloc_range_list(value, value);
435 db_info.left = left;
436 db_info.callbacks = db_return_states_list;
438 db_info.true_side = 1;
439 __push_fake_cur_slist();
440 run_sql(db_compare_callback,
441 "select return, type, parameter, key, value from return_states where %s",
442 sql_filter);
443 true_states = __pop_fake_cur_slist();
445 db_info.true_side = 0;
446 __push_fake_cur_slist();
447 run_sql(db_compare_callback,
448 "select return, type, parameter, key, value from return_states where %s",
449 sql_filter);
450 false_states = __pop_fake_cur_slist();
452 FOR_EACH_PTR(true_states, sm) {
453 __set_true_false_sm(sm, NULL);
454 } END_FOR_EACH_PTR(sm);
455 FOR_EACH_PTR(false_states, sm) {
456 __set_true_false_sm(NULL, sm);
457 } END_FOR_EACH_PTR(sm);
459 free_slist(&true_states);
460 free_slist(&false_states);
465 void function_comparison(int comparison, struct expression *expr,
466 long long value, int left)
468 if (call_implies_callbacks(comparison, expr, value, left))
469 return;
470 compare_db_implies_callbacks(comparison, expr, value, left);
471 compare_db_return_states_callbacks(comparison, expr, value, left);
474 static int db_assign_callback(void *unused, int argc, char **argv, char **azColName)
476 struct range_list *ret_range;
477 int type, param;
478 char *key, *value;
479 struct return_implies_callback *tmp;
480 struct state_list *slist;
482 if (argc != 5)
483 return 0;
485 get_value_ranges(argv[0], &ret_range);
486 type = atoi(argv[1]);
487 param = atoi(argv[2]);
488 key = argv[3];
489 value = argv[4];
491 __push_fake_cur_slist();
492 FOR_EACH_PTR(db_implies_list, tmp) {
493 if (tmp->type == type)
494 tmp->callback(db_info.expr->right, param, key, value);
495 } END_FOR_EACH_PTR(tmp);
496 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
497 slist = __pop_fake_cur_slist();
499 merge_slist(&db_info.slist, slist);
501 return 0;
504 static int db_return_implies_assign(struct expression *expr)
506 struct symbol *sym;
507 static char sql_filter[1024];
508 static struct sm_state *sm;
509 int handled = 0;
511 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
512 return 0;
514 sym = expr->right->fn->symbol;
515 if (!sym)
516 return 0;
518 if (sym->ctype.modifiers & MOD_STATIC) {
519 snprintf(sql_filter, 1024,
520 "file = '%s' and function = '%s' and static = '1';",
521 get_filename(), sym->ident->name);
522 } else {
523 snprintf(sql_filter, 1024,
524 "function = '%s' and static = '0';", sym->ident->name);
527 db_info.expr = expr;
528 db_info.slist = NULL;
529 run_sql(db_assign_callback,
530 "select return, type, parameter, key, value from return_implies where %s",
531 sql_filter);
533 FOR_EACH_PTR(db_info.slist, sm) {
534 __set_sm(sm);
535 handled = 1;
536 } END_FOR_EACH_PTR(sm);
538 return handled;
541 static int prev_return_id;
542 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
544 struct range_list *ret_range;
545 int type, param;
546 char *key, *value;
547 struct return_implies_callback *tmp;
548 struct state_list *slist;
549 int return_id;
551 if (argc != 6)
552 return 0;
554 return_id = atoi(argv[0]);
555 get_value_ranges(argv[1], &ret_range);
556 if (!ret_range)
557 ret_range = whole_range_list();
558 type = atoi(argv[2]);
559 param = atoi(argv[3]);
560 key = argv[4];
561 value = argv[5];
563 if (prev_return_id != -1 && return_id != prev_return_id) {
564 slist = __pop_fake_cur_slist();
565 merge_slist(&db_info.slist, slist);
566 __push_fake_cur_slist();
568 prev_return_id = return_id;
570 FOR_EACH_PTR(db_return_states_list, tmp) {
571 if (tmp->type == type)
572 tmp->callback(db_info.expr, param, key, value);
573 } END_FOR_EACH_PTR(tmp);
574 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
576 return 0;
579 static int db_return_states_assign(struct expression *expr)
581 struct expression *right;
582 struct symbol *sym;
583 struct sm_state *sm;
584 struct state_list *slist;
585 static char sql_filter[1024];
586 int handled = 0;
588 right = strip_expr(expr->right);
589 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
590 return 0;
592 sym = right->fn->symbol;
593 if (!sym)
594 return 0;
596 if (sym->ctype.modifiers & MOD_STATIC) {
597 snprintf(sql_filter, 1024,
598 "file = '%s' and function = '%s' and static = '1';",
599 get_filename(), sym->ident->name);
600 } else {
601 snprintf(sql_filter, 1024,
602 "function = '%s' and static = '0';", sym->ident->name);
605 prev_return_id = -1;
606 db_info.expr = expr;
607 db_info.slist = NULL;
608 __push_fake_cur_slist();
609 run_sql(db_assign_return_states_callback,
610 "select return_id, return, type, parameter, key, value from return_states where %s",
611 sql_filter);
612 slist = __pop_fake_cur_slist();
613 merge_slist(&db_info.slist, slist);
615 FOR_EACH_PTR(db_info.slist, sm) {
616 __set_sm(sm);
617 handled = 1;
618 } END_FOR_EACH_PTR(sm);
620 return handled;
623 static int handle_implied_return(struct expression *expr)
625 struct range_list *rl;
627 if (!get_implied_return(expr->right, &rl))
628 return 0;
629 set_extra_expr_mod(expr->left, alloc_estate_range_list(rl));
630 return 1;
633 static void match_assign_call(struct expression *expr)
635 struct call_back_list *call_backs;
636 const char *fn;
637 struct expression *right;
638 int handled = 0;
640 right = strip_expr(expr->right);
641 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
642 set_extra_expr_mod(expr->left, extra_undefined());
643 return;
645 fn = right->fn->symbol->ident->name;
648 * some of these conflict (they try to set smatch extra twice), so we
649 * call them in order from least important to most important.
652 call_backs = search_callback(func_hash, (char *)fn);
653 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
655 handled |= db_return_states_assign(expr);
656 handled |= db_return_implies_assign(expr);
657 handled |= assign_ranged_funcs(fn, expr, call_backs);
658 handled |= handle_implied_return(expr);
660 if (!handled)
661 set_extra_expr_mod(expr->left, extra_undefined());
664 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
666 struct range_list *ret_range;
667 int type, param;
668 char *key, *value;
669 struct return_implies_callback *tmp;
670 struct state_list *slist;
671 int return_id;
673 if (argc != 6)
674 return 0;
676 return_id = atoi(argv[0]);
677 get_value_ranges(argv[1], &ret_range);
678 type = atoi(argv[2]);
679 param = atoi(argv[3]);
680 key = argv[4];
681 value = argv[5];
683 if (prev_return_id != -1 && return_id != prev_return_id) {
684 slist = __pop_fake_cur_slist();
685 merge_slist(&db_info.slist, slist);
686 __push_fake_cur_slist();
688 prev_return_id = return_id;
690 FOR_EACH_PTR(db_return_states_list, tmp) {
691 if (tmp->type == type)
692 tmp->callback(db_info.expr, param, key, value);
693 } END_FOR_EACH_PTR(tmp);
695 return 0;
698 static void db_return_states(struct expression *expr)
700 struct symbol *sym;
701 struct sm_state *sm;
702 struct state_list *slist;
703 static char sql_filter[1024];
705 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
706 return;
708 sym = expr->fn->symbol;
709 if (!sym)
710 return;
712 if (sym->ctype.modifiers & MOD_STATIC) {
713 snprintf(sql_filter, 1024,
714 "file = '%s' and function = '%s' and static = '1';",
715 get_filename(), sym->ident->name);
716 } else {
717 snprintf(sql_filter, 1024,
718 "function = '%s' and static = '0';", sym->ident->name);
721 prev_return_id = -1;
722 db_info.expr = expr;
723 db_info.slist = NULL;
724 __push_fake_cur_slist();
725 run_sql(db_return_states_callback,
726 "select return_id, return, type, parameter, key, value from return_states where %s",
727 sql_filter);
728 slist = __pop_fake_cur_slist();
729 merge_slist(&db_info.slist, slist);
731 FOR_EACH_PTR(db_info.slist, sm) {
732 __set_sm(sm);
733 } END_FOR_EACH_PTR(sm);
736 static int is_assigned_call(struct expression *expr)
738 struct expression *tmp;
740 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
741 if (tmp->type == EXPR_ASSIGNMENT && strip_expr(tmp->right) == expr)
742 return 1;
743 if (tmp->pos.line < expr->pos.line)
744 return 0;
745 } END_FOR_EACH_PTR_REVERSE(tmp);
746 return 0;
749 static void db_return_states_call(struct expression *expr)
751 if (is_assigned_call(expr))
752 return;
753 db_return_states(expr);
756 static void match_function_call(struct expression *expr)
758 struct call_back_list *call_backs;
760 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
761 return;
762 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
763 if (call_backs)
764 call_call_backs(call_backs, REGULAR_CALL,
765 expr->fn->symbol->ident->name, expr);
766 db_return_states_call(expr);
769 static void match_macro_assign(struct expression *expr)
771 struct call_back_list *call_backs;
772 const char *macro;
773 struct expression *right;
775 right = strip_expr(expr->right);
776 macro = get_macro_name(right->pos);
777 call_backs = search_callback(func_hash, (char *)macro);
778 if (!call_backs)
779 return;
780 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
781 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
784 int get_implied_return(struct expression *expr, struct range_list **rl)
786 struct call_back_list *call_backs;
787 struct fcall_back *tmp;
788 int handled = 0;
789 char *fn;
791 *rl = NULL;
793 expr = strip_expr(expr);
794 fn = get_variable_from_expr(expr->fn, NULL);
795 if (!fn)
796 goto out;
798 call_backs = search_callback(func_hash, fn);
800 FOR_EACH_PTR(call_backs, tmp) {
801 if (tmp->type == IMPLIED_RETURN) {
802 (tmp->u.implied_return)(expr, tmp->info, rl);
803 handled = 1;
805 } END_FOR_EACH_PTR(tmp);
807 out:
808 free_string(fn);
809 return handled;
812 void create_function_hook_hash(void)
814 func_hash = create_function_hashtable(5000);
817 void register_function_hooks(int id)
819 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
820 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
821 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);