1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2013 Oracle.
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
5*1f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
6*1f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
7*1f5207b7SJohn Levon  * of the License, or (at your option) any later version.
8*1f5207b7SJohn Levon  *
9*1f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
10*1f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*1f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*1f5207b7SJohn Levon  * GNU General Public License for more details.
13*1f5207b7SJohn Levon  *
14*1f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
15*1f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16*1f5207b7SJohn Levon  */
17*1f5207b7SJohn Levon 
18*1f5207b7SJohn Levon #include "smatch.h"
19*1f5207b7SJohn Levon 
20*1f5207b7SJohn Levon #define RECURSE_LIMIT 10
21*1f5207b7SJohn Levon 
recurse(struct expression * expr,int (func)(struct expression * expr,void * p),void * param,int nr)22*1f5207b7SJohn Levon static int recurse(struct expression *expr,
23*1f5207b7SJohn Levon 		   int (func)(struct expression *expr, void *p),
24*1f5207b7SJohn Levon 		   void *param, int nr)
25*1f5207b7SJohn Levon {
26*1f5207b7SJohn Levon 	int ret;
27*1f5207b7SJohn Levon 
28*1f5207b7SJohn Levon 	if (!expr)
29*1f5207b7SJohn Levon 		return 0;
30*1f5207b7SJohn Levon 
31*1f5207b7SJohn Levon 	ret = func(expr, param);
32*1f5207b7SJohn Levon 	if (ret)
33*1f5207b7SJohn Levon 		return ret;
34*1f5207b7SJohn Levon 
35*1f5207b7SJohn Levon 	if (nr > RECURSE_LIMIT)
36*1f5207b7SJohn Levon 		return -1;
37*1f5207b7SJohn Levon 	nr++;
38*1f5207b7SJohn Levon 
39*1f5207b7SJohn Levon 	switch (expr->type) {
40*1f5207b7SJohn Levon 	case EXPR_PREOP:
41*1f5207b7SJohn Levon 		ret = recurse(expr->unop, func, param, nr);
42*1f5207b7SJohn Levon 		break;
43*1f5207b7SJohn Levon 	case EXPR_POSTOP:
44*1f5207b7SJohn Levon 		ret = recurse(expr->unop, func, param, nr);
45*1f5207b7SJohn Levon 		break;
46*1f5207b7SJohn Levon 	case EXPR_STATEMENT:
47*1f5207b7SJohn Levon 		return -1;
48*1f5207b7SJohn Levon 		break;
49*1f5207b7SJohn Levon 	case EXPR_LOGICAL:
50*1f5207b7SJohn Levon 	case EXPR_COMPARE:
51*1f5207b7SJohn Levon 	case EXPR_BINOP:
52*1f5207b7SJohn Levon 	case EXPR_COMMA:
53*1f5207b7SJohn Levon 		ret = recurse(expr->left, func, param, nr);
54*1f5207b7SJohn Levon 		if (ret)
55*1f5207b7SJohn Levon 			return ret;
56*1f5207b7SJohn Levon 		ret = recurse(expr->right, func, param, nr);
57*1f5207b7SJohn Levon 		break;
58*1f5207b7SJohn Levon 	case EXPR_ASSIGNMENT:
59*1f5207b7SJohn Levon 		ret = recurse(expr->right, func, param, nr);
60*1f5207b7SJohn Levon 		if (ret)
61*1f5207b7SJohn Levon 			return ret;
62*1f5207b7SJohn Levon 		ret = recurse(expr->left, func, param, nr);
63*1f5207b7SJohn Levon 		break;
64*1f5207b7SJohn Levon 	case EXPR_DEREF:
65*1f5207b7SJohn Levon 		ret = recurse(expr->deref, func, param, nr);
66*1f5207b7SJohn Levon 		break;
67*1f5207b7SJohn Levon 	case EXPR_SLICE:
68*1f5207b7SJohn Levon 		ret = recurse(expr->base, func, param, nr);
69*1f5207b7SJohn Levon 		break;
70*1f5207b7SJohn Levon 	case EXPR_CAST:
71*1f5207b7SJohn Levon 	case EXPR_FORCE_CAST:
72*1f5207b7SJohn Levon 		ret = recurse(expr->cast_expression, func, param, nr);
73*1f5207b7SJohn Levon 		break;
74*1f5207b7SJohn Levon 	case EXPR_SIZEOF:
75*1f5207b7SJohn Levon 	case EXPR_OFFSETOF:
76*1f5207b7SJohn Levon 	case EXPR_ALIGNOF:
77*1f5207b7SJohn Levon 		break;
78*1f5207b7SJohn Levon 	case EXPR_CONDITIONAL:
79*1f5207b7SJohn Levon 	case EXPR_SELECT:
80*1f5207b7SJohn Levon 		ret = recurse(expr->conditional, func, param, nr);
81*1f5207b7SJohn Levon 		if (ret)
82*1f5207b7SJohn Levon 			return ret;
83*1f5207b7SJohn Levon 		ret = recurse(expr->cond_true, func, param, nr);
84*1f5207b7SJohn Levon 		if (ret)
85*1f5207b7SJohn Levon 			return ret;
86*1f5207b7SJohn Levon 		ret = recurse(expr->cond_false, func, param, nr);
87*1f5207b7SJohn Levon 		break;
88*1f5207b7SJohn Levon 	case EXPR_CALL:
89*1f5207b7SJohn Levon 		return -1;
90*1f5207b7SJohn Levon 		break;
91*1f5207b7SJohn Levon 	case EXPR_INITIALIZER:
92*1f5207b7SJohn Levon 		return -1;
93*1f5207b7SJohn Levon 		break;
94*1f5207b7SJohn Levon 	case EXPR_IDENTIFIER:
95*1f5207b7SJohn Levon 		ret = recurse(expr->ident_expression, func, param, nr);
96*1f5207b7SJohn Levon 		break;
97*1f5207b7SJohn Levon 	case EXPR_INDEX:
98*1f5207b7SJohn Levon 		ret = recurse(expr->idx_expression, func, param, nr);
99*1f5207b7SJohn Levon 		break;
100*1f5207b7SJohn Levon 	case EXPR_POS:
101*1f5207b7SJohn Levon 		ret = recurse(expr->init_expr, func, param, nr);
102*1f5207b7SJohn Levon 		break;
103*1f5207b7SJohn Levon 	case EXPR_SYMBOL:
104*1f5207b7SJohn Levon 	case EXPR_STRING:
105*1f5207b7SJohn Levon 	case EXPR_VALUE:
106*1f5207b7SJohn Levon 		break;
107*1f5207b7SJohn Levon 	default:
108*1f5207b7SJohn Levon 		return -1;
109*1f5207b7SJohn Levon 		break;
110*1f5207b7SJohn Levon 	};
111*1f5207b7SJohn Levon 	return ret;
112*1f5207b7SJohn Levon }
113*1f5207b7SJohn Levon 
has_symbol_helper(struct expression * expr,void * _sym)114*1f5207b7SJohn Levon static int has_symbol_helper(struct expression *expr, void *_sym)
115*1f5207b7SJohn Levon {
116*1f5207b7SJohn Levon 	struct symbol *sym = _sym;
117*1f5207b7SJohn Levon 
118*1f5207b7SJohn Levon 	if (!expr || expr->type != EXPR_SYMBOL)
119*1f5207b7SJohn Levon 		return 0;
120*1f5207b7SJohn Levon 	if (expr->symbol == sym)
121*1f5207b7SJohn Levon 		return 1;
122*1f5207b7SJohn Levon 	return 0;
123*1f5207b7SJohn Levon }
124*1f5207b7SJohn Levon 
has_symbol(struct expression * expr,struct symbol * sym)125*1f5207b7SJohn Levon int has_symbol(struct expression *expr, struct symbol *sym)
126*1f5207b7SJohn Levon {
127*1f5207b7SJohn Levon 	return recurse(expr, has_symbol_helper, sym, 0);
128*1f5207b7SJohn Levon }
129*1f5207b7SJohn Levon 
130*1f5207b7SJohn Levon struct expr_name_sym {
131*1f5207b7SJohn Levon 	struct expression *expr;
132*1f5207b7SJohn Levon 	char *name;
133*1f5207b7SJohn Levon 	struct symbol *sym;
134*1f5207b7SJohn Levon };
135*1f5207b7SJohn Levon 
has_var_helper(struct expression * expr,void * _var)136*1f5207b7SJohn Levon static int has_var_helper(struct expression *expr, void *_var)
137*1f5207b7SJohn Levon {
138*1f5207b7SJohn Levon 	struct expr_name_sym *xns = _var;
139*1f5207b7SJohn Levon 	char *name;
140*1f5207b7SJohn Levon 	struct symbol *sym;
141*1f5207b7SJohn Levon 	int matched = 0;
142*1f5207b7SJohn Levon 
143*1f5207b7SJohn Levon 	if (!expr)
144*1f5207b7SJohn Levon 		return 0;
145*1f5207b7SJohn Levon 	if (expr->type != xns->expr->type)
146*1f5207b7SJohn Levon 		return 0;
147*1f5207b7SJohn Levon 	// I hope this is defined for everything?  It should work, right?
148*1f5207b7SJohn Levon 	if (expr->op != xns->expr->op)
149*1f5207b7SJohn Levon 		return 0;
150*1f5207b7SJohn Levon 
151*1f5207b7SJohn Levon 	name = expr_to_var_sym(expr, &sym);
152*1f5207b7SJohn Levon 	if (!name || !sym)
153*1f5207b7SJohn Levon 		goto free;
154*1f5207b7SJohn Levon 	if (sym == xns->sym && strcmp(name, xns->name) == 0)
155*1f5207b7SJohn Levon 		matched = 1;
156*1f5207b7SJohn Levon free:
157*1f5207b7SJohn Levon 	free_string(name);
158*1f5207b7SJohn Levon 	return matched;
159*1f5207b7SJohn Levon }
160*1f5207b7SJohn Levon 
has_variable(struct expression * expr,struct expression * var)161*1f5207b7SJohn Levon int has_variable(struct expression *expr, struct expression *var)
162*1f5207b7SJohn Levon {
163*1f5207b7SJohn Levon 	struct expr_name_sym xns;
164*1f5207b7SJohn Levon 	int ret = -1;
165*1f5207b7SJohn Levon 
166*1f5207b7SJohn Levon 	xns.expr = var;
167*1f5207b7SJohn Levon 	xns.name = expr_to_var_sym(var, &xns.sym);
168*1f5207b7SJohn Levon 	if (!xns.name || !xns.sym)
169*1f5207b7SJohn Levon 		goto free;
170*1f5207b7SJohn Levon 	ret = recurse(expr, has_var_helper, &xns, 0);
171*1f5207b7SJohn Levon free:
172*1f5207b7SJohn Levon 	free_string(xns.name);
173*1f5207b7SJohn Levon 	return ret;
174*1f5207b7SJohn Levon }
175*1f5207b7SJohn Levon 
has_inc_dec_helper(struct expression * expr,void * unused)176*1f5207b7SJohn Levon static int has_inc_dec_helper(struct expression *expr, void *unused)
177*1f5207b7SJohn Levon {
178*1f5207b7SJohn Levon 	if (!expr)
179*1f5207b7SJohn Levon 		return 0;
180*1f5207b7SJohn Levon 	if (expr->type != EXPR_PREOP && expr->type != EXPR_POSTOP)
181*1f5207b7SJohn Levon 		return 0;
182*1f5207b7SJohn Levon 	if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
183*1f5207b7SJohn Levon 		return 1;
184*1f5207b7SJohn Levon 	return 0;
185*1f5207b7SJohn Levon }
186*1f5207b7SJohn Levon 
has_inc_dec(struct expression * expr)187*1f5207b7SJohn Levon int has_inc_dec(struct expression *expr)
188*1f5207b7SJohn Levon {
189*1f5207b7SJohn Levon 	return recurse(expr, has_inc_dec_helper, NULL, 0);
190*1f5207b7SJohn Levon }
191*1f5207b7SJohn Levon 
192