2 * Copyright (C) 2009 Dan Carpenter.
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
19 * This check is supposed to find places like this:
24 * (the first assignment isn't used)
26 * How the check works is that every assignment gets an ID.
27 * We store that assignment ID in a list of assignments that
28 * haven't been used. We also set the state of 'err' from
29 * the example above to be. Then when we use 'err' we remove
30 * it from the list. At the end of the function we print
31 * a list of assignments that still haven't been used.
33 * Note that this check only works for assignments to
34 * EXPR_SYMBOL. Maybe it could be modified to cover other
35 * assignments later but then you would have to deal with
38 * Also this state is quite tied to the order the callbacks
39 * are called in smatch_flow.c. (If the order changed it
45 #include "smatch_slist.h"
46 #include "smatch_function_hashtable.h"
56 ALLOCATOR(assignment
, "assignment id");
57 DECLARE_PTR_LIST(assignment_list
, struct assignment
);
58 static struct assignment_list
*assignment_list
;
60 static struct expression
*skip_this
;
63 static DEFINE_HASHTABLE_INSERT(insert_func
, char, int);
64 static DEFINE_HASHTABLE_SEARCH(search_func
, char, int);
65 static struct hashtable
*ignored_funcs
;
67 static const char *kernel_ignored
[] = {
76 static char *get_fn_name(struct expression
*expr
)
78 if (expr
->type
!= EXPR_CALL
)
80 if (expr
->fn
->type
!= EXPR_SYMBOL
)
82 return expr_to_var(expr
->fn
);
85 static int ignored_function(struct expression
*expr
)
90 func
= get_fn_name(expr
);
93 if (search_func(ignored_funcs
, func
))
99 static void match_assign_call(struct expression
*expr
)
101 struct expression
*left
;
102 struct assignment
*assign
;
112 if (ignored_function(expr
->right
))
114 left
= strip_expr(expr
->left
);
115 if (!left
|| left
->type
!= EXPR_SYMBOL
)
117 if (left
->symbol
->ctype
.modifiers
& (MOD_TOPLEVEL
| MOD_EXTERN
| MOD_STATIC
))
122 set_state_expr(my_id
, left
, alloc_state_num(assign_id
));
124 assign
= __alloc_assignment(0);
125 assign
->assign_id
= assign_id
++;
126 assign
->name
= expr_to_var(left
);
127 assign
->function
= get_fn_name(expr
->right
);
128 assign
->line
= get_lineno();
129 add_ptr_list(&assignment_list
, assign
);
132 static void match_assign(struct expression
*expr
)
134 struct expression
*left
;
138 left
= strip_expr(expr
->left
);
139 if (!left
|| left
->type
!= EXPR_SYMBOL
)
141 set_state_expr(my_id
, left
, &undefined
);
144 static void delete_used(int assign_id
)
146 struct assignment
*tmp
;
148 FOR_EACH_PTR(assignment_list
, tmp
) {
149 if (tmp
->assign_id
== assign_id
) {
150 DELETE_CURRENT_PTR(tmp
);
153 } END_FOR_EACH_PTR(tmp
);
156 static void delete_used_symbols(struct state_list
*possible
)
158 struct sm_state
*tmp
;
160 FOR_EACH_PTR(possible
, tmp
) {
161 delete_used(PTR_INT(tmp
->state
->data
));
162 } END_FOR_EACH_PTR(tmp
);
165 static void match_symbol(struct expression
*expr
)
169 expr
= strip_expr(expr
);
170 if (expr
== skip_this
)
172 sm
= get_sm_state_expr(my_id
, expr
);
175 delete_used_symbols(sm
->possible
);
176 set_state_expr(my_id
, expr
, &undefined
);
179 static void match_end_func(struct symbol
*sym
)
181 struct assignment
*tmp
;
185 FOR_EACH_PTR(assignment_list
, tmp
) {
186 sm_printf("%s:%d %s ", get_filename(), tmp
->line
, get_function());
187 sm_printf("warn: unused return: %s = %s()\n",
188 tmp
->name
, tmp
->function
);
189 } END_FOR_EACH_PTR(tmp
);
190 clear_assignment_alloc();
191 __free_ptr_list((struct ptr_list
**)&assignment_list
);
194 void check_unused_ret(int id
)
198 /* It turns out that this test is worthless unless you use --two-passes. */
199 if (!option_two_passes
)
201 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
202 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
203 add_hook(&match_symbol
, SYM_HOOK
);
204 add_hook(&match_end_func
, END_FUNC_HOOK
);
205 ignored_funcs
= create_function_hashtable(100);
206 if (option_project
== PROJ_KERNEL
) {
209 for (i
= 0; i
< ARRAY_SIZE(kernel_ignored
); i
++)
210 insert_func(ignored_funcs
, (char *)kernel_ignored
[i
], (int *)1);