sizeof: mv check_sizeof_pointer.c check_sizeof.c
[smatch.git] / check_missing_break.c
blob2a82ce486550feb97b95e71fe3e92923c3cf63f2
1 /*
2 * sparse/check_missing_break.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
11 * The way I'm detecting missing breaks is if there is an assignment inside a
12 * switch statement which is over written.
16 #include "smatch.h"
17 #include "smatch_slist.h"
19 static int my_id;
20 static struct expression *skip_this;
23 * It goes like 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
26 * it was assigned.
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
29 * to).
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.
37 STATE(used);
38 STATE(no_break);
40 static struct smatch_state *alloc_my_state(struct expression *expr)
42 struct smatch_state *state;
43 char *name;
45 state = __alloc_smatch_state(0);
46 expr = strip_expr(expr);
47 name = get_variable_from_expr_complex(expr, NULL);
48 state->name = alloc_sname(name);
49 free_string(name);
50 state->data = expr;
51 return state;
54 static void match_assign(struct expression *expr)
56 struct expression *left;
58 if (expr->op != '=')
59 return;
60 if (!get_switch_expr())
61 return;
62 left = strip_expr(expr->left);
63 if (get_state_expr(my_id, left) == &no_break) {
64 char *name;
66 name = get_variable_from_expr(left, NULL);
67 sm_msg("warn: missing break? reassigning '%s'", name);
68 free_string(name);
71 set_state_expr(my_id, left, alloc_my_state(get_switch_expr()));
72 skip_this = left;
75 static void match_symbol(struct expression *expr)
77 expr = strip_expr(expr);
78 if (expr == skip_this)
79 return;
80 set_state_expr(my_id, expr, &used);
83 static struct smatch_state *unmatched_state(struct sm_state *sm)
85 return &used;
88 static int in_case;
89 struct smatch_state *merge_hook(struct smatch_state *s1, struct smatch_state *s2)
91 struct expression *switch_expr;
93 if (s1 == &no_break || s2 == &no_break)
94 return &no_break;
95 if (!in_case)
96 return &used;
97 switch_expr = get_switch_expr();
98 if (s1->data == switch_expr || s2->data == switch_expr)
99 return &no_break;
100 return &used;
103 static void match_stmt(struct statement *stmt)
105 if (stmt->type == STMT_CASE)
106 in_case = 1;
107 else
108 in_case = 0;
111 void check_missing_break(int id)
113 my_id = id;
115 add_unmatched_state_hook(my_id, &unmatched_state);
116 add_merge_hook(my_id, &merge_hook);
118 add_hook(&match_assign, ASSIGNMENT_HOOK);
119 add_hook(&match_symbol, SYM_HOOK);
120 add_hook(&match_stmt, STMT_HOOK);