smatch: add a --succeed option
[smatch.git] / smatch_equiv.c
blobe00b6f2a6aeea3d69bde640a64c99305a017d25f
1 /*
2 * Copyright (C) 2010 Dan Carpenter.
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 * smatch_equiv.c is for tracking how variables are the same
21 * if (a == b) {
22 * Or
23 * x = y;
25 * When a variable gets modified all the old relationships are
26 * deleted. remove_equiv(expr);
30 #include "smatch.h"
31 #include "smatch_slist.h"
32 #include "smatch_extra.h"
34 ALLOCATOR(relation, "related variables");
36 static struct relation *alloc_relation(const char *name, struct symbol *sym)
38 struct relation *tmp;
40 tmp = __alloc_relation(0);
41 tmp->name = alloc_string(name);
42 tmp->sym = sym;
43 return tmp;
46 struct related_list *clone_related_list(struct related_list *related)
48 struct relation *rel;
49 struct related_list *to_list = NULL;
51 FOR_EACH_PTR(related, rel) {
52 add_ptr_list(&to_list, rel);
53 } END_FOR_EACH_PTR(rel);
55 return to_list;
58 static int cmp_relation(struct relation *a, struct relation *b)
60 int ret;
62 if (a == b)
63 return 0;
65 if (a->sym > b->sym)
66 return -1;
67 if (a->sym < b->sym)
68 return 1;
70 ret = strcmp(a->name, b->name);
71 if (ret)
72 return ret;
74 return 0;
77 struct related_list *get_shared_relations(struct related_list *one,
78 struct related_list *two)
80 struct related_list *ret = NULL;
81 struct relation *one_rel;
82 struct relation *two_rel;
84 PREPARE_PTR_LIST(one, one_rel);
85 PREPARE_PTR_LIST(two, two_rel);
86 for (;;) {
87 if (!one_rel || !two_rel)
88 break;
89 if (cmp_relation(one_rel, two_rel) < 0) {
90 NEXT_PTR_LIST(one_rel);
91 } else if (cmp_relation(one_rel, two_rel) == 0) {
92 add_ptr_list(&ret, one_rel);
93 NEXT_PTR_LIST(one_rel);
94 NEXT_PTR_LIST(two_rel);
95 } else {
96 NEXT_PTR_LIST(two_rel);
99 FINISH_PTR_LIST(two_rel);
100 FINISH_PTR_LIST(one_rel);
102 return ret;
105 static void debug_addition(struct related_list *rlist, const char *name)
107 struct relation *tmp;
109 if (!option_debug_related)
110 return;
112 sm_prefix();
113 sm_printf("(");
114 FOR_EACH_PTR(rlist, tmp) {
115 sm_printf("%s ", tmp->name);
116 } END_FOR_EACH_PTR(tmp);
117 sm_printf(") <-- %s\n", name);
120 static void add_related(struct related_list **rlist, const char *name, struct symbol *sym)
122 struct relation *rel;
123 struct relation *new;
124 struct relation tmp = {
125 .name = (char *)name,
126 .sym = sym
129 debug_addition(*rlist, name);
131 FOR_EACH_PTR(*rlist, rel) {
132 if (cmp_relation(rel, &tmp) < 0)
133 continue;
134 if (cmp_relation(rel, &tmp) == 0)
135 return;
136 new = alloc_relation(name, sym);
137 INSERT_CURRENT(new, rel);
138 return;
139 } END_FOR_EACH_PTR(rel);
140 new = alloc_relation(name, sym);
141 add_ptr_list(rlist, new);
144 static struct related_list *del_related(struct smatch_state *state, const char *name, struct symbol *sym)
146 struct relation *tmp;
147 struct relation remove = {
148 .name = (char *)name,
149 .sym = sym,
151 struct related_list *ret = NULL;
153 FOR_EACH_PTR(estate_related(state), tmp) {
154 if (cmp_relation(tmp, &remove) != 0)
155 add_ptr_list(&ret, tmp);
156 } END_FOR_EACH_PTR(tmp);
158 return ret;
161 void remove_from_equiv(const char *name, struct symbol *sym)
163 struct sm_state *orig_sm;
164 struct relation *rel;
165 struct smatch_state *state;
166 struct related_list *to_update;
168 orig_sm = get_sm_state(SMATCH_EXTRA, name, sym);
169 if (!orig_sm || !get_dinfo(orig_sm->state)->related)
170 return;
172 state = clone_estate(orig_sm->state);
173 to_update = del_related(state, name, sym);
175 FOR_EACH_PTR(to_update, rel) {
176 struct sm_state *old_sm, *new_sm;
178 old_sm = get_sm_state(SMATCH_EXTRA, rel->name, rel->sym);
179 if (!old_sm)
180 continue;
182 new_sm = clone_sm(old_sm);
183 get_dinfo(new_sm->state)->related = to_update;
184 __set_sm(new_sm);
185 } END_FOR_EACH_PTR(rel);
188 void remove_from_equiv_expr(struct expression *expr)
190 char *name;
191 struct symbol *sym;
193 name = expr_to_var_sym(expr, &sym);
194 if (!name || !sym)
195 goto free;
196 remove_from_equiv(name, sym);
197 free:
198 free_string(name);
201 void set_related(struct smatch_state *estate, struct related_list *rlist)
203 if (!estate_related(estate) && !rlist)
204 return;
205 get_dinfo(estate)->related = rlist;
209 * set_equiv() is only used for assignments where we set one variable
210 * equal to the other. a = b;. It's not used for if conditions where
211 * a == b.
213 void set_equiv(struct expression *left, struct expression *right)
215 struct sm_state *right_sm, *left_sm;
216 struct relation *rel;
217 char *left_name;
218 struct symbol *left_sym;
219 struct related_list *rlist;
221 left_name = expr_to_var_sym(left, &left_sym);
222 if (!left_name || !left_sym)
223 goto free;
225 right_sm = get_sm_state_expr(SMATCH_EXTRA, right);
226 if (!right_sm)
227 right_sm = set_state_expr(SMATCH_EXTRA, right, alloc_estate_whole(get_type(right)));
228 if (!right_sm)
229 goto free;
231 /* This block is because we want to preserve the implications. */
232 left_sm = clone_sm(right_sm);
233 left_sm->name = alloc_string(left_name);
234 left_sm->sym = left_sym;
235 left_sm->state = clone_estate_cast(get_type(left), right_sm->state);
236 set_extra_mod_helper(left_name, left_sym, left, left_sm->state);
237 __set_sm(left_sm);
239 rlist = clone_related_list(estate_related(right_sm->state));
240 add_related(&rlist, right_sm->name, right_sm->sym);
241 add_related(&rlist, left_name, left_sym);
243 FOR_EACH_PTR(rlist, rel) {
244 struct sm_state *old_sm, *new_sm;
246 old_sm = get_sm_state(SMATCH_EXTRA, rel->name, rel->sym);
247 if (!old_sm) /* shouldn't happen */
248 continue;
249 new_sm = clone_sm(old_sm);
250 new_sm->state = clone_estate(old_sm->state);
251 get_dinfo(new_sm->state)->related = rlist;
252 __set_sm(new_sm);
253 } END_FOR_EACH_PTR(rel);
254 free:
255 free_string(left_name);
258 void set_equiv_state_expr(int id, struct expression *expr, struct smatch_state *state)
260 struct relation *rel;
261 struct smatch_state *estate;
263 estate = get_state_expr(SMATCH_EXTRA, expr);
265 if (!estate)
266 return;
268 FOR_EACH_PTR(get_dinfo(estate)->related, rel) {
269 set_state(id, rel->name, rel->sym, state);
270 } END_FOR_EACH_PTR(rel);