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
25 * When a variable gets modified all the old relationships are
26 * deleted. remove_equiv(expr);
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
)
40 tmp
= __alloc_relation(0);
41 tmp
->name
= alloc_string(name
);
46 struct related_list
*clone_related_list(struct related_list
*related
)
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
);
58 static int cmp_relation(struct relation
*a
, struct relation
*b
)
70 ret
= strcmp(a
->name
, b
->name
);
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
);
87 if (!one_rel
|| !two_rel
)
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
);
96 NEXT_PTR_LIST(two_rel
);
99 FINISH_PTR_LIST(two_rel
);
100 FINISH_PTR_LIST(one_rel
);
105 static void add_related(struct related_list
**rlist
, const char *name
, struct symbol
*sym
)
107 struct relation
*rel
;
108 struct relation
*new;
109 struct relation tmp
= {
110 .name
= (char *)name
,
114 FOR_EACH_PTR(*rlist
, rel
) {
115 if (cmp_relation(rel
, &tmp
) < 0)
117 if (cmp_relation(rel
, &tmp
) == 0)
119 new = alloc_relation(name
, sym
);
120 INSERT_CURRENT(new, rel
);
122 } END_FOR_EACH_PTR(rel
);
123 new = alloc_relation(name
, sym
);
124 add_ptr_list(rlist
, new);
127 static struct related_list
*del_related(struct smatch_state
*state
, const char *name
, struct symbol
*sym
)
129 struct relation
*tmp
;
130 struct relation remove
= {
131 .name
= (char *)name
,
134 struct related_list
*ret
= NULL
;
136 FOR_EACH_PTR(estate_related(state
), tmp
) {
137 if (cmp_relation(tmp
, &remove
) != 0)
138 add_ptr_list(&ret
, tmp
);
139 } END_FOR_EACH_PTR(tmp
);
144 void remove_from_equiv(const char *name
, struct symbol
*sym
)
146 struct sm_state
*orig_sm
;
147 struct relation
*rel
;
148 struct smatch_state
*state
;
149 struct related_list
*to_update
;
151 orig_sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
152 if (!orig_sm
|| !get_dinfo(orig_sm
->state
)->related
)
155 state
= clone_estate(orig_sm
->state
);
156 to_update
= del_related(state
, name
, sym
);
158 FOR_EACH_PTR(to_update
, rel
) {
159 struct sm_state
*old_sm
, *new_sm
;
161 old_sm
= get_sm_state(SMATCH_EXTRA
, rel
->name
, rel
->sym
);
165 new_sm
= clone_sm(old_sm
);
166 get_dinfo(new_sm
->state
)->related
= to_update
;
168 } END_FOR_EACH_PTR(rel
);
171 void remove_from_equiv_expr(struct expression
*expr
)
176 name
= expr_to_var_sym(expr
, &sym
);
179 remove_from_equiv(name
, sym
);
184 void set_related(struct smatch_state
*estate
, struct related_list
*rlist
)
186 if (!estate_related(estate
) && !rlist
)
188 get_dinfo(estate
)->related
= rlist
;
192 * set_equiv() is only used for assignments where we set one variable
193 * equal to the other. a = b;. It's not used for if conditions where
196 void set_equiv(struct expression
*left
, struct expression
*right
)
198 struct sm_state
*right_sm
, *left_sm
, *other_sm
;
199 struct relation
*rel
;
201 struct symbol
*left_sym
;
202 struct related_list
*rlist
;
204 struct symbol
*other_sym
;
206 left_name
= expr_to_var_sym(left
, &left_sym
);
207 if (!left_name
|| !left_sym
)
210 other_name
= get_other_name_sym(left_name
, left_sym
, &other_sym
);
212 right_sm
= get_sm_state_expr(SMATCH_EXTRA
, right
);
214 struct range_list
*rl
;
216 if (!get_implied_rl(right
, &rl
))
217 rl
= alloc_whole_rl(get_type(right
));
218 right_sm
= set_state_expr(SMATCH_EXTRA
, right
, alloc_estate_rl(rl
));
223 /* This block is because we want to preserve the implications. */
224 left_sm
= clone_sm(right_sm
);
225 left_sm
->name
= alloc_string(left_name
);
226 left_sm
->sym
= left_sym
;
227 left_sm
->state
= clone_estate_cast(get_type(left
), right_sm
->state
);
228 /* FIXME: The expression we're passing is wrong */
229 set_extra_mod_helper(left_name
, left_sym
, left
, left_sm
->state
);
232 if (other_name
&& other_sym
) {
233 other_sm
= clone_sm(right_sm
);
234 other_sm
->name
= alloc_string(other_name
);
235 other_sm
->sym
= other_sym
;
236 other_sm
->state
= clone_estate_cast(get_type(left
), left_sm
->state
);
237 set_extra_mod_helper(other_name
, other_sym
, NULL
, other_sm
->state
);
241 rlist
= clone_related_list(estate_related(right_sm
->state
));
242 add_related(&rlist
, right_sm
->name
, right_sm
->sym
);
243 add_related(&rlist
, left_name
, left_sym
);
244 if (other_name
&& other_sym
)
245 add_related(&rlist
, other_name
, other_sym
);
247 FOR_EACH_PTR(rlist
, rel
) {
248 struct sm_state
*old_sm
, *new_sm
;
250 old_sm
= get_sm_state(SMATCH_EXTRA
, rel
->name
, rel
->sym
);
251 if (!old_sm
) /* shouldn't happen */
253 new_sm
= clone_sm(old_sm
);
254 new_sm
->state
= clone_estate(old_sm
->state
);
255 get_dinfo(new_sm
->state
)->related
= rlist
;
257 } END_FOR_EACH_PTR(rel
);
259 free_string(left_name
);
262 void set_equiv_state_expr(int id
, struct expression
*expr
, struct smatch_state
*state
)
264 struct relation
*rel
;
265 struct smatch_state
*estate
;
267 estate
= get_state_expr(SMATCH_EXTRA
, expr
);
272 FOR_EACH_PTR(get_dinfo(estate
)->related
, rel
) {
273 set_state(id
, rel
->name
, rel
->sym
, state
);
274 } END_FOR_EACH_PTR(rel
);