unreachable code: don't warn about empty statements
[smatch.git] / check_balanced.c
blobd7b9432b4df6bad3d9a13e286fdb0b208819ef00
1 /*
2 * sparse/check_prempt.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * This test checks that prempt is enabled at the end of every function.
14 #include "smatch.h"
15 #include "smatch_slist.h"
17 static int my_id;
19 STATE(left);
20 STATE(right);
21 STATE(start_state);
23 static struct tracker_list *starts_left;
24 static struct tracker_list *starts_right;
26 static struct smatch_state *get_start_state(struct sm_state *sm)
28 int is_left = 0;
29 int is_right = 0;
31 if (in_tracker_list(starts_left, my_id, sm->name, sm->sym))
32 is_left = 1;
33 if (in_tracker_list(starts_right, my_id, sm->name, sm->sym))
34 is_right = 1;
35 if (is_left && is_right)
36 return &undefined;
37 if (is_left)
38 return &left;
39 if (is_right)
40 return &right;
41 return &undefined;
44 static struct smatch_state *unmatched_state(struct sm_state *sm)
46 return &start_state;
49 static void match_left(const char *fn, struct expression *expr, void *data)
51 struct sm_state *sm;
52 char *name = (char *)data;
54 if (__inline_fn)
55 return;
57 sm = get_sm_state(my_id, name, NULL);
58 if (!sm)
59 add_tracker(&starts_right, my_id, name, NULL);
60 if (sm && slist_has_state(sm->possible, &left))
61 sm_msg("warn: double '%s'", fn);
62 set_state(my_id, (char *)data, NULL, &left);
65 static void match_right(const char *fn, struct expression *expr, void *data)
67 struct sm_state *sm;
68 char *name = (char *)data;
70 if (__inline_fn)
71 return;
73 sm = get_sm_state(my_id, name, NULL);
74 if (!sm)
75 add_tracker(&starts_left, my_id, name, NULL);
76 if (sm && slist_has_state(sm->possible, &right))
77 sm_msg("warn: double '%s'", fn);
78 set_state(my_id, (char *)data, NULL, &right);
81 static void check_possible(struct sm_state *sm)
83 struct sm_state *tmp;
84 int is_left = 0;
85 int is_right = 0;
86 int undef = 0;
88 FOR_EACH_PTR(sm->possible, tmp) {
89 if (tmp->state == &left)
90 is_left = 1;
91 if (tmp->state == &right)
92 is_right = 1;
93 if (tmp->state == &start_state) {
94 struct smatch_state *s;
96 s = get_start_state(tmp);
97 if (s == &left)
98 is_left = 1;
99 else if (s == &right)
100 is_right = 1;
101 else
102 undef = 1;
104 if (tmp->state == &undefined)
105 undef = 1; // i don't think this is possible any more.
106 } END_FOR_EACH_PTR(tmp);
107 if ((is_left && is_right) || undef)
108 sm_msg("warn: returning with unbalanced %s", sm->name);
111 static void match_return(struct expression *expr)
113 struct state_list *slist;
114 struct sm_state *tmp;
116 if (__inline_fn)
117 return;
119 slist = get_all_states(my_id);
120 FOR_EACH_PTR(slist, tmp) {
121 if (tmp->state == &merged)
122 check_possible(tmp);
123 } END_FOR_EACH_PTR(tmp);
124 free_slist(&slist);
127 static void clear_lists(void)
129 free_trackers_and_list(&starts_left);
130 free_trackers_and_list(&starts_right);
133 static void match_func_end(struct symbol *sym)
135 if (__inline_fn)
136 return;
137 if (is_reachable())
138 match_return(NULL);
139 clear_lists();
142 static void get_left_funcs(const char *name, struct token **token)
144 const char *func;
146 while (token_type(*token) == TOKEN_IDENT) {
147 func = show_ident((*token)->ident);
148 add_function_hook(func, &match_left, (char *)name);
149 *token = (*token)->next;
151 if (token_type(*token) == TOKEN_SPECIAL)
152 *token = (*token)->next;
155 static void get_right_funcs(const char *name, struct token **token)
157 const char *func;
159 while (token_type(*token) == TOKEN_IDENT) {
160 func = show_ident((*token)->ident);
161 add_function_hook(func, &match_right, (char *)name);
162 *token = (*token)->next;
164 if (token_type(*token) == TOKEN_SPECIAL)
165 *token = (*token)->next;
168 static void register_funcs_from_file(void)
170 struct token *token;
171 char *name;
173 token = get_tokens_file("kernel.balanced_funcs");
174 if (!token)
175 return;
176 if (token_type(token) != TOKEN_STREAMBEGIN)
177 return;
178 token = token->next;
179 while (token_type(token) != TOKEN_STREAMEND) {
180 if (token_type(token) != TOKEN_IDENT)
181 return;
182 name = alloc_string(show_ident(token->ident));
183 token = token->next;
184 get_left_funcs(name, &token);
185 get_right_funcs(name, &token);
187 clear_token_alloc();
190 void check_balanced(int id)
192 my_id = id;
193 add_unmatched_state_hook(my_id, &unmatched_state);
194 add_hook(&match_return, RETURN_HOOK);
195 add_hook(&match_func_end, END_FUNC_HOOK);
196 register_funcs_from_file();