11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2014 Oracle.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon /*
191f5207b7SJohn Levon  * Some helper functions for managing links.
201f5207b7SJohn Levon  *
211f5207b7SJohn Levon  */
221f5207b7SJohn Levon 
231f5207b7SJohn Levon #include "smatch.h"
241f5207b7SJohn Levon #include "smatch_slist.h"
251f5207b7SJohn Levon 
alloc_link(struct var_sym_list * links)261f5207b7SJohn Levon static struct smatch_state *alloc_link(struct var_sym_list *links)
271f5207b7SJohn Levon {
281f5207b7SJohn Levon 	struct smatch_state *state;
291f5207b7SJohn Levon 	static char buf[256];
301f5207b7SJohn Levon 	struct var_sym *tmp;
311f5207b7SJohn Levon 	int i;
321f5207b7SJohn Levon 
331f5207b7SJohn Levon 	state = __alloc_smatch_state(0);
341f5207b7SJohn Levon 
351f5207b7SJohn Levon 	i = 0;
361f5207b7SJohn Levon 	FOR_EACH_PTR(links, tmp) {
371f5207b7SJohn Levon 		if (!i++) {
381f5207b7SJohn Levon 			snprintf(buf, sizeof(buf), "%s", tmp->var);
391f5207b7SJohn Levon 		} else {
401f5207b7SJohn Levon 			append(buf, ", ", sizeof(buf));
411f5207b7SJohn Levon 			append(buf, tmp->var, sizeof(buf));
421f5207b7SJohn Levon 		}
431f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
441f5207b7SJohn Levon 
451f5207b7SJohn Levon 	state->name = alloc_sname(buf);
461f5207b7SJohn Levon 	state->data = links;
471f5207b7SJohn Levon 	return state;
481f5207b7SJohn Levon }
491f5207b7SJohn Levon 
merge_link_states(struct smatch_state * s1,struct smatch_state * s2)501f5207b7SJohn Levon struct smatch_state *merge_link_states(struct smatch_state *s1, struct smatch_state *s2)
511f5207b7SJohn Levon {
521f5207b7SJohn Levon 	struct var_sym_list *new_links;
531f5207b7SJohn Levon 
541f5207b7SJohn Levon 	if (s1 == &undefined)
551f5207b7SJohn Levon 		return s2;
561f5207b7SJohn Levon 	if (s2 == &undefined)
571f5207b7SJohn Levon 		return s1;
581f5207b7SJohn Levon 
591f5207b7SJohn Levon 	if (var_sym_lists_equiv(s1->data, s2->data))
601f5207b7SJohn Levon 		return s1;
611f5207b7SJohn Levon 
621f5207b7SJohn Levon 	new_links = clone_var_sym_list(s1->data);
631f5207b7SJohn Levon 	merge_var_sym_list(&new_links, s2->data);
641f5207b7SJohn Levon 
651f5207b7SJohn Levon 	return alloc_link(new_links);
661f5207b7SJohn Levon }
671f5207b7SJohn Levon 
store_link(int link_id,const char * var,struct symbol * sym,const char * link_name,struct symbol * link_sym)681f5207b7SJohn Levon void store_link(int link_id, const char *var, struct symbol *sym, const char *link_name, struct symbol *link_sym)
691f5207b7SJohn Levon {
701f5207b7SJohn Levon 
711f5207b7SJohn Levon 	struct smatch_state *old_state;
721f5207b7SJohn Levon 	struct var_sym_list *links;
731f5207b7SJohn Levon 
741f5207b7SJohn Levon 	if (!cur_func_sym)
751f5207b7SJohn Levon 		return;
761f5207b7SJohn Levon 
771f5207b7SJohn Levon 	old_state = get_state(link_id, var, sym);
781f5207b7SJohn Levon 	if (old_state)
791f5207b7SJohn Levon 		links = clone_var_sym_list(old_state->data);
801f5207b7SJohn Levon 	else
811f5207b7SJohn Levon 		links = NULL;
821f5207b7SJohn Levon 
831f5207b7SJohn Levon 	add_var_sym(&links, link_name, link_sym);
841f5207b7SJohn Levon 	set_state(link_id, var, sym, alloc_link(links));
851f5207b7SJohn Levon }
861f5207b7SJohn Levon 
match_link_modify(struct sm_state * sm,struct expression * mod_expr)871f5207b7SJohn Levon static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
881f5207b7SJohn Levon {
891f5207b7SJohn Levon 	struct var_sym_list *links;
901f5207b7SJohn Levon 	struct var_sym *tmp;
911f5207b7SJohn Levon 
921f5207b7SJohn Levon 	links = sm->state->data;
931f5207b7SJohn Levon 
941f5207b7SJohn Levon 	FOR_EACH_PTR(links, tmp) {
951f5207b7SJohn Levon 		set_state(sm->owner - 1, tmp->var, tmp->sym, &undefined);
961f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
971f5207b7SJohn Levon 	set_state(sm->owner, sm->name, sm->sym, &undefined);
981f5207b7SJohn Levon }
991f5207b7SJohn Levon 
set_up_link_functions(int id,int link_id)1001f5207b7SJohn Levon void set_up_link_functions(int id, int link_id)
1011f5207b7SJohn Levon {
1021f5207b7SJohn Levon 	if (id + 1 != link_id)
1031f5207b7SJohn Levon 		sm_fatal("FATAL ERROR: links need to be registered directly after the check");
1041f5207b7SJohn Levon 
105*efe51d0cSJohn Levon 	set_dynamic_states(link_id);
1061f5207b7SJohn Levon 	add_merge_hook(link_id, &merge_link_states);
1071f5207b7SJohn Levon 	add_modification_hook(link_id, &match_link_modify);
1081f5207b7SJohn Levon 	// free link at the end of function
1091f5207b7SJohn Levon }
1101f5207b7SJohn Levon 
111