db/fixup_kernel.sh: fix clear_user() handling
[smatch.git] / check_continue_vs_break.c
blob6c991630d3d9a6ee9f23a9f8a27b561fe198a2cc
1 /*
2 * Copyright (C) 2015 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
19 * If you have code like:
20 * do {
21 * if (xxx)
22 * continue;
23 * }
24 * while (0);
26 * Then the continue is equivalent of a break. So what was really intended?
29 #include "smatch.h"
30 #include "smatch_slist.h"
32 static int my_id;
34 static struct statement_list *iterator_stack;
36 static int is_do_while_zero(struct statement *stmt)
38 if (!stmt->iterator_post_condition)
39 return 0;
40 if (!expr_is_zero(stmt->iterator_post_condition))
41 return 0;
42 return 1;
45 static void push_statement(struct statement_list **stack, struct statement *stmt)
47 add_ptr_list(stack, stmt);
50 static void pop_statement(struct statement_list **stack)
52 delete_ptr_list_last((struct ptr_list **)stack);
55 static int inside_do_while_zero(void)
57 struct statement *stmt;
59 stmt = last_ptr_list((struct ptr_list *)iterator_stack);
60 return !!stmt;
63 static int loop_is_macro(void)
65 struct statement *stmt;
67 stmt = last_ptr_list((struct ptr_list *)iterator_stack);
68 if (!stmt)
69 return 0;
70 if (get_macro_name(stmt->iterator_post_condition->pos))
71 return 1;
72 return 0;
75 static void match_stmt(struct statement *stmt)
77 if (stmt->type != STMT_ITERATOR)
78 return;
80 if (is_do_while_zero(stmt))
81 push_statement(&iterator_stack, stmt);
82 else
83 push_statement(&iterator_stack, NULL);
86 static void match_stmt_after(struct statement *stmt)
88 if (stmt->type != STMT_ITERATOR)
89 return;
91 pop_statement(&iterator_stack);
94 static void match_inline_start(struct expression *expr)
96 push_statement(&iterator_stack, NULL);
99 static void match_inline_end(struct expression *expr)
101 pop_statement(&iterator_stack);
104 static void match_continue(struct statement *stmt)
106 if (stmt->type != STMT_GOTO)
107 return;
109 if (!stmt->goto_label || stmt->goto_label->type != SYM_NODE)
110 return;
111 if (strcmp(stmt->goto_label->ident->name, "continue") != 0)
112 return;
113 if (!inside_do_while_zero())
114 return;
115 if (loop_is_macro())
116 return;
117 sm_warning("continue to end of do { ... } while(0); loop");
120 void check_continue_vs_break(int id)
122 my_id = id;
123 add_hook(&match_stmt, STMT_HOOK);
124 add_hook(&match_stmt_after, STMT_HOOK_AFTER);
125 add_hook(&match_inline_start, INLINE_FN_START);
126 add_hook(&match_inline_end, INLINE_FN_END);
128 add_hook(&match_continue, STMT_HOOK);