struct_assignment: handle struct assignments to better
[smatch.git] / smatch_struct_assignment.c
blobf77c1ef6bcd5ae23bd1061aff1e2168e888b459e
1 /*
2 * sparse/smatch_struct_assignment.c
4 * Copyright (C) 2014 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "scope.h"
11 #include "smatch.h"
12 #include "smatch_slist.h"
13 #include "smatch_extra.h"
15 static struct symbol *get_struct_type(struct expression *expr)
17 struct symbol *type;
19 type = get_type(expr);
20 if (!type)
21 return NULL;
22 if (type->type == SYM_PTR)
23 type = get_real_base_type(type);
24 if (type && type->type == SYM_STRUCT)
25 return type;
26 return NULL;
29 static int known_struct_member_states(struct expression *expr)
31 struct state_list *slist = __get_cur_slist();
32 struct sm_state *sm;
33 char *name;
34 int ret = 0;
35 int cmp;
36 int len;
38 if (expr->type == EXPR_PREOP && expr->op == '&')
39 expr = strip_expr(expr->unop);
41 name = expr_to_var(expr);
42 if (!name)
43 return 0;
44 len = strlen(name);
46 FOR_EACH_PTR(slist, sm) {
47 if (sm->owner != SMATCH_EXTRA)
48 continue;
49 cmp = strncmp(sm->name, name, len);
50 if (cmp < 0)
51 continue;
52 if (cmp == 0) {
53 if (sm->name[len] == '.' ||
54 sm->name[len] == '-' ||
55 sm->name[len] == '.') {
56 ret = 1;
57 goto out;
59 continue;
61 goto out;
62 } END_FOR_EACH_PTR(sm);
64 out:
65 return ret;
68 static struct expression *get_matching_member_expr(struct symbol *left_type, struct expression *right, struct symbol *left_member)
70 struct symbol *struct_type;
71 int op = '.';
73 if (!left_member->ident)
74 return NULL;
76 struct_type = get_struct_type(right);
77 if (!struct_type)
78 return NULL;
79 if (struct_type != left_type)
80 return NULL;
82 if (right->type == EXPR_PREOP && right->op == '&')
83 right = strip_expr(right->unop);
85 if (is_pointer(right)) {
86 right = deref_expression(right);
87 op = '*';
90 return member_expression(right, op, left_member->ident);
93 void __struct_members_copy(int mode, struct expression *left, struct expression *right)
95 struct symbol *struct_type, *tmp, *type;
96 struct expression *left_member, *right_member, *assign;
97 int op = '.';
99 left = strip_expr(left);
100 right = strip_expr(right);
102 struct_type = get_struct_type(left);
103 if (!struct_type)
104 return;
106 if (!known_struct_member_states(right))
107 return;
109 if (is_pointer(left)) {
110 left = deref_expression(left);
111 op = '*';
114 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
115 type = get_real_base_type(tmp);
116 if (type && type->type == SYM_ARRAY)
117 continue;
119 left_member = member_expression(left, op, tmp->ident);
121 switch (mode) {
122 case COPY_NORMAL:
123 case COPY_MEMCPY:
124 right_member = get_matching_member_expr(struct_type, right, tmp);
125 break;
126 case COPY_MEMSET:
127 right_member = right;
128 break;
130 if (!right_member)
131 continue;
132 #if 0
133 if (!right_member)
134 continue;
135 if (!get_implied_rl(right_member, &rl) || is_whole_rl(rl))
136 continue;
137 #endif
138 assign = assign_expression(left_member, right_member);
139 __pass_to_client(assign, ASSIGNMENT_HOOK);
140 } END_FOR_EACH_PTR(tmp);
143 void __fake_struct_member_assignments(struct expression *expr)
145 __struct_members_copy(COPY_NORMAL, expr->left, expr->right);