2 * Copyright (C) 2014 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
22 static struct string_list
*ignored_macros
;
24 static int in_ignored_macro(struct statement
*stmt
)
29 macro
= get_macro_name(stmt
->pos
);
33 FOR_EACH_PTR(ignored_macros
, tmp
) {
34 if (!strcmp(tmp
, macro
))
36 } END_FOR_EACH_PTR(tmp
);
40 static int missing_curly_braces(struct statement
*stmt
)
44 if (stmt
->pos
.pos
== __prev_stmt
->pos
.pos
)
47 if (__prev_stmt
->type
== STMT_IF
) {
48 if (__prev_stmt
->if_true
->type
== STMT_COMPOUND
)
50 inside_pos
= __prev_stmt
->if_true
->pos
.pos
;
51 } else if (__prev_stmt
->type
== STMT_ITERATOR
) {
52 if (!__prev_stmt
->iterator_pre_condition
)
54 if (__prev_stmt
->iterator_statement
->type
== STMT_COMPOUND
)
56 inside_pos
= __prev_stmt
->iterator_statement
->pos
.pos
;
61 if (stmt
->pos
.pos
!= inside_pos
)
64 sm_msg("warn: curly braces intended?");
68 static int prev_lines_say_endif(struct statement
*stmt
)
71 struct position pos
= stmt
->pos
;
76 for (i
= 0; i
< 4; i
++) {
78 token
= pos_get_token(pos
);
79 if (token
&& token_type(token
) == TOKEN_IDENT
&&
80 strcmp(show_ident(token
->ident
), "endif") == 0)
88 * If we go out of position, then warn, but don't warn when we go back
89 * into the correct position.
94 * If the code has two statements on the same line then don't complain
95 * on the following line. This is a bit of hack because it relies on the
96 * quirk that we don't process nested inline functions.
98 static struct position ignore_prev
;
99 static struct position ignore_prev_inline
;
101 static void match_stmt(struct statement
*stmt
)
103 if (stmt
!= __cur_stmt
)
108 if (prev_lines_say_endif(stmt
))
111 /* ignore empty statements if (foo) frob();; */
112 if (stmt
->type
== STMT_EXPRESSION
&& !stmt
->expression
)
114 if (__prev_stmt
->type
== STMT_EXPRESSION
&& !__prev_stmt
->expression
)
117 if (__prev_stmt
->type
== STMT_LABEL
|| __prev_stmt
->type
== STMT_CASE
)
120 * This is sort of ugly. The first statement after a case/label is
121 * special. Probably we should handle this in smatch_flow.c so that
122 * this is not a special case. Anyway it's like this:
123 * "foo: one++; two++;" The code is on the same line.
124 * Also there is still a false positive here, if the first case
125 * statement has two statements on the same line. I'm not sure what the
128 if (stmt
->type
== STMT_CASE
) {
130 __next_stmt
->pos
.line
== stmt
->case_statement
->pos
.line
)
131 ignore_prev
= __next_stmt
->pos
;
134 if (stmt
->type
== STMT_LABEL
) {
136 __next_stmt
->pos
.line
== stmt
->label_statement
->pos
.line
)
137 ignore_prev
= __next_stmt
->pos
;
141 if (missing_curly_braces(stmt
))
144 if (stmt
->pos
.line
== __prev_stmt
->pos
.line
) {
146 ignore_prev_inline
= stmt
->pos
;
148 ignore_prev
= stmt
->pos
;
151 if (stmt
->pos
.pos
== __prev_stmt
->pos
.pos
)
154 /* some people like to line up their break and case statements. */
155 if (stmt
->type
== STMT_GOTO
&& stmt
->goto_label
&&
156 stmt
->goto_label
->type
== SYM_NODE
&&
157 strcmp(stmt
->goto_label
->ident
->name
, "break") == 0) {
158 if (__next_stmt
&& __next_stmt
->type
== STMT_CASE
&&
159 (stmt
->pos
.line
== __next_stmt
->pos
.line
||
160 stmt
->pos
.pos
== __next_stmt
->pos
.pos
))
163 * If we have a compound and the last statement is a break then
164 * it's probably intentional. This is most likely inside a
171 if (cmp_pos(__prev_stmt
->pos
, ignore_prev
) == 0 ||
172 cmp_pos(__prev_stmt
->pos
, ignore_prev_inline
) == 0)
175 if (in_ignored_macro(stmt
))
178 if (stmt
->pos
.pos
== orig_pos
) {
182 sm_msg("warn: inconsistent indenting");
183 orig_pos
= __prev_stmt
->pos
.pos
;
186 static void match_end_func(void)
193 static void register_ignored_macros(void)
199 snprintf(name
, 256, "%s.ignore_macro_indenting", option_project_str
);
201 token
= get_tokens_file(name
);
204 if (token_type(token
) != TOKEN_STREAMBEGIN
)
207 while (token_type(token
) != TOKEN_STREAMEND
) {
208 if (token_type(token
) != TOKEN_IDENT
)
210 macro
= alloc_string(show_ident(token
->ident
));
211 add_ptr_list(&ignored_macros
, macro
);
217 void check_indenting(int id
)
220 add_hook(&match_stmt
, STMT_HOOK
);
221 add_hook(&match_end_func
, END_FUNC_HOOK
);
222 register_ignored_macros();