2 * Copyright (C) 2013 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 * The way I'm detecting missing breaks is if there is an assignment inside a
20 * switch statement which is over written.
25 #include "smatch_slist.h"
28 static struct expression
*skip_this
;
32 * - Allocate a state which stores the switch expression. I wanted to
33 * just have a state &assigned but we need to know the switch statement where
35 * - If it gets used then we change it to &used.
36 * - For unmatched states we use &used (because of cleanness, not because we need
38 * - If we merge inside a case statement and one of the states is &assigned (or
39 * if it is &nobreak) then &nobreak is used.
41 * We print an error when we assign something to a &no_break symbol.
48 static int in_switch_stmt
;
50 static struct smatch_state
*alloc_my_state(struct expression
*expr
)
52 struct smatch_state
*state
;
55 state
= __alloc_smatch_state(0);
56 expr
= strip_expr(expr
);
57 name
= expr_to_str(expr
);
59 name
= alloc_string("");
60 state
->name
= alloc_sname(name
);
66 struct expression
*last_print_expr
;
67 static void print_missing_break(struct expression
*expr
)
71 if (get_switch_expr() == last_print_expr
)
73 last_print_expr
= get_switch_expr();
75 name
= expr_to_var(expr
);
76 sm_msg("warn: missing break? reassigning '%s'", name
);
80 static void match_assign(struct expression
*expr
)
82 struct expression
*left
;
86 if (!get_switch_expr())
88 left
= strip_expr(expr
->left
);
89 if (get_state_expr(my_id
, left
) == &no_break
)
90 print_missing_break(left
);
92 set_state_expr(my_id
, left
, alloc_my_state(get_switch_expr()));
96 static void match_symbol(struct expression
*expr
)
98 if (outside_of_function())
100 if (!get_switch_expr())
103 expr
= strip_expr(expr
);
104 if (expr
== skip_this
)
106 set_state_expr(my_id
, expr
, &used
);
109 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
115 static struct smatch_state
*merge_hook(struct smatch_state
*s1
, struct smatch_state
*s2
)
117 struct expression
*switch_expr
;
119 if (s1
== &no_break
|| s2
== &no_break
)
123 switch_expr
= get_switch_expr();
124 if (s1
->data
== switch_expr
|| s2
->data
== switch_expr
)
129 static void match_stmt(struct statement
*stmt
)
131 if (stmt
->type
== STMT_CASE
)
137 static void match_switch(struct statement
*stmt
)
139 if (stmt
->type
!= STMT_SWITCH
)
145 static void delete_my_states(int owner
)
147 struct state_list
*slist
= NULL
;
150 FOR_EACH_MY_SM(owner
, __get_cur_stree(), sm
) {
151 add_ptr_list(&slist
, sm
);
152 } END_FOR_EACH_SM(sm
);
154 FOR_EACH_PTR(slist
, sm
) {
155 delete_state(sm
->owner
, sm
->name
, sm
->sym
);
156 } END_FOR_EACH_PTR(sm
);
161 static void match_switch_end(struct statement
*stmt
)
164 if (stmt
->type
!= STMT_SWITCH
)
170 delete_my_states(my_id
);
173 void check_missing_break(int id
)
177 add_unmatched_state_hook(my_id
, &unmatched_state
);
178 add_merge_hook(my_id
, &merge_hook
);
180 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
181 add_hook(&match_symbol
, SYM_HOOK
);
182 add_hook(&match_stmt
, STMT_HOOK
);
183 add_hook(&match_switch
, STMT_HOOK
);
184 add_hook(&match_switch_end
, STMT_HOOK_AFTER
);