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 int empty_statement(struct statement
*stmt
)
30 if (stmt
->type
== STMT_EXPRESSION
&& !stmt
->expression
)
35 static int is_last_stmt(struct statement
*cur_stmt
)
37 struct symbol
*fn
= get_base_type(cur_func_sym
);
38 struct statement
*stmt
;
44 stmt
= fn
->inline_stmt
;
45 if (!stmt
|| stmt
->type
!= STMT_COMPOUND
)
47 stmt
= last_ptr_list((struct ptr_list
*)stmt
->stmts
);
53 static void print_unreached_initializers(struct symbol_list
*sym_list
)
57 FOR_EACH_PTR(sym_list
, sym
) {
59 sm_msg("info: '%s' is not actually initialized (unreached code).",
60 (sym
->ident
? sym
->ident
->name
: "this variable"));
61 } END_FOR_EACH_PTR(sym
);
64 static int is_ignored_macro(struct statement
*stmt
)
69 name
= get_macro_name(stmt
->pos
);
73 FOR_EACH_PTR(ignore_names
, tmp
) {
74 if (strcmp(tmp
, name
) == 0)
76 } END_FOR_EACH_PTR(tmp
);
81 static void unreachable_stmt(struct statement
*stmt
)
87 if (!__path_is_null()) {
95 case STMT_COMPOUND
: /* after a switch before a case stmt */
100 case STMT_DECLARATION
: /* switch (x) { int a; case foo: ... */
101 print_unreached_initializers(stmt
->declaration
);
103 case STMT_RETURN
: /* gcc complains if you don't have a return statement */
104 if (is_last_stmt(stmt
))
108 /* people put extra breaks inside switch statements */
109 if (stmt
->goto_label
&& stmt
->goto_label
->type
== SYM_NODE
&&
110 strcmp(stmt
->goto_label
->ident
->name
, "break") == 0)
116 if (empty_statement(stmt
))
118 if (is_ignored_macro(stmt
))
122 sm_msg("info: ignoring unreachable code.");
126 static int is_turn_off(char *name
)
133 FOR_EACH_PTR(turn_off_names
, tmp
) {
134 if (strcmp(tmp
, name
) == 0)
136 } END_FOR_EACH_PTR(tmp
);
141 static char *get_function_name(struct statement
*stmt
)
143 struct expression
*expr
;
145 if (stmt
->type
!= STMT_EXPRESSION
)
147 expr
= stmt
->expression
;
148 if (!expr
|| expr
->type
!= EXPR_CALL
)
150 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol_name
)
152 return expr
->fn
->symbol_name
->name
;
155 static void turn_off_unreachable(struct statement
*stmt
)
159 name
= get_macro_name(stmt
->pos
);
160 if (is_turn_off(name
)) {
165 if (stmt
->type
== STMT_IF
&&
166 known_condition_true(stmt
->if_conditional
) && __path_is_null()) {
171 name
= get_function_name(stmt
);
172 if (is_turn_off(name
))
176 static void register_turn_off_macros(void)
182 if (option_project
== PROJ_NONE
)
183 strcpy(name
, "unreachable.turn_off");
185 snprintf(name
, 256, "%s.unreachable.turn_off", option_project_str
);
187 token
= get_tokens_file(name
);
190 if (token_type(token
) != TOKEN_STREAMBEGIN
)
193 while (token_type(token
) != TOKEN_STREAMEND
) {
194 if (token_type(token
) != TOKEN_IDENT
)
196 macro
= alloc_string(show_ident(token
->ident
));
197 add_ptr_list(&turn_off_names
, macro
);
203 static void register_ignored_macros(void)
209 if (option_project
== PROJ_NONE
)
210 strcpy(name
, "unreachable.ignore");
212 snprintf(name
, 256, "%s.unreachable.ignore", option_project_str
);
214 token
= get_tokens_file(name
);
217 if (token_type(token
) != TOKEN_STREAMBEGIN
)
220 while (token_type(token
) != TOKEN_STREAMEND
) {
221 if (token_type(token
) != TOKEN_IDENT
)
223 macro
= alloc_string(show_ident(token
->ident
));
224 add_ptr_list(&ignore_names
, macro
);
230 void check_unreachable(int id
)
234 register_turn_off_macros();
235 register_ignored_macros();
236 add_hook(&unreachable_stmt
, STMT_HOOK
);
237 add_hook(&turn_off_unreachable
, STMT_HOOK_AFTER
);