implied: fix get_tf_stacks_from_pool()
[smatch.git] / check_iterator_outside_loop.c
blob267eabea77bbdb9f6e625b3312453f2bf330ef08
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 struct expression *get_iterator(struct statement *stmt)
28 struct expression *expr;
30 if (!stmt ||
31 stmt->type != STMT_ITERATOR ||
32 !stmt->iterator_pre_statement ||
33 stmt->iterator_pre_statement->type != STMT_EXPRESSION)
34 return NULL;
36 expr = strip_expr(stmt->iterator_pre_statement->expression);
37 if (!expr || expr->type != EXPR_ASSIGNMENT)
38 return NULL;
40 return strip_expr(expr->left);
43 static void match_loop(struct statement *stmt)
45 struct expression *pos;
46 char *macro;
48 if (stmt->type != STMT_ITERATOR)
49 return;
50 if (!stmt->iterator_pre_statement ||
51 !stmt->iterator_pre_condition ||
52 !stmt->iterator_post_statement)
53 return;
55 macro = get_macro_name(stmt->pos);
56 if (!macro)
57 return;
58 if (strncmp(macro, "list_for_each", strlen("list_for_each")) != 0)
59 return;
60 pos = get_iterator(stmt);
61 if (!pos)
62 return;
64 set_state_expr(my_id, pos, &iterator);
67 static bool getting_prev_next(struct expression *expr)
69 struct expression *parent;
70 int cnt = 0;
72 parent = expr;
73 while ((parent = expr_get_parent_expr(parent))) {
74 if (parent->type == EXPR_PREOP && parent->op == '(')
75 continue;
76 if (parent->type == EXPR_DEREF &&
77 parent->member &&
78 (strcmp(parent->member->name, "prev") == 0 ||
79 strcmp(parent->member->name, "next") == 0))
80 return true;
81 if (cnt++ > 3)
82 break;
85 return false;
88 static void match_dereference(struct expression *expr)
90 struct expression *orig = expr;
91 struct sm_state *sm;
92 char *name;
94 if (expr->type == EXPR_PREOP && expr->op == '*')
95 expr = strip_expr(expr->unop);
97 sm = get_sm_state_expr(my_id, expr);
98 if (!sm || !slist_has_state(sm->possible, &iterator))
99 return;
101 if (getting_prev_next(orig))
102 return;
104 name = expr_to_str(expr);
105 sm_warning("iterator used outside loop: '%s'", name);
106 free_string(name);
108 set_state_expr(my_id, expr, &undefined);
111 void check_iterator_outside_loop(int id)
113 my_id = id;
115 if (option_project != PROJ_KERNEL)
116 return;
118 add_hook(match_loop, AFTER_LOOP_NO_BREAKS);
119 add_modification_hook(my_id, &set_undefined);
120 add_hook(&match_dereference, DEREF_HOOK);