extra: don't save unneeded states
[smatch.git] / smatch_var_sym.c
blobff3459886c002c0daea227bb9ad1c8202a79d3c4
1 /*
2 * Copyright (C) 2013 Oracle.
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
18 #include "smatch.h"
20 ALLOCATOR(var_sym, "var_sym structs");
22 struct var_sym *alloc_var_sym(const char *var, struct symbol *sym)
24 struct var_sym *tmp;
26 tmp = __alloc_var_sym(0);
27 tmp->var = alloc_string(var);
28 tmp->sym = sym;
29 return tmp;
32 struct var_sym_list *expr_to_vsl(struct expression *expr)
34 struct var_sym_list *ret = NULL;
35 char *var;
36 struct symbol *sym;
38 expr = strip_expr(expr);
39 if (!expr)
40 return NULL;
42 if (expr->type == EXPR_PREOP && expr->op == '*')
43 return expr_to_vsl(expr->unop);
45 if (expr->type == EXPR_BINOP ||
46 expr->type == EXPR_LOGICAL ||
47 expr->type == EXPR_COMPARE) {
48 struct var_sym_list *left, *right;
50 left = expr_to_vsl(expr->left);
51 right = expr_to_vsl(expr->right);
52 ret = combine_var_sym_lists(left, right);
53 free_var_syms_and_list(&left);
54 free_var_syms_and_list(&right);
55 return ret;
57 var = expr_to_var_sym(expr, &sym);
58 if (!var || !sym) {
59 free_string(var);
60 return NULL;
62 add_var_sym(&ret, var, sym);
63 return ret;
66 int cmp_var_sym(const struct var_sym *a, const struct var_sym *b)
68 int ret;
70 if (a == b)
71 return 0;
72 if (!b)
73 return -1;
74 if (!a)
75 return 1;
77 ret = strcmp(a->var, b->var);
78 if (ret < 0)
79 return -1;
80 if (ret > 0)
81 return 1;
83 if (!b->sym && a->sym)
84 return -1;
85 if (!a->sym && b->sym)
86 return 1;
87 if (a->sym < b->sym)
88 return -1;
89 if (a->sym > b->sym)
90 return 1;
92 return 0;
95 void add_var_sym(struct var_sym_list **list, const char *var, struct symbol *sym)
97 struct var_sym *tmp, *new;
99 if (in_var_sym_list(*list, var, sym))
100 return;
101 new = alloc_var_sym(var, sym);
103 FOR_EACH_PTR(*list, tmp) {
104 if (cmp_var_sym(tmp, new) < 0)
105 continue;
106 else if (cmp_var_sym(tmp, new) == 0) {
107 return;
108 } else {
109 INSERT_CURRENT(new, tmp);
110 return;
112 } END_FOR_EACH_PTR(tmp);
113 add_ptr_list(list, new);
116 void add_var_sym_expr(struct var_sym_list **list, struct expression *expr)
118 char *var;
119 struct symbol *sym;
121 var = expr_to_var_sym(expr, &sym);
122 if (!var || !sym)
123 goto free;
124 add_var_sym(list, var, sym);
125 free:
126 free_string(var);
129 static void free_var_sym(struct var_sym *vs)
131 free_string(vs->var);
132 __free_var_sym(vs);
135 void del_var_sym(struct var_sym_list **list, const char *var, struct symbol *sym)
137 struct var_sym *tmp;
139 FOR_EACH_PTR(*list, tmp) {
140 if (tmp->sym == sym && strcmp(tmp->var, var) == 0) {
141 DELETE_CURRENT_PTR(tmp);
142 free_var_sym(tmp);
143 return;
145 } END_FOR_EACH_PTR(tmp);
148 int in_var_sym_list(struct var_sym_list *list, const char *var, struct symbol *sym)
150 struct var_sym *tmp;
152 FOR_EACH_PTR(list, tmp) {
153 if (tmp->sym == sym && strcmp(tmp->var, var) == 0)
154 return 1;
155 } END_FOR_EACH_PTR(tmp);
156 return 0;
159 struct var_sym_list *clone_var_sym_list(struct var_sym_list *from_vsl)
161 struct var_sym *tmp, *clone_vs;
162 struct var_sym_list *to_vsl = NULL;
164 FOR_EACH_PTR(from_vsl, tmp) {
165 clone_vs = alloc_var_sym(tmp->var, tmp->sym);
166 add_ptr_list(&to_vsl, clone_vs);
167 } END_FOR_EACH_PTR(tmp);
168 return to_vsl;
171 void merge_var_sym_list(struct var_sym_list **dest, struct var_sym_list *src)
173 struct var_sym *tmp;
175 FOR_EACH_PTR(src, tmp) {
176 add_var_sym(dest, tmp->var, tmp->sym);
177 } END_FOR_EACH_PTR(tmp);
180 struct var_sym_list *combine_var_sym_lists(struct var_sym_list *one, struct var_sym_list *two)
182 struct var_sym_list *to_vsl;
184 to_vsl = clone_var_sym_list(one);
185 merge_var_sym_list(&to_vsl, two);
186 return to_vsl;
189 int var_sym_lists_equiv(struct var_sym_list *one, struct var_sym_list *two)
191 struct var_sym *one_tmp, *two_tmp;
193 if (one == two)
194 return 1;
196 if (ptr_list_size((struct ptr_list *)one) != ptr_list_size((struct ptr_list *)two))
197 return 0;
199 PREPARE_PTR_LIST(one, one_tmp);
200 PREPARE_PTR_LIST(two, two_tmp);
201 for (;;) {
202 if (!one_tmp && !two_tmp)
203 return 1;
204 if (one_tmp->sym != two_tmp->sym)
205 return 0;
206 if (strcmp(one_tmp->var, two_tmp->var) != 0)
207 return 0;
208 NEXT_PTR_LIST(one_tmp);
209 NEXT_PTR_LIST(two_tmp);
211 FINISH_PTR_LIST(two_tmp);
212 FINISH_PTR_LIST(one_tmp);
214 return 1;
217 void free_var_sym_list(struct var_sym_list **list)
219 __free_ptr_list((struct ptr_list **)list);
222 void free_var_syms_and_list(struct var_sym_list **list)
224 struct var_sym *tmp;
226 FOR_EACH_PTR(*list, tmp) {
227 free_var_sym(tmp);
228 } END_FOR_EACH_PTR(tmp);
229 free_var_sym_list(list);