unreachable: don't complain about iterate_all_kinds()
[smatch.git] / check_indenting.c
blobde08a9eb3fc06208e1fba2ac29c73b75f3c6cf97
1 /*
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
18 #include "smatch.h"
20 static int my_id;
22 static struct string_list *ignored_macros;
24 static int in_ignored_macro(struct statement *stmt)
26 const char *macro;
27 char *tmp;
29 macro = get_macro_name(stmt->pos);
30 if (!macro)
31 return 0;
33 FOR_EACH_PTR(ignored_macros, tmp) {
34 if (!strcmp(tmp, macro))
35 return 1;
36 } END_FOR_EACH_PTR(tmp);
37 return 0;
40 static int missing_curly_braces(struct statement *stmt)
42 int inside_pos;
44 if (stmt->pos.pos == __prev_stmt->pos.pos)
45 return 0;
47 if (__prev_stmt->type == STMT_IF) {
48 if (__prev_stmt->if_true->type == STMT_COMPOUND)
49 return 0;
50 inside_pos = __prev_stmt->if_true->pos.pos;
51 } else if (__prev_stmt->type == STMT_ITERATOR) {
52 if (!__prev_stmt->iterator_pre_condition)
53 return 0;
54 if (__prev_stmt->iterator_statement->type == STMT_COMPOUND)
55 return 0;
56 inside_pos = __prev_stmt->iterator_statement->pos.pos;
57 } else {
58 return 0;
61 if (stmt->pos.pos != inside_pos)
62 return 0;
64 sm_msg("warn: curly braces intended?");
65 return 1;
68 static int prev_lines_say_endif(struct statement *stmt)
70 struct token *token;
71 struct position pos = stmt->pos;
72 int i;
74 pos.pos = 2;
76 for (i = 0; i < 4; i++) {
77 pos.line--;
78 token = pos_get_token(pos);
79 if (token && token_type(token) == TOKEN_IDENT &&
80 strcmp(show_ident(token->ident), "endif") == 0)
81 return 1;
84 return 0;
88 * If we go out of position, then warn, but don't warn when we go back
89 * into the correct position.
91 static int orig_pos;
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)
104 return;
105 if (!__prev_stmt)
106 return;
108 if (prev_lines_say_endif(stmt))
109 return;
111 /* ignore empty statements if (foo) frob();; */
112 if (stmt->type == STMT_EXPRESSION && !stmt->expression)
113 return;
114 if (__prev_stmt->type == STMT_EXPRESSION && !__prev_stmt->expression)
115 return;
117 if (__prev_stmt->type == STMT_LABEL || __prev_stmt->type == STMT_CASE)
118 return;
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
126 * deal is with that.
128 if (stmt->type == STMT_CASE) {
129 if (__next_stmt &&
130 __next_stmt->pos.line == stmt->case_statement->pos.line)
131 ignore_prev = __next_stmt->pos;
132 return;
134 if (stmt->type == STMT_LABEL) {
135 if (__next_stmt &&
136 __next_stmt->pos.line == stmt->label_statement->pos.line)
137 ignore_prev = __next_stmt->pos;
138 return;
141 if (missing_curly_braces(stmt))
142 return;
144 if (stmt->pos.line == __prev_stmt->pos.line) {
145 if (__inline_fn)
146 ignore_prev_inline = stmt->pos;
147 else
148 ignore_prev = stmt->pos;
149 return;
151 if (stmt->pos.pos == __prev_stmt->pos.pos)
152 return;
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))
161 return;
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
165 * case statement.
167 if (!__next_stmt)
168 return;
171 if (cmp_pos(__prev_stmt->pos, ignore_prev) == 0 ||
172 cmp_pos(__prev_stmt->pos, ignore_prev_inline) == 0)
173 return;
175 if (in_ignored_macro(stmt))
176 return;
178 if (stmt->pos.pos == orig_pos) {
179 orig_pos = 0;
180 return;
182 sm_msg("warn: inconsistent indenting");
183 orig_pos = __prev_stmt->pos.pos;
186 static void match_end_func(void)
188 if (__inline_fn)
189 return;
190 orig_pos = 0;
193 static void register_ignored_macros(void)
195 struct token *token;
196 char *macro;
197 char name[256];
199 snprintf(name, 256, "%s.ignore_macro_indenting", option_project_str);
201 token = get_tokens_file(name);
202 if (!token)
203 return;
204 if (token_type(token) != TOKEN_STREAMBEGIN)
205 return;
206 token = token->next;
207 while (token_type(token) != TOKEN_STREAMEND) {
208 if (token_type(token) != TOKEN_IDENT)
209 return;
210 macro = alloc_string(show_ident(token->ident));
211 add_ptr_list(&ignored_macros, macro);
212 token = token->next;
214 clear_token_alloc();
217 void check_indenting(int id)
219 my_id = id;
220 add_hook(&match_stmt, STMT_HOOK);
221 add_hook(&match_end_func, END_FUNC_HOOK);
222 register_ignored_macros();