2 * sparse/check_missing_break.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
11 * The way I'm detecting missing breaks is if there is an assignment inside a
12 * switch statement which is over written.
17 #include "smatch_slist.h"
20 static struct expression
*skip_this
;
24 * - Allocate a state which stores the switch expression. I wanted to
25 * just have a state &assigned but we need to know the switch statement where
27 * - If it gets used then we change it to &used.
28 * - For unmatched states we use &used (because of cleanness, not because we need
30 * - If we merge inside a case statement and one of the states is &assigned (or
31 * if it is &nobreak) then &nobreak is used.
33 * We print an error when we assign something to a &no_break symbol.
40 static struct smatch_state
*alloc_my_state(struct expression
*expr
)
42 struct smatch_state
*state
;
45 state
= __alloc_smatch_state(0);
46 expr
= strip_expr(expr
);
47 name
= expr_to_str(expr
);
49 name
= alloc_string("");
50 state
->name
= alloc_sname(name
);
56 struct expression
*last_print_expr
;
57 static void print_missing_break(struct expression
*expr
)
61 if (get_switch_expr() == last_print_expr
)
63 last_print_expr
= get_switch_expr();
65 name
= expr_to_var(expr
);
66 sm_msg("warn: missing break? reassigning '%s'", name
);
70 static void match_assign(struct expression
*expr
)
72 struct expression
*left
;
76 if (!get_switch_expr())
78 left
= strip_expr(expr
->left
);
79 if (get_state_expr(my_id
, left
) == &no_break
)
80 print_missing_break(left
);
82 set_state_expr(my_id
, left
, alloc_my_state(get_switch_expr()));
86 static void match_symbol(struct expression
*expr
)
88 if (outside_of_function())
91 expr
= strip_expr(expr
);
92 if (expr
== skip_this
)
94 set_state_expr(my_id
, expr
, &used
);
97 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
103 struct smatch_state
*merge_hook(struct smatch_state
*s1
, struct smatch_state
*s2
)
105 struct expression
*switch_expr
;
107 if (s1
== &no_break
|| s2
== &no_break
)
111 switch_expr
= get_switch_expr();
112 if (s1
->data
== switch_expr
|| s2
->data
== switch_expr
)
117 static void match_stmt(struct statement
*stmt
)
119 if (stmt
->type
== STMT_CASE
)
125 void check_missing_break(int id
)
129 add_unmatched_state_hook(my_id
, &unmatched_state
);
130 add_merge_hook(my_id
, &merge_hook
);
132 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
133 add_hook(&match_symbol
, SYM_HOOK
);
134 add_hook(&match_stmt
, STMT_HOOK
);