1 /*
2 * Copyright (C) 2013 Oracle.
3 *
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.
8 *
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.
13 *
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
16 */
17
18 #include "smatch.h"
19
20 #define RECURSE_LIMIT 10
21
recurse(struct expression * expr,int (func)(struct expression * expr,void * p),void * param,int nr)22 static int recurse(struct expression *expr,
23 int (func)(struct expression *expr, void *p),
24 void *param, int nr)
25 {
26 int ret;
27
28 if (!expr)
29 return 0;
30
31 ret = func(expr, param);
32 if (ret)
33 return ret;
34
35 if (nr > RECURSE_LIMIT)
36 return -1;
37 nr++;
38
39 switch (expr->type) {
40 case EXPR_PREOP:
41 ret = recurse(expr->unop, func, param, nr);
42 break;
43 case EXPR_POSTOP:
44 ret = recurse(expr->unop, func, param, nr);
45 break;
46 case EXPR_STATEMENT:
47 return -1;
48 break;
49 case EXPR_LOGICAL:
50 case EXPR_COMPARE:
51 case EXPR_BINOP:
52 case EXPR_COMMA:
53 ret = recurse(expr->left, func, param, nr);
54 if (ret)
55 return ret;
56 ret = recurse(expr->right, func, param, nr);
57 break;
58 case EXPR_ASSIGNMENT:
59 ret = recurse(expr->right, func, param, nr);
60 if (ret)
61 return ret;
62 ret = recurse(expr->left, func, param, nr);
63 break;
64 case EXPR_DEREF:
65 ret = recurse(expr->deref, func, param, nr);
66 break;
67 case EXPR_SLICE:
68 ret = recurse(expr->base, func, param, nr);
69 break;
70 case EXPR_CAST:
71 case EXPR_FORCE_CAST:
72 ret = recurse(expr->cast_expression, func, param, nr);
73 break;
74 case EXPR_SIZEOF:
75 case EXPR_OFFSETOF:
76 case EXPR_ALIGNOF:
77 break;
78 case EXPR_CONDITIONAL:
79 case EXPR_SELECT:
80 ret = recurse(expr->conditional, func, param, nr);
81 if (ret)
82 return ret;
83 ret = recurse(expr->cond_true, func, param, nr);
84 if (ret)
85 return ret;
86 ret = recurse(expr->cond_false, func, param, nr);
87 break;
88 case EXPR_CALL:
89 return -1;
90 break;
91 case EXPR_INITIALIZER:
92 return -1;
93 break;
94 case EXPR_IDENTIFIER:
95 ret = recurse(expr->ident_expression, func, param, nr);
96 break;
97 case EXPR_INDEX:
98 ret = recurse(expr->idx_expression, func, param, nr);
99 break;
100 case EXPR_POS:
101 ret = recurse(expr->init_expr, func, param, nr);
102 break;
103 case EXPR_SYMBOL:
104 case EXPR_STRING:
105 case EXPR_VALUE:
106 break;
107 default:
108 return -1;
109 break;
110 };
111 return ret;
112 }
113
has_symbol_helper(struct expression * expr,void * _sym)114 static int has_symbol_helper(struct expression *expr, void *_sym)
115 {
116 struct symbol *sym = _sym;
117
118 if (!expr || expr->type != EXPR_SYMBOL)
119 return 0;
120 if (expr->symbol == sym)
121 return 1;
122 return 0;
123 }
124
has_symbol(struct expression * expr,struct symbol * sym)125 int has_symbol(struct expression *expr, struct symbol *sym)
126 {
127 return recurse(expr, has_symbol_helper, sym, 0);
128 }
129
130 struct expr_name_sym {
131 struct expression *expr;
132 char *name;
133 struct symbol *sym;
134 };
135
has_var_helper(struct expression * expr,void * _var)136 static int has_var_helper(struct expression *expr, void *_var)
137 {
138 struct expr_name_sym *xns = _var;
139 char *name;
140 struct symbol *sym;
141 int matched = 0;
142
143 if (!expr)
144 return 0;
145 if (expr->type != xns->expr->type)
146 return 0;
147 // I hope this is defined for everything? It should work, right?
148 if (expr->op != xns->expr->op)
149 return 0;
150
151 name = expr_to_var_sym(expr, &sym);
152 if (!name || !sym)
153 goto free;
154 if (sym == xns->sym && strcmp(name, xns->name) == 0)
155 matched = 1;
156 free:
157 free_string(name);
158 return matched;
159 }
160
has_variable(struct expression * expr,struct expression * var)161 int has_variable(struct expression *expr, struct expression *var)
162 {
163 struct expr_name_sym xns;
164 int ret = -1;
165
166 xns.expr = var;
167 xns.name = expr_to_var_sym(var, &xns.sym);
168 if (!xns.name || !xns.sym)
169 goto free;
170 ret = recurse(expr, has_var_helper, &xns, 0);
171 free:
172 free_string(xns.name);
173 return ret;
174 }
175
has_inc_dec_helper(struct expression * expr,void * unused)176 static int has_inc_dec_helper(struct expression *expr, void *unused)
177 {
178 if (!expr)
179 return 0;
180 if (expr->type != EXPR_PREOP && expr->type != EXPR_POSTOP)
181 return 0;
182 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
183 return 1;
184 return 0;
185 }
186
has_inc_dec(struct expression * expr)187 int has_inc_dec(struct expression *expr)
188 {
189 return recurse(expr, has_inc_dec_helper, NULL, 0);
190 }
191
192