points_to_user_data: rename set_points_to_user_data() to set_array_user_ptr()
[smatch.git] / check_iterator_outside_loop.c
bloba82d630209640ce839b271da115b4be4c8467346
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_slist.h"
20 #include "smatch_extra.h"
22 static int my_id;
24 STATE(iterator);
26 static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
28 set_state(my_id, sm->name, sm->sym, &undefined);
31 static struct expression *get_iterator(struct statement *stmt)
33 struct expression *expr;
35 if (!stmt ||
36 stmt->type != STMT_ITERATOR ||
37 !stmt->iterator_pre_statement ||
38 stmt->iterator_pre_statement->type != STMT_EXPRESSION)
39 return NULL;
42 expr = strip_expr(stmt->iterator_pre_statement->expression);
43 if (!expr || expr->type != EXPR_ASSIGNMENT)
44 return NULL;
46 return strip_expr(expr->left);
49 static void match_loop(struct statement *stmt)
51 struct expression *pos;
52 char *macro;
54 if (stmt->type != STMT_ITERATOR)
55 return;
56 if (!stmt->iterator_pre_statement ||
57 !stmt->iterator_pre_condition ||
58 !stmt->iterator_post_statement)
59 return;
61 macro = get_macro_name(stmt->pos);
62 if (!macro)
63 return;
64 if (strncmp(macro, "list_for_each", strlen("list_for_each")) != 0)
65 return;
66 pos = get_iterator(stmt);
67 if (!pos)
68 return;
70 set_state_expr(my_id, pos, &iterator);
73 static bool getting_prev_next(struct expression *expr)
75 struct expression *parent;
76 int cnt = 0;
78 parent = expr;
79 while ((parent = expr_get_parent_expr(parent))) {
80 if (parent->type == EXPR_PREOP && parent->op == '(')
81 continue;
82 if (parent->type == EXPR_DEREF &&
83 parent->member &&
84 (strcmp(parent->member->name, "prev") == 0 ||
85 strcmp(parent->member->name, "next") == 0))
86 return true;
87 if (cnt++ > 3)
88 break;
91 return false;
94 static void match_dereference(struct expression *expr)
96 struct expression *orig = expr;
97 struct sm_state *sm;
98 char *name;
100 if (expr->type == EXPR_PREOP && expr->op == '*')
101 expr = strip_expr(expr->unop);
103 sm = get_sm_state_expr(my_id, expr);
104 if (!sm || !slist_has_state(sm->possible, &iterator))
105 return;
107 if (getting_prev_next(orig))
108 return;
110 name = expr_to_str(expr);
111 sm_warning("iterator used outside loop: '%s'", name);
112 free_string(name);
114 set_state_expr(my_id, expr, &undefined);
117 void check_iterator_outside_loop(int id)
119 my_id = id;
121 if (option_project != PROJ_KERNEL)
122 return;
124 add_hook(match_loop, AFTER_LOOP_NO_BREAKS);
125 add_modification_hook(my_id, &ok_to_use);
126 add_hook(&match_dereference, DEREF_HOOK);