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 struct smatch_state
*alloc_my_state(struct expression
*expr
)
50 struct smatch_state
*state
;
53 state
= __alloc_smatch_state(0);
54 expr
= strip_expr(expr
);
55 name
= expr_to_str(expr
);
57 name
= alloc_string("");
58 state
->name
= alloc_sname(name
);
64 struct expression
*last_print_expr
;
65 static void print_missing_break(struct expression
*expr
)
69 if (get_switch_expr() == last_print_expr
)
71 last_print_expr
= get_switch_expr();
73 name
= expr_to_var(expr
);
74 sm_msg("warn: missing break? reassigning '%s'", name
);
78 static void match_assign(struct expression
*expr
)
80 struct expression
*left
;
84 if (!get_switch_expr())
86 left
= strip_expr(expr
->left
);
87 if (get_state_expr(my_id
, left
) == &no_break
)
88 print_missing_break(left
);
90 set_state_expr(my_id
, left
, alloc_my_state(get_switch_expr()));
94 static void match_symbol(struct expression
*expr
)
96 if (outside_of_function())
99 expr
= strip_expr(expr
);
100 if (expr
== skip_this
)
102 set_state_expr(my_id
, expr
, &used
);
105 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
111 struct smatch_state
*merge_hook(struct smatch_state
*s1
, struct smatch_state
*s2
)
113 struct expression
*switch_expr
;
115 if (s1
== &no_break
|| s2
== &no_break
)
119 switch_expr
= get_switch_expr();
120 if (s1
->data
== switch_expr
|| s2
->data
== switch_expr
)
125 static void match_stmt(struct statement
*stmt
)
127 if (stmt
->type
== STMT_CASE
)
133 void check_missing_break(int id
)
137 add_unmatched_state_hook(my_id
, &unmatched_state
);
138 add_merge_hook(my_id
, &merge_hook
);
140 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
141 add_hook(&match_symbol
, SYM_HOOK
);
142 add_hook(&match_stmt
, STMT_HOOK
);