*new* check_macros: find macro precedence bugs
[smatch.git] / check_macros.c
blob7bf31fb089eec3372500a830bdfaa4b71ebf1329
1 /*
2 * smatch/check_macros.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
12 static int my_id;
14 static int same_pos(struct position *pos1, struct position *pos2)
16 if (pos1->stream != pos2->stream)
17 return 0;
18 if (pos1->line != pos2->line)
19 return 0;
20 if (pos1->pos != pos2->pos)
21 return 0;
22 return 1;
25 static void match_inside(struct expression *expr, struct position *pos)
27 char *name;
28 int matched = 0;
30 if (same_pos(&expr->pos, pos))
31 matched++;
32 if (same_pos(&expr->unop->pos, pos))
33 matched++;
34 if (matched != 1)
35 return;
36 name = get_macro_name(pos);
37 if (!name)
38 return;
39 sm_msg("warn: the '%s' macro might need parens", name);
42 static void match_one_side(struct expression *expr, struct position *pos, int op)
44 char *name;
45 int matched = 0;
47 if ((op == '+' || op == '*' || op == '|' || op == '&') && expr->op == op)
48 return;
49 if (same_pos(&expr->right->pos, pos))
50 matched++;
51 if (same_pos(&expr->left->pos, pos))
52 matched++;
53 if (matched != 1)
54 return;
55 name = get_macro_name(pos);
56 if (!name)
57 return;
58 if (option_project == PROJ_WINE && !strcmp("BEGIN", name))
59 return;
60 sm_msg("warn: the '%s' macro might need parens", name);
63 static void match_join(struct expression *expr)
65 if (expr->left->type == EXPR_PREOP)
66 match_inside(expr->left, &expr->pos);
67 if (expr->right->type == EXPR_POSTOP)
68 match_inside(expr->right, &expr->pos);
70 if (expr->left->type == EXPR_BINOP)
71 match_one_side(expr->left, &expr->pos, expr->op);
72 if (expr->right->type == EXPR_BINOP)
73 match_one_side(expr->right, &expr->pos, expr->op);
76 void check_macros(int id)
78 my_id = id;
79 add_hook(&match_join, BINOP_HOOK);
80 add_hook(&match_join, LOGIC_HOOK);