11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2015 Oracle.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon /*
191f5207b7SJohn Levon  * If you have code like:
201f5207b7SJohn Levon  * do {
211f5207b7SJohn Levon  *    if (xxx)
221f5207b7SJohn Levon  *        continue;
231f5207b7SJohn Levon  * while (0);
241f5207b7SJohn Levon  *
251f5207b7SJohn Levon  * Then the continue is equivalent of a break.  So what was really intended?
261f5207b7SJohn Levon  */
271f5207b7SJohn Levon 
281f5207b7SJohn Levon #include "smatch.h"
291f5207b7SJohn Levon #include "smatch_slist.h"
301f5207b7SJohn Levon 
311f5207b7SJohn Levon static int my_id;
321f5207b7SJohn Levon 
331f5207b7SJohn Levon static struct statement_list *iterator_stack;
341f5207b7SJohn Levon 
is_do_while_zero(struct statement * stmt)351f5207b7SJohn Levon static int is_do_while_zero(struct statement *stmt)
361f5207b7SJohn Levon {
371f5207b7SJohn Levon 	if (!stmt->iterator_post_condition)
381f5207b7SJohn Levon 		return 0;
39*c85f09ccSJohn Levon 	if (!expr_is_zero(stmt->iterator_post_condition))
401f5207b7SJohn Levon 		return 0;
411f5207b7SJohn Levon 	return 1;
421f5207b7SJohn Levon }
431f5207b7SJohn Levon 
push_statement(struct statement_list ** stack,struct statement * stmt)441f5207b7SJohn Levon static void push_statement(struct statement_list **stack, struct statement *stmt)
451f5207b7SJohn Levon {
461f5207b7SJohn Levon 	add_ptr_list(stack, stmt);
471f5207b7SJohn Levon }
481f5207b7SJohn Levon 
pop_statement(struct statement_list ** stack)491f5207b7SJohn Levon static void pop_statement(struct statement_list **stack)
501f5207b7SJohn Levon {
511f5207b7SJohn Levon 	delete_ptr_list_last((struct ptr_list **)stack);
521f5207b7SJohn Levon }
531f5207b7SJohn Levon 
inside_do_while_zero(void)541f5207b7SJohn Levon static int inside_do_while_zero(void)
551f5207b7SJohn Levon {
561f5207b7SJohn Levon 	struct statement *stmt;
571f5207b7SJohn Levon 
581f5207b7SJohn Levon 	stmt = last_ptr_list((struct ptr_list *)iterator_stack);
591f5207b7SJohn Levon 	return !!stmt;
601f5207b7SJohn Levon }
611f5207b7SJohn Levon 
loop_is_macro(void)621f5207b7SJohn Levon static int loop_is_macro(void)
631f5207b7SJohn Levon {
641f5207b7SJohn Levon 	struct statement *stmt;
651f5207b7SJohn Levon 
661f5207b7SJohn Levon 	stmt = last_ptr_list((struct ptr_list *)iterator_stack);
671f5207b7SJohn Levon 	if (!stmt)
681f5207b7SJohn Levon 		return 0;
691f5207b7SJohn Levon 	if (get_macro_name(stmt->iterator_post_condition->pos))
701f5207b7SJohn Levon 		return 1;
711f5207b7SJohn Levon 	return 0;
721f5207b7SJohn Levon }
731f5207b7SJohn Levon 
match_stmt(struct statement * stmt)741f5207b7SJohn Levon static void match_stmt(struct statement *stmt)
751f5207b7SJohn Levon {
761f5207b7SJohn Levon 	if (stmt->type != STMT_ITERATOR)
771f5207b7SJohn Levon 		return;
781f5207b7SJohn Levon 
791f5207b7SJohn Levon 	if (is_do_while_zero(stmt)) {
801f5207b7SJohn Levon 		push_statement(&iterator_stack, stmt);
811f5207b7SJohn Levon 	} else
821f5207b7SJohn Levon 		push_statement(&iterator_stack, NULL);
831f5207b7SJohn Levon }
841f5207b7SJohn Levon 
match_stmt_after(struct statement * stmt)851f5207b7SJohn Levon static void match_stmt_after(struct statement *stmt)
861f5207b7SJohn Levon {
871f5207b7SJohn Levon 	if (stmt->type != STMT_ITERATOR)
881f5207b7SJohn Levon 		return;
891f5207b7SJohn Levon 
901f5207b7SJohn Levon 	pop_statement(&iterator_stack);
911f5207b7SJohn Levon }
921f5207b7SJohn Levon 
match_inline_start(struct expression * expr)931f5207b7SJohn Levon static void match_inline_start(struct expression *expr)
941f5207b7SJohn Levon {
951f5207b7SJohn Levon 	push_statement(&iterator_stack, NULL);
961f5207b7SJohn Levon }
971f5207b7SJohn Levon 
match_inline_end(struct expression * expr)981f5207b7SJohn Levon static void match_inline_end(struct expression *expr)
991f5207b7SJohn Levon {
1001f5207b7SJohn Levon 	pop_statement(&iterator_stack);
1011f5207b7SJohn Levon }
1021f5207b7SJohn Levon 
match_continue(struct statement * stmt)1031f5207b7SJohn Levon static void match_continue(struct statement *stmt)
1041f5207b7SJohn Levon {
1051f5207b7SJohn Levon 	if (stmt->type != STMT_GOTO)
1061f5207b7SJohn Levon 		return;
1071f5207b7SJohn Levon 
1081f5207b7SJohn Levon 	if (!stmt->goto_label || stmt->goto_label->type != SYM_NODE)
1091f5207b7SJohn Levon 		return;
1101f5207b7SJohn Levon 	if (strcmp(stmt->goto_label->ident->name, "continue") != 0)
1111f5207b7SJohn Levon 		return;
1121f5207b7SJohn Levon 	if (!inside_do_while_zero())
1131f5207b7SJohn Levon 		return;
1141f5207b7SJohn Levon 	if (loop_is_macro())
1151f5207b7SJohn Levon 		return;
1161f5207b7SJohn Levon 	sm_warning("continue to end of do { ... } while(0); loop");
1171f5207b7SJohn Levon }
1181f5207b7SJohn Levon 
check_continue_vs_break(int id)1191f5207b7SJohn Levon void check_continue_vs_break(int id)
1201f5207b7SJohn Levon {
1211f5207b7SJohn Levon 	my_id = id;
1221f5207b7SJohn Levon 	add_hook(&match_stmt, STMT_HOOK);
1231f5207b7SJohn Levon 	add_hook(&match_stmt_after, STMT_HOOK_AFTER);
1241f5207b7SJohn Levon 	add_hook(&match_inline_start, INLINE_FN_START);
1251f5207b7SJohn Levon 	add_hook(&match_inline_end, INLINE_FN_END);
1261f5207b7SJohn Levon 
1271f5207b7SJohn Levon 	add_hook(&match_continue, STMT_HOOK);
1281f5207b7SJohn Levon }
129