2 * Copyright (C) 2014 Oracle.
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
22 static int print_unreached
= 1;
23 static struct string_list
*turn_off_names
;
24 static struct string_list
*ignore_names
;
26 static bool empty_statement(struct statement
*stmt
)
30 if (stmt
->type
== STMT_EXPRESSION
&& !stmt
->expression
)
35 static void print_unreached_initializers(struct symbol_list
*sym_list
)
39 FOR_EACH_PTR(sym_list
, sym
) {
40 if (sym
->initializer
&& !(sym
->ctype
.modifiers
& MOD_STATIC
))
41 sm_msg("info: '%s' is not actually initialized (unreached code).",
42 (sym
->ident
? sym
->ident
->name
: "this variable"));
43 } END_FOR_EACH_PTR(sym
);
46 static bool is_ignored_macro(struct statement
*stmt
)
51 name
= get_macro_name(stmt
->pos
);
55 if (strncmp(name
, "for_", 4) == 0)
58 FOR_EACH_PTR(ignore_names
, tmp
) {
59 if (strcmp(tmp
, name
) == 0)
61 } END_FOR_EACH_PTR(tmp
);
66 static bool prev_line_was_endif(struct statement
*stmt
)
69 struct position pos
= stmt
->pos
;
74 token
= pos_get_token(pos
);
75 if (token
&& token_type(token
) == TOKEN_IDENT
&&
76 strcmp(show_ident(token
->ident
), "endif") == 0)
80 token
= pos_get_token(pos
);
81 if (token
&& token_type(token
) == TOKEN_IDENT
&&
82 strcmp(show_ident(token
->ident
), "endif") == 0)
88 static bool we_jumped_into_the_middle_of_a_loop(struct statement
*stmt
)
90 struct statement
*prev
;
93 * Smatch doesn't handle loops correctly and this is a hack. What we
94 * do is that if the first unreachable statement is a loop and the
95 * previous statement was a goto then it's probably code like this:
102 * Every statement is reachable but only on the second iteration.
105 if (stmt
->type
!= STMT_ITERATOR
)
107 prev
= get_prev_statement();
108 if (prev
&& prev
->type
== STMT_GOTO
)
113 static bool prev_stmt_false_if(void)
115 struct statement
*prev
;
117 /* true if statements are handled in turn_off_unreachable() */
119 if (!__path_is_null())
122 prev
= get_prev_statement();
123 if (!prev
|| prev
->type
!= STMT_IF
)
126 if (known_condition_false(prev
->if_conditional
))
131 static void unreachable_stmt(struct statement
*stmt
)
137 if (!__path_is_null()) {
142 /* if we hit a label then assume there is a matching goto */
143 if (stmt
->type
== STMT_LABEL
)
145 if (prev_line_was_endif(stmt
))
147 if (we_jumped_into_the_middle_of_a_loop(stmt
))
149 if (prev_stmt_false_if())
152 if (!print_unreached
)
154 if (empty_statement(stmt
))
156 if (is_ignored_macro(stmt
))
159 switch (stmt
->type
) {
160 case STMT_COMPOUND
: /* after a switch before a case stmt */
164 case STMT_DECLARATION
: /* switch (x) { int a; case foo: ... */
165 print_unreached_initializers(stmt
->declaration
);
167 case STMT_RETURN
: /* gcc complains if you don't have a return statement */
168 if (is_last_stmt(stmt
))
172 /* people put extra breaks inside switch statements */
173 if (stmt
->goto_label
&& stmt
->goto_label
->type
== SYM_NODE
&&
174 strcmp(stmt
->goto_label
->ident
->name
, "break") == 0)
180 sm_warning("ignoring unreachable code.");
184 static bool is_turn_off(char *name
)
191 FOR_EACH_PTR(turn_off_names
, tmp
) {
192 if (strcmp(tmp
, name
) == 0)
194 } END_FOR_EACH_PTR(tmp
);
199 static char *get_function_name(struct statement
*stmt
)
201 struct expression
*expr
;
203 if (stmt
->type
!= STMT_EXPRESSION
)
205 expr
= stmt
->expression
;
206 if (!expr
|| expr
->type
!= EXPR_CALL
)
208 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol_name
)
210 return expr
->fn
->symbol_name
->name
;
213 static void turn_off_unreachable(struct statement
*stmt
)
217 name
= get_macro_name(stmt
->pos
);
218 if (is_turn_off(name
)) {
223 if (stmt
->type
== STMT_IF
&&
224 known_condition_true(stmt
->if_conditional
) && __path_is_null()) {
229 name
= get_function_name(stmt
);
230 if (is_turn_off(name
))
234 static void register_turn_off_macros(void)
240 if (option_project
== PROJ_NONE
)
241 strcpy(name
, "unreachable.turn_off");
243 snprintf(name
, 256, "%s.unreachable.turn_off", option_project_str
);
245 token
= get_tokens_file(name
);
248 if (token_type(token
) != TOKEN_STREAMBEGIN
)
251 while (token_type(token
) != TOKEN_STREAMEND
) {
252 if (token_type(token
) != TOKEN_IDENT
)
254 macro
= alloc_string(show_ident(token
->ident
));
255 add_ptr_list(&turn_off_names
, macro
);
261 static void register_ignored_macros(void)
267 if (option_project
== PROJ_NONE
)
268 strcpy(name
, "unreachable.ignore");
270 snprintf(name
, 256, "%s.unreachable.ignore", option_project_str
);
272 token
= get_tokens_file(name
);
275 if (token_type(token
) != TOKEN_STREAMBEGIN
)
278 while (token_type(token
) != TOKEN_STREAMEND
) {
279 if (token_type(token
) != TOKEN_IDENT
)
281 macro
= alloc_string(show_ident(token
->ident
));
282 add_ptr_list(&ignore_names
, macro
);
288 void check_unreachable(int id
)
292 register_turn_off_macros();
293 register_ignored_macros();
294 add_hook(&unreachable_stmt
, STMT_HOOK
);
295 add_hook(&turn_off_unreachable
, STMT_HOOK_AFTER
);