user_data: make a function static
[smatch.git] / check_missing_break.c
blob2c78112fa828fc3fbaccfe987bea161c7668c886
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 = expr_to_str(expr);
48 if (!name)
49 name = alloc_string("");
50 state->name = alloc_sname(name);
51 free_string(name);
52 state->data = expr;
53 return state;
56 struct expression *last_print_expr;
57 static void print_missing_break(struct expression *expr)
59 char *name;
61 if (get_switch_expr() == last_print_expr)
62 return;
63 last_print_expr = get_switch_expr();
65 name = expr_to_var(expr);
66 sm_msg("warn: missing break? reassigning '%s'", name);
67 free_string(name);
70 static void match_assign(struct expression *expr)
72 struct expression *left;
74 if (expr->op != '=')
75 return;
76 if (!get_switch_expr())
77 return;
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()));
83 skip_this = left;
86 static void match_symbol(struct expression *expr)
88 expr = strip_expr(expr);
89 if (expr == skip_this)
90 return;
91 set_state_expr(my_id, expr, &used);
94 static struct smatch_state *unmatched_state(struct sm_state *sm)
96 return &used;
99 static int in_case;
100 struct smatch_state *merge_hook(struct smatch_state *s1, struct smatch_state *s2)
102 struct expression *switch_expr;
104 if (s1 == &no_break || s2 == &no_break)
105 return &no_break;
106 if (!in_case)
107 return &used;
108 switch_expr = get_switch_expr();
109 if (s1->data == switch_expr || s2->data == switch_expr)
110 return &no_break;
111 return &used;
114 static void match_stmt(struct statement *stmt)
116 if (stmt->type == STMT_CASE)
117 in_case = 1;
118 else
119 in_case = 0;
122 void check_missing_break(int id)
124 my_id = id;
126 add_unmatched_state_hook(my_id, &unmatched_state);
127 add_merge_hook(my_id, &merge_hook);
129 add_hook(&match_assign, ASSIGNMENT_HOOK);
130 add_hook(&match_symbol, SYM_HOOK);
131 add_hook(&match_stmt, STMT_HOOK);