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 state
= __alloc_smatch_state(0);
34 expr
= strip_expr(expr
);
35 name
= expr_to_str(expr
);
36 state
->name
= alloc_sname(name
);
42 static int defined_inside_macro(struct position macro_pos
, struct expression
*expr
)
48 name
= expr_to_var_sym(expr
, &sym
);
51 if (!sym
->scope
|| !sym
->scope
->token
)
53 if (positions_eq(macro_pos
, sym
->scope
->token
->pos
))
60 static int affected_inside_macro_before(struct expression
*expr
)
64 struct expression
*old_mod
;
66 sm
= get_sm_state_expr(my_id
, expr
);
70 FOR_EACH_PTR(sm
->possible
, tmp
) {
71 old_mod
= tmp
->state
->data
;
74 if (positions_eq(old_mod
->pos
, expr
->pos
))
76 } END_FOR_EACH_PTR(tmp
);
80 static int is_ignored_macro(const char *macro
)
84 FOR_EACH_PTR(ignored_macros
, tmp
) {
85 if (!strcmp(tmp
, macro
))
87 } END_FOR_EACH_PTR(tmp
);
91 static void match_unop(struct expression
*raw_expr
)
93 struct expression
*expr
;
96 if (raw_expr
->op
!= SPECIAL_INCREMENT
&& raw_expr
->op
!= SPECIAL_DECREMENT
)
99 macro
= get_macro_name(raw_expr
->pos
);
103 expr
= strip_expr(raw_expr
->unop
);
105 if (defined_inside_macro(expr
->pos
, expr
))
108 if (is_ignored_macro(macro
))
111 if (!affected_inside_macro_before(expr
)) {
112 set_state_expr(my_id
, expr
, alloc_my_state(expr
));
117 if (!positions_eq(old_pos
, expr
->pos
))
120 name
= expr_to_str(raw_expr
);
121 sm_warning("side effect in macro '%s' doing '%s'",
126 static void match_stmt(struct statement
*stmt
)
128 if (!positions_eq(old_pos
, stmt
->pos
))
132 static void register_ignored_macros(void)
138 snprintf(name
, 256, "%s.ignore_side_effects", option_project_str
);
140 token
= get_tokens_file(name
);
143 if (token_type(token
) != TOKEN_STREAMBEGIN
)
146 while (token_type(token
) != TOKEN_STREAMEND
) {
147 if (token_type(token
) != TOKEN_IDENT
)
149 macro
= alloc_string(show_ident(token
->ident
));
150 add_ptr_list(&ignored_macros
, macro
);
156 void check_macro_side_effects(int id
)
163 add_hook(&match_unop
, OP_HOOK
);
164 add_hook(&match_stmt
, STMT_HOOK
);
165 register_ignored_macros();