param_key: use get_name_sym_from_key() instead of return_state_to_var_sym()
[smatch.git] / smatch_param_key.c
blob5e4dbb146dd0a5b9179af10df3307a975c9d9d54
1 /*
2 * Copyright (C) 2020 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"
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
22 static int my_id;
24 static char *swap_names(const char *orig, const char *remove, const char *add)
26 int offset, len;
27 char buf[64];
29 offset = 0;
30 while(orig[offset] == '*' || orig[offset] == '&' || orig[offset] == '(')
31 offset++;
33 len = strlen(remove);
34 if (len + offset > strlen(orig))
35 return NULL;
36 if (orig[offset + len] != '-')
37 return NULL;
38 if (strncmp(orig + offset, remove, len) != 0)
39 return NULL;
41 snprintf(buf, sizeof(buf), "%.*s%s%s", offset, orig, add, orig + offset + len);
42 return alloc_string(buf);
45 static char *swap_with_param(const char *name, struct symbol *sym, struct symbol **sym_p)
47 struct smatch_state *state;
48 struct var_sym *var_sym;
49 char *ret;
52 * Say you know that "foo = bar;" and you have a state "foo->baz" then
53 * we can just substitute "bar" for "foo" giving "bar->baz".
56 if (!sym || !sym->ident)
57 return NULL;
59 state = get_state(my_id, sym->ident->name, sym);
60 if (!state || !state->data)
61 return NULL;
62 var_sym = state->data;
64 ret = swap_names(name, sym->ident->name, var_sym->var);
65 if (!ret)
66 return NULL;
68 *sym_p = var_sym->sym;
69 return ret;
72 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
74 struct symbol *type;
75 char buf[256];
76 char *tmp;
77 int star_cnt = 0;
78 bool add_dot = false;
80 if (!arg)
81 return NULL;
83 arg = strip_expr(arg);
85 if (strcmp(key, "$") == 0)
86 return expr_to_var_sym(arg, sym);
88 if (strcmp(key, "*$") == 0) {
89 if (arg->type == EXPR_PREOP && arg->op == '&') {
90 arg = strip_expr(arg->unop);
91 return expr_to_var_sym(arg, sym);
92 } else {
93 tmp = expr_to_var_sym(arg, sym);
94 if (!tmp)
95 return NULL;
96 snprintf(buf, sizeof(buf), "*%s", tmp);
97 free_string(tmp);
98 return alloc_string(buf);
102 if (strncmp(key, "(*$)", 4) == 0) {
103 char buf[64];
105 if (arg->type == EXPR_PREOP && arg->op == '&') {
106 arg = strip_expr(arg->unop);
107 snprintf(buf, sizeof(buf), "$%s", key + 4);
108 return get_variable_from_key(arg, buf, sym);
109 } else {
110 tmp = expr_to_var_sym(arg, sym);
111 if (!tmp)
112 return NULL;
113 snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
114 free_string(tmp);
115 return alloc_string(buf);
119 while (key[0] == '*') {
120 star_cnt++;
121 key++;
125 * FIXME: This is a hack.
126 * We should be able to parse expressions like (*$)->foo and *$->foo.
128 type = get_type(arg);
129 if (is_struct_ptr(type))
130 add_dot = true;
132 if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
133 arg = strip_expr(arg->unop);
134 star_cnt--;
137 if (arg->type == EXPR_PREOP && arg->op == '&') {
138 arg = strip_expr(arg->unop);
139 tmp = expr_to_var_sym(arg, sym);
140 if (!tmp)
141 return NULL;
142 snprintf(buf, sizeof(buf), "%.*s%s.%s",
143 star_cnt, "**********", tmp, key + 3);
144 return alloc_string(buf);
147 tmp = expr_to_var_sym(arg, sym);
148 if (!tmp)
149 return NULL;
150 snprintf(buf, sizeof(buf), "%.*s%s%s", star_cnt, "**********", tmp, key + 1);
151 free_string(tmp);
152 return alloc_string(buf);
155 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)
157 *vsl = NULL;
159 if (strcmp("$", key) == 0)
160 return expr_to_chunk_sym_vsl(arg, sym, vsl);
161 return get_variable_from_key(arg, key, sym);
164 const char *state_name_to_param_name(const char *state_name, const char *param_name)
166 int star_cnt = 0;
167 int name_len;
168 char buf[256];
170 name_len = strlen(param_name);
172 while (state_name[0] == '*') {
173 star_cnt++;
174 state_name++;
177 /* ten out of ten stars! */
178 if (star_cnt > 10)
179 return NULL;
181 if (strncmp(state_name, "(*", 2) == 0 &&
182 strncmp(state_name + 2, param_name, name_len) == 0 &&
183 state_name[name_len + 2] == ')') {
184 snprintf(buf, sizeof(buf), "%.*s(*$)%s", star_cnt, "**********",
185 state_name + name_len + 3);
186 return alloc_sname(buf);
189 if (strcmp(state_name, param_name) == 0) {
190 snprintf(buf, sizeof(buf), "%.*s$", star_cnt, "**********");
191 return alloc_sname(buf);
194 /* check for '-' from "->" */
195 if (strncmp(state_name, param_name, name_len) == 0 &&
196 state_name[name_len] == '-') {
197 snprintf(buf, sizeof(buf), "%.*s$%s", star_cnt, "**********", state_name + name_len);
198 return alloc_sname(buf);
200 return NULL;
203 const char *get_param_name_var_sym(const char *name, struct symbol *sym)
205 if (!sym || !sym->ident)
206 return NULL;
208 return state_name_to_param_name(name, sym->ident->name);
211 const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym)
213 struct symbol *type;
214 const char *sym_name;
215 int name_len;
216 static char buf[256];
219 * mtag_name is different from param_name because mtags can be a struct
220 * instead of a struct pointer. But we want to treat it like a pointer
221 * because really an mtag is a pointer. Or in other words, if you pass
222 * a struct foo then you want to talk about foo.bar but with an mtag
223 * you want to refer to it as foo->bar.
227 if (!sym || !sym->ident)
228 return NULL;
230 type = get_real_base_type(sym);
231 if (type && type->type == SYM_BASETYPE)
232 return "*$";
234 sym_name = sym->ident->name;
235 name_len = strlen(sym_name);
237 if (state_name[name_len] == '.' && /* check for '-' from "->" */
238 strncmp(state_name, sym_name, name_len) == 0) {
239 snprintf(buf, sizeof(buf), "$->%s", state_name + name_len + 1);
240 return buf;
243 return state_name_to_param_name(state_name, sym_name);
246 const char *get_mtag_name_expr(struct expression *expr)
248 char *name;
249 struct symbol *sym;
250 const char *ret = NULL;
252 name = expr_to_var_sym(expr, &sym);
253 if (!name || !sym)
254 goto free;
256 ret = get_mtag_name_var_sym(name, sym);
257 free:
258 free_string(name);
259 return ret;
262 const char *get_param_name(struct sm_state *sm)
264 return get_param_name_var_sym(sm->name, sm->sym);
267 static char *get_param_var_sym_var_sym(const char *name, struct symbol *sym, struct expression *ret_expr, struct symbol **sym_p)
269 struct smatch_state *state;
270 struct var_sym *var_sym;
271 int param;
273 *sym_p = NULL;
275 // FIXME was modified...
277 param = get_param_num_from_sym(sym);
278 if (param >= 0) {
279 *sym_p = sym;
280 return alloc_string(name);
283 state = get_state(my_id, name, sym);
284 if (state && state->data) {
285 var_sym = state->data;
286 if (!var_sym)
287 return NULL;
289 *sym_p = var_sym->sym;
290 return alloc_string(var_sym->var);
293 return swap_with_param(name, sym, sym_p);
296 static char *get_param_name_sym(struct expression *expr, struct symbol **sym_p)
298 struct symbol *sym;
299 const char *ret = NULL;
300 char *name;
302 name = expr_to_var_sym(expr, &sym);
303 if (!name || !sym)
304 goto free;
306 ret = get_param_var_sym_var_sym(name, sym, NULL, sym_p);
307 free:
308 free_string(name);
309 return alloc_string(ret);
312 int get_param_key_from_var_sym(const char *name, struct symbol *sym,
313 struct expression *ret_expr,
314 const char **key)
316 const char *param_name;
317 char *other_name;
318 struct symbol *other_sym;
319 int param;
321 *key = name;
323 /* straight forward param match */
324 param = get_param_num_from_sym(sym);
325 if (param >= 0) {
326 param_name = get_param_name_var_sym(name, sym);
327 if (param_name)
328 *key = param_name;
329 return param;
332 /* it's the return value */
333 if (ret_expr) {
334 struct symbol *ret_sym;
335 char *ret_str;
337 ret_str = expr_to_str_sym(ret_expr, &ret_sym);
338 if (ret_str && ret_sym == sym) {
339 param_name = state_name_to_param_name(name, ret_str);
340 if (param_name) {
341 free_string(ret_str);
342 *key = param_name;
343 return -1;
346 free_string(ret_str);
349 other_name = get_param_var_sym_var_sym(name, sym, ret_expr, &other_sym);
350 if (!other_name || !other_sym)
351 return -2;
352 param = get_param_num_from_sym(other_sym);
353 if (param < 0) {
354 sm_msg("internal: '%s' parameter not found", other_name);
355 return -2;
358 param_name = get_param_name_var_sym(other_name, other_sym);
359 if (param_name)
360 *key = param_name;
361 return param;
364 int get_param_key_from_sm(struct sm_state *sm, struct expression *ret_expr,
365 const char **key)
367 return get_param_key_from_var_sym(sm->name, sm->sym, ret_expr, key);
370 int get_param_num_from_sym(struct symbol *sym)
372 struct symbol *tmp;
373 int i;
375 if (!sym)
376 return UNKNOWN_SCOPE;
378 if (sym->ctype.modifiers & MOD_TOPLEVEL) {
379 if (sym->ctype.modifiers & MOD_STATIC)
380 return FILE_SCOPE;
381 return GLOBAL_SCOPE;
384 if (!cur_func_sym) {
385 if (!parse_error) {
386 sm_msg("warn: internal. problem with scope: %s",
387 sym->ident ? sym->ident->name : "<anon var>");
389 return GLOBAL_SCOPE;
393 i = 0;
394 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
395 if (tmp == sym)
396 return i;
397 i++;
398 } END_FOR_EACH_PTR(tmp);
399 return LOCAL_SCOPE;
402 int get_param_num(struct expression *expr)
404 struct symbol *sym;
405 char *name;
407 if (!cur_func_sym)
408 return UNKNOWN_SCOPE;
409 name = expr_to_var_sym(expr, &sym);
410 free_string(name);
411 if (!sym)
412 return UNKNOWN_SCOPE;
413 return get_param_num_from_sym(sym);
416 struct symbol *get_param_sym_from_num(int num)
418 struct symbol *sym;
419 int i;
421 if (!cur_func_sym)
422 return NULL;
424 i = 0;
425 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
426 if (i++ == num)
427 return sym;
428 } END_FOR_EACH_PTR(sym);
429 return NULL;
432 char *get_name_sym_from_key(struct expression *expr, int param, const char *key, struct symbol **sym)
434 struct expression *call, *arg;
435 char *name;
437 *sym = NULL;
439 if (!expr) {
440 sm_msg("internal: null call_expr. param=%d key='%s'", param, key);
441 return NULL;
444 call = expr;
445 while (call->type == EXPR_ASSIGNMENT)
446 call = strip_expr(call->right);
448 if (call->type != EXPR_CALL)
449 return NULL;
451 if (param == -1 &&
452 expr->type == EXPR_ASSIGNMENT &&
453 expr->op == '=') {
454 name = get_variable_from_key(expr->left, key, sym);
455 if (!name || !*sym)
456 goto free;
457 } else if (param >= 0) {
458 arg = get_argument_from_call_expr(call->args, param);
459 if (!arg)
460 return NULL;
462 name = get_variable_from_key(arg, key, sym);
463 if (!name || !*sym)
464 goto free;
465 } else {
466 name = alloc_string(key);
469 return name;
470 free:
471 free_string(name);
472 return NULL;
475 static void match_assign(struct expression *expr)
477 struct symbol *param_sym;
478 char *param_name;
480 if (expr->op != '=')
481 return;
483 /* __in_fake_parameter_assign is included deliberately */
484 if (is_fake_call(expr->right) ||
485 __in_fake_struct_assign)
486 return;
488 param_name = get_param_name_sym(expr->right, &param_sym);
489 if (!param_name || !param_sym)
490 goto free;
492 set_state_expr(my_id, expr->left, alloc_var_sym_state(param_name, param_sym));
493 free:
494 free_string(param_name);
497 void register_param_key(int id)
499 if (option_project != PROJ_KERNEL)
500 return;
502 my_id = id;
504 set_dynamic_states(my_id);
505 add_hook(&match_assign, ASSIGNMENT_HOOK);