2 * Copyright (C) 2012 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
20 #include "smatch_slist.h"
21 #include "smatch_expression_stacks.h"
25 static struct string_list
*ignored_macros
;
26 static struct position old_pos
;
28 static struct smatch_state
*alloc_my_state(struct expression
*expr
)
30 struct smatch_state
*state
;
33 expr
= strip_expr(expr
);
34 name
= expr_to_str(expr
);
38 state
= __alloc_smatch_state(0);
39 state
->name
= alloc_sname(name
);
45 static int defined_inside_macro(struct position macro_pos
, struct expression
*expr
)
51 name
= expr_to_var_sym(expr
, &sym
);
54 if (!sym
->scope
|| !sym
->scope
->token
)
56 if (positions_eq(macro_pos
, sym
->scope
->token
->pos
))
63 static int affected_inside_macro_before(struct expression
*expr
)
67 struct expression
*old_mod
;
69 sm
= get_sm_state_expr(my_id
, expr
);
73 FOR_EACH_PTR(sm
->possible
, tmp
) {
74 old_mod
= tmp
->state
->data
;
77 if (positions_eq(old_mod
->pos
, expr
->pos
))
79 } END_FOR_EACH_PTR(tmp
);
83 static int is_ignored_macro(const char *macro
)
87 FOR_EACH_PTR(ignored_macros
, tmp
) {
88 if (!strcmp(tmp
, macro
))
90 } END_FOR_EACH_PTR(tmp
);
94 static void match_unop(struct expression
*raw_expr
)
96 struct expression
*expr
;
99 if (raw_expr
->op
!= SPECIAL_INCREMENT
&& raw_expr
->op
!= SPECIAL_DECREMENT
)
102 macro
= get_macro_name(raw_expr
->pos
);
106 expr
= strip_expr(raw_expr
->unop
);
108 if (defined_inside_macro(expr
->pos
, expr
))
111 if (is_ignored_macro(macro
))
114 if (!affected_inside_macro_before(expr
)) {
115 set_state_expr(my_id
, expr
, alloc_my_state(expr
));
120 if (!positions_eq(old_pos
, expr
->pos
))
123 name
= expr_to_str(raw_expr
);
124 sm_warning("side effect in macro '%s' doing '%s'",
129 static void match_stmt(struct statement
*stmt
)
131 if (!positions_eq(old_pos
, stmt
->pos
))
135 static void register_ignored_macros(void)
141 snprintf(name
, 256, "%s.ignore_side_effects", option_project_str
);
143 token
= get_tokens_file(name
);
146 if (token_type(token
) != TOKEN_STREAMBEGIN
)
149 while (token_type(token
) != TOKEN_STREAMEND
) {
150 if (token_type(token
) != TOKEN_IDENT
)
152 macro
= alloc_string(show_ident(token
->ident
));
153 add_ptr_list(&ignored_macros
, macro
);
159 void check_macro_side_effects(int id
)
166 set_dynamic_states(my_id
);
167 add_hook(&match_unop
, OP_HOOK
);
168 add_hook(&match_stmt
, STMT_HOOK
);
169 register_ignored_macros();