comparison: improve "foo = min(...);" assignment handling
[smatch.git] / smatch_expressions.c
blob613a7f1cee653235f5865e08405fbc33fa1ef7b2
1 #include "smatch.h"
2 #include "smatch_extra.h"
4 __ALLOCATOR(struct expression, "temporary expr", tmp_expression);
6 static struct position get_cur_pos(void)
8 static struct position pos;
9 static struct position none;
10 struct expression *expr;
11 struct statement *stmt;
13 expr = last_ptr_list((struct ptr_list *)big_expression_stack);
14 stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
15 if (expr)
16 pos = expr->pos;
17 else if (stmt)
18 pos = stmt->pos;
19 else
20 pos = none;
21 return pos;
24 struct expression *alloc_tmp_expression(struct position pos, int type)
26 struct expression *expr;
28 expr = __alloc_tmp_expression(0);
29 expr->smatch_flags |= Fake;
30 expr->type = type;
31 expr->pos = pos;
32 return expr;
35 void free_tmp_expressions(void)
37 clear_tmp_expression_alloc();
40 struct expression *zero_expr(void)
42 struct expression *zero;
44 zero = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
45 zero->value = 0;
46 zero->ctype = &int_ctype;
47 return zero;
50 struct expression *value_expr(long long val)
52 struct expression *expr;
54 if (!val)
55 return zero_expr();
57 expr = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
58 expr->value = val;
59 expr->ctype = &llong_ctype;
60 return expr;
63 struct expression *member_expression(struct expression *deref, int op, struct ident *member)
65 struct expression *expr;
67 expr = alloc_tmp_expression(deref->pos, EXPR_DEREF);
68 expr->op = op;
69 expr->deref = deref;
70 expr->member = member;
71 expr->member_offset = -1;
72 return expr;
75 struct expression *preop_expression(struct expression *expr, int op)
77 struct expression *preop;
79 preop = alloc_tmp_expression(expr->pos, EXPR_PREOP);
80 preop->unop = expr;
81 preop->op = op;
82 return preop;
85 struct expression *deref_expression(struct expression *expr)
87 return preop_expression(expr, '*');
90 struct expression *assign_expression(struct expression *left, int op, struct expression *right)
92 struct expression *expr;
94 /* FIXME: make this a tmp expression. */
95 expr = alloc_expression(right->pos, EXPR_ASSIGNMENT);
96 expr->op = op;
97 expr->left = left;
98 expr->right = right;
99 return expr;
102 struct expression *binop_expression(struct expression *left, int op, struct expression *right)
104 struct expression *expr;
106 expr = alloc_tmp_expression(right->pos, EXPR_BINOP);
107 expr->op = op;
108 expr->left = left;
109 expr->right = right;
110 return expr;
113 struct expression *array_element_expression(struct expression *array, struct expression *offset)
115 struct expression *expr;
117 expr = binop_expression(array, '+', offset);
118 return deref_expression(expr);
121 struct expression *symbol_expression(struct symbol *sym)
123 struct expression *expr;
125 expr = alloc_tmp_expression(sym->pos, EXPR_SYMBOL);
126 expr->symbol = sym;
127 expr->symbol_name = sym->ident;
128 return expr;
131 struct expression *compare_expression(struct expression *left, int op, struct expression *right)
133 struct expression *expr;
135 expr = alloc_tmp_expression(get_cur_pos(), EXPR_COMPARE);
136 expr->op = op;
137 expr->left = left;
138 expr->right = right;
139 return expr;
142 struct expression *gen_expression_from_key(struct expression *arg, const char *key)
144 struct expression *ret;
145 struct token *token, *end;
146 const char *p = key;
147 char buf[4095];
148 char *alloc;
149 size_t len;
151 /* The idea is that we can parse either $0->foo or $->foo */
152 if (key[0] != '$')
153 return NULL;
154 p++;
155 while (*p >= '0' && *p <= '9')
156 p++;
157 len = snprintf(buf, sizeof(buf), "%s\n", p);
158 alloc = alloc_string(buf);
160 token = tokenize_buffer(alloc, len, &end);
161 if (!token)
162 return NULL;
163 if (token_type(token) != TOKEN_STREAMBEGIN)
164 return NULL;
165 token = token->next;
167 ret = arg;
168 while (token_type(token) == TOKEN_SPECIAL &&
169 token->special == SPECIAL_DEREFERENCE) {
170 token = token->next;
171 if (token_type(token) != TOKEN_IDENT)
172 return NULL;
173 ret = deref_expression(ret);
174 ret = member_expression(ret, '*', token->ident);
175 token = token->next;
178 if (token_type(token) != TOKEN_STREAMEND)
179 return NULL;
181 return ret;
184 void expr_set_parent_expr(struct expression *expr, struct expression *parent)
186 if (!expr)
187 return;
188 if (parent->smatch_flags & Fake)
189 return;
191 expr->parent = (unsigned long)parent | 0x1UL;
194 void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
196 if (!expr)
197 return;
198 expr->parent = (unsigned long)parent;
201 struct expression *expr_get_parent_expr(struct expression *expr)
203 if (!expr)
204 return NULL;
205 if (!(expr->parent & 0x1UL))
206 return NULL;
207 return (struct expression *)(expr->parent & ~0x1UL);
210 struct statement *expr_get_parent_stmt(struct expression *expr)
212 if (!expr)
213 return NULL;
214 if (expr->parent & 0x1UL)
215 return NULL;
216 return (struct statement *)expr->parent;