annotate gcc/c-family/c-indentation.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Implementation of -Wmisleading-indentation
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2015-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This file is part of GCC.
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
7 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
8 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
9 version.
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
14 for more details.
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
17 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
18 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 #include "config.h"
kono
parents:
diff changeset
21 #include "system.h"
kono
parents:
diff changeset
22 #include "coretypes.h"
kono
parents:
diff changeset
23 #include "tm.h"
kono
parents:
diff changeset
24 #include "c-common.h"
kono
parents:
diff changeset
25 #include "c-indentation.h"
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
26 #include "selftest.h"
111
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 extern cpp_options *cpp_opts;
kono
parents:
diff changeset
29
kono
parents:
diff changeset
30 /* Round up VIS_COLUMN to nearest tab stop. */
kono
parents:
diff changeset
31
kono
parents:
diff changeset
32 static unsigned int
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
33 next_tab_stop (unsigned int vis_column, unsigned int tab_width)
111
kono
parents:
diff changeset
34 {
kono
parents:
diff changeset
35 vis_column = ((vis_column + tab_width) / tab_width) * tab_width;
kono
parents:
diff changeset
36 return vis_column;
kono
parents:
diff changeset
37 }
kono
parents:
diff changeset
38
kono
parents:
diff changeset
39 /* Convert libcpp's notion of a column (a 1-based char count) to
kono
parents:
diff changeset
40 the "visual column" (0-based column, respecting tabs), by reading the
kono
parents:
diff changeset
41 relevant line.
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43 Returns true if a conversion was possible, writing the result to OUT,
kono
parents:
diff changeset
44 otherwise returns false. If FIRST_NWS is not NULL, then write to it
kono
parents:
diff changeset
45 the visual column corresponding to the first non-whitespace character
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
46 on the line (up to or before EXPLOC). */
111
kono
parents:
diff changeset
47
kono
parents:
diff changeset
48 static bool
kono
parents:
diff changeset
49 get_visual_column (expanded_location exploc, location_t loc,
kono
parents:
diff changeset
50 unsigned int *out,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
51 unsigned int *first_nws,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
52 unsigned int tab_width)
111
kono
parents:
diff changeset
53 {
kono
parents:
diff changeset
54 /* PR c++/68819: if the column number is zero, we presumably
kono
parents:
diff changeset
55 had a location_t > LINE_MAP_MAX_LOCATION_WITH_COLS, and so
kono
parents:
diff changeset
56 we have no column information.
kono
parents:
diff changeset
57 Act as if no conversion was possible, triggering the
kono
parents:
diff changeset
58 error-handling path in the caller. */
kono
parents:
diff changeset
59 if (!exploc.column)
kono
parents:
diff changeset
60 {
kono
parents:
diff changeset
61 static bool issued_note = false;
kono
parents:
diff changeset
62 if (!issued_note)
kono
parents:
diff changeset
63 {
kono
parents:
diff changeset
64 /* Notify the user the first time this happens. */
kono
parents:
diff changeset
65 issued_note = true;
kono
parents:
diff changeset
66 inform (loc,
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
67 "%<-Wmisleading-indentation%> is disabled from this point"
111
kono
parents:
diff changeset
68 " onwards, since column-tracking was disabled due to"
kono
parents:
diff changeset
69 " the size of the code/headers");
kono
parents:
diff changeset
70 }
kono
parents:
diff changeset
71 return false;
kono
parents:
diff changeset
72 }
kono
parents:
diff changeset
73
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
74 char_span line = location_get_source_line (exploc.file, exploc.line);
111
kono
parents:
diff changeset
75 if (!line)
kono
parents:
diff changeset
76 return false;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
77 if ((size_t)exploc.column > line.length ())
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
78 return false;
111
kono
parents:
diff changeset
79 unsigned int vis_column = 0;
kono
parents:
diff changeset
80 for (int i = 1; i < exploc.column; i++)
kono
parents:
diff changeset
81 {
kono
parents:
diff changeset
82 unsigned char ch = line[i - 1];
kono
parents:
diff changeset
83
kono
parents:
diff changeset
84 if (first_nws != NULL && !ISSPACE (ch))
kono
parents:
diff changeset
85 {
kono
parents:
diff changeset
86 *first_nws = vis_column;
kono
parents:
diff changeset
87 first_nws = NULL;
kono
parents:
diff changeset
88 }
kono
parents:
diff changeset
89
kono
parents:
diff changeset
90 if (ch == '\t')
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
91 vis_column = next_tab_stop (vis_column, tab_width);
111
kono
parents:
diff changeset
92 else
kono
parents:
diff changeset
93 vis_column++;
kono
parents:
diff changeset
94 }
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 if (first_nws != NULL)
kono
parents:
diff changeset
97 *first_nws = vis_column;
kono
parents:
diff changeset
98
kono
parents:
diff changeset
99 *out = vis_column;
kono
parents:
diff changeset
100 return true;
kono
parents:
diff changeset
101 }
kono
parents:
diff changeset
102
kono
parents:
diff changeset
103 /* Attempt to determine the first non-whitespace character in line LINE_NUM
kono
parents:
diff changeset
104 of source line FILE.
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106 If this is possible, return true and write its "visual column" to
kono
parents:
diff changeset
107 *FIRST_NWS.
kono
parents:
diff changeset
108 Otherwise, return false, leaving *FIRST_NWS untouched. */
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 static bool
kono
parents:
diff changeset
111 get_first_nws_vis_column (const char *file, int line_num,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
112 unsigned int *first_nws,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
113 unsigned int tab_width)
111
kono
parents:
diff changeset
114 {
kono
parents:
diff changeset
115 gcc_assert (first_nws);
kono
parents:
diff changeset
116
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
117 char_span line = location_get_source_line (file, line_num);
111
kono
parents:
diff changeset
118 if (!line)
kono
parents:
diff changeset
119 return false;
kono
parents:
diff changeset
120 unsigned int vis_column = 0;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
121 for (size_t i = 1; i < line.length (); i++)
111
kono
parents:
diff changeset
122 {
kono
parents:
diff changeset
123 unsigned char ch = line[i - 1];
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 if (!ISSPACE (ch))
kono
parents:
diff changeset
126 {
kono
parents:
diff changeset
127 *first_nws = vis_column;
kono
parents:
diff changeset
128 return true;
kono
parents:
diff changeset
129 }
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 if (ch == '\t')
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
132 vis_column = next_tab_stop (vis_column, tab_width);
111
kono
parents:
diff changeset
133 else
kono
parents:
diff changeset
134 vis_column++;
kono
parents:
diff changeset
135 }
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 /* No non-whitespace characters found. */
kono
parents:
diff changeset
138 return false;
kono
parents:
diff changeset
139 }
kono
parents:
diff changeset
140
kono
parents:
diff changeset
141 /* Determine if there is an unindent/outdent between
kono
parents:
diff changeset
142 BODY_EXPLOC and NEXT_STMT_EXPLOC, to ensure that we don't
kono
parents:
diff changeset
143 issue a warning for cases like the following:
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 (1) Preprocessor logic
kono
parents:
diff changeset
146
kono
parents:
diff changeset
147 if (flagA)
kono
parents:
diff changeset
148 foo ();
kono
parents:
diff changeset
149 ^ BODY_EXPLOC
kono
parents:
diff changeset
150 #if SOME_CONDITION_THAT_DOES_NOT_HOLD
kono
parents:
diff changeset
151 if (flagB)
kono
parents:
diff changeset
152 #endif
kono
parents:
diff changeset
153 bar ();
kono
parents:
diff changeset
154 ^ NEXT_STMT_EXPLOC
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 "bar ();" is visually aligned below "foo ();" and
kono
parents:
diff changeset
157 is (as far as the parser sees) the next token, but
kono
parents:
diff changeset
158 this isn't misleading to a human reader.
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 (2) Empty macro with bad indentation
kono
parents:
diff changeset
161
kono
parents:
diff changeset
162 In the following, the
kono
parents:
diff changeset
163 "if (i > 0)"
kono
parents:
diff changeset
164 is poorly indented, and ought to be on the same column as
kono
parents:
diff changeset
165 "engine_ref_debug(e, 0, -1)"
kono
parents:
diff changeset
166 However, it is not misleadingly indented, due to the presence
kono
parents:
diff changeset
167 of that macro.
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 #define engine_ref_debug(X, Y, Z)
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 if (locked)
kono
parents:
diff changeset
172 i = foo (0);
kono
parents:
diff changeset
173 else
kono
parents:
diff changeset
174 i = foo (1);
kono
parents:
diff changeset
175 engine_ref_debug(e, 0, -1)
kono
parents:
diff changeset
176 if (i > 0)
kono
parents:
diff changeset
177 return 1;
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 Return true if such an unindent/outdent is detected. */
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 static bool
kono
parents:
diff changeset
182 detect_intervening_unindent (const char *file,
kono
parents:
diff changeset
183 int body_line,
kono
parents:
diff changeset
184 int next_stmt_line,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
185 unsigned int vis_column,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
186 unsigned int tab_width)
111
kono
parents:
diff changeset
187 {
kono
parents:
diff changeset
188 gcc_assert (file);
kono
parents:
diff changeset
189 gcc_assert (next_stmt_line > body_line);
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 for (int line = body_line + 1; line < next_stmt_line; line++)
kono
parents:
diff changeset
192 {
kono
parents:
diff changeset
193 unsigned int line_vis_column;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
194 if (get_first_nws_vis_column (file, line, &line_vis_column, tab_width))
111
kono
parents:
diff changeset
195 if (line_vis_column < vis_column)
kono
parents:
diff changeset
196 return true;
kono
parents:
diff changeset
197 }
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 /* Not found. */
kono
parents:
diff changeset
200 return false;
kono
parents:
diff changeset
201 }
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 /* Helper function for warn_for_misleading_indentation; see
kono
parents:
diff changeset
205 description of that function below. */
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 static bool
kono
parents:
diff changeset
208 should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
kono
parents:
diff changeset
209 const token_indent_info &body_tinfo,
kono
parents:
diff changeset
210 const token_indent_info &next_tinfo)
kono
parents:
diff changeset
211 {
kono
parents:
diff changeset
212 location_t guard_loc = guard_tinfo.location;
kono
parents:
diff changeset
213 location_t body_loc = body_tinfo.location;
kono
parents:
diff changeset
214 location_t next_stmt_loc = next_tinfo.location;
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 enum cpp_ttype body_type = body_tinfo.type;
kono
parents:
diff changeset
217 enum cpp_ttype next_tok_type = next_tinfo.type;
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 /* Don't attempt to compare the indentation of BODY_LOC and NEXT_STMT_LOC
kono
parents:
diff changeset
220 if either are within macros. */
kono
parents:
diff changeset
221 if (linemap_location_from_macro_expansion_p (line_table, body_loc)
kono
parents:
diff changeset
222 || linemap_location_from_macro_expansion_p (line_table, next_stmt_loc))
kono
parents:
diff changeset
223 return false;
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 /* Don't attempt to compare indentation if #line or # 44 "file"-style
kono
parents:
diff changeset
226 directives are present, suggesting generated code.
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 All bets are off if these are present: the file that the #line
kono
parents:
diff changeset
229 directive could have an entirely different coding layout to C/C++
kono
parents:
diff changeset
230 (e.g. .md files).
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 To determine if a #line is present, in theory we could look for a
kono
parents:
diff changeset
233 map with reason == LC_RENAME_VERBATIM. However, if there has
kono
parents:
diff changeset
234 subsequently been a long line requiring a column number larger than
kono
parents:
diff changeset
235 that representable by the original LC_RENAME_VERBATIM map, then
kono
parents:
diff changeset
236 we'll have a map with reason LC_RENAME.
kono
parents:
diff changeset
237 Rather than attempting to search all of the maps for a
kono
parents:
diff changeset
238 LC_RENAME_VERBATIM, instead we have libcpp set a flag whenever one
kono
parents:
diff changeset
239 is seen, and we check for the flag here.
kono
parents:
diff changeset
240 */
kono
parents:
diff changeset
241 if (line_table->seen_line_directive)
kono
parents:
diff changeset
242 return false;
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 /* We can't usefully warn about do-while and switch statements since the
kono
parents:
diff changeset
245 bodies of these statements are always explicitly delimited at both ends,
kono
parents:
diff changeset
246 so control flow is quite obvious. */
kono
parents:
diff changeset
247 if (guard_tinfo.keyword == RID_DO
kono
parents:
diff changeset
248 || guard_tinfo.keyword == RID_SWITCH)
kono
parents:
diff changeset
249 return false;
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 /* If the token following the body is a close brace or an "else"
kono
parents:
diff changeset
252 then while indentation may be sloppy, there is not much ambiguity
kono
parents:
diff changeset
253 about control flow, e.g.
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 if (foo) <- GUARD
kono
parents:
diff changeset
256 bar (); <- BODY
kono
parents:
diff changeset
257 else baz (); <- NEXT
kono
parents:
diff changeset
258
kono
parents:
diff changeset
259 {
kono
parents:
diff changeset
260 while (foo) <- GUARD
kono
parents:
diff changeset
261 bar (); <- BODY
kono
parents:
diff changeset
262 } <- NEXT
kono
parents:
diff changeset
263 baz ();
kono
parents:
diff changeset
264 */
kono
parents:
diff changeset
265 if (next_tok_type == CPP_CLOSE_BRACE
kono
parents:
diff changeset
266 || next_tinfo.keyword == RID_ELSE)
kono
parents:
diff changeset
267 return false;
kono
parents:
diff changeset
268
kono
parents:
diff changeset
269 /* Likewise, if the body of the guard is a compound statement then control
kono
parents:
diff changeset
270 flow is quite visually explicit regardless of the code's possibly poor
kono
parents:
diff changeset
271 indentation, e.g.
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 while (foo) <- GUARD
kono
parents:
diff changeset
274 { <- BODY
kono
parents:
diff changeset
275 bar ();
kono
parents:
diff changeset
276 }
kono
parents:
diff changeset
277 baz (); <- NEXT
kono
parents:
diff changeset
278
kono
parents:
diff changeset
279 Things only get muddy when the body of the guard does not have
kono
parents:
diff changeset
280 braces, e.g.
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 if (foo) <- GUARD
kono
parents:
diff changeset
283 bar (); <- BODY
kono
parents:
diff changeset
284 baz (); <- NEXT
kono
parents:
diff changeset
285 */
kono
parents:
diff changeset
286 if (body_type == CPP_OPEN_BRACE)
kono
parents:
diff changeset
287 return false;
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 /* Don't warn here about spurious semicolons. */
kono
parents:
diff changeset
290 if (next_tok_type == CPP_SEMICOLON)
kono
parents:
diff changeset
291 return false;
kono
parents:
diff changeset
292
kono
parents:
diff changeset
293 expanded_location body_exploc = expand_location (body_loc);
kono
parents:
diff changeset
294 expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
kono
parents:
diff changeset
295 expanded_location guard_exploc = expand_location (guard_loc);
kono
parents:
diff changeset
296
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
297 const unsigned int tab_width = cpp_opts->tabstop;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
298
111
kono
parents:
diff changeset
299 /* They must be in the same file. */
kono
parents:
diff changeset
300 if (next_stmt_exploc.file != body_exploc.file)
kono
parents:
diff changeset
301 return false;
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 /* If NEXT_STMT_LOC and BODY_LOC are on the same line, consider
kono
parents:
diff changeset
304 the location of the guard.
kono
parents:
diff changeset
305
kono
parents:
diff changeset
306 Cases where we want to issue a warning:
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 if (flag)
kono
parents:
diff changeset
309 foo (); bar ();
kono
parents:
diff changeset
310 ^ WARN HERE
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 if (flag) foo (); bar ();
kono
parents:
diff changeset
313 ^ WARN HERE
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315
kono
parents:
diff changeset
316 if (flag) ; {
kono
parents:
diff changeset
317 ^ WARN HERE
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 if (flag)
kono
parents:
diff changeset
320 ; {
kono
parents:
diff changeset
321 ^ WARN HERE
kono
parents:
diff changeset
322
kono
parents:
diff changeset
323 Cases where we don't want to issue a warning:
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 various_code (); if (flag) foo (); bar (); more_code ();
kono
parents:
diff changeset
326 ^ DON'T WARN HERE. */
kono
parents:
diff changeset
327 if (next_stmt_exploc.line == body_exploc.line)
kono
parents:
diff changeset
328 {
kono
parents:
diff changeset
329 if (guard_exploc.file != body_exploc.file)
kono
parents:
diff changeset
330 return true;
kono
parents:
diff changeset
331 if (guard_exploc.line < body_exploc.line)
kono
parents:
diff changeset
332 /* The guard is on a line before a line that contains both
kono
parents:
diff changeset
333 the body and the next stmt. */
kono
parents:
diff changeset
334 return true;
kono
parents:
diff changeset
335 else if (guard_exploc.line == body_exploc.line)
kono
parents:
diff changeset
336 {
kono
parents:
diff changeset
337 /* They're all on the same line. */
kono
parents:
diff changeset
338 gcc_assert (guard_exploc.file == next_stmt_exploc.file);
kono
parents:
diff changeset
339 gcc_assert (guard_exploc.line == next_stmt_exploc.line);
kono
parents:
diff changeset
340 unsigned int guard_vis_column;
kono
parents:
diff changeset
341 unsigned int guard_line_first_nws;
kono
parents:
diff changeset
342 if (!get_visual_column (guard_exploc, guard_loc,
kono
parents:
diff changeset
343 &guard_vis_column,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
344 &guard_line_first_nws, tab_width))
111
kono
parents:
diff changeset
345 return false;
kono
parents:
diff changeset
346 /* Heuristic: only warn if the guard is the first thing
kono
parents:
diff changeset
347 on its line. */
kono
parents:
diff changeset
348 if (guard_vis_column == guard_line_first_nws)
kono
parents:
diff changeset
349 return true;
kono
parents:
diff changeset
350 }
kono
parents:
diff changeset
351 }
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 /* If NEXT_STMT_LOC is on a line after BODY_LOC, consider
kono
parents:
diff changeset
354 their relative locations, and of the guard.
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 Cases where we want to issue a warning:
kono
parents:
diff changeset
357 if (flag)
kono
parents:
diff changeset
358 foo ();
kono
parents:
diff changeset
359 bar ();
kono
parents:
diff changeset
360 ^ WARN HERE
kono
parents:
diff changeset
361
kono
parents:
diff changeset
362 Cases where we don't want to issue a warning:
kono
parents:
diff changeset
363 if (flag)
kono
parents:
diff changeset
364 foo ();
kono
parents:
diff changeset
365 bar ();
kono
parents:
diff changeset
366 ^ DON'T WARN HERE (autogenerated code?)
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 if (flagA)
kono
parents:
diff changeset
369 foo ();
kono
parents:
diff changeset
370 #if SOME_CONDITION_THAT_DOES_NOT_HOLD
kono
parents:
diff changeset
371 if (flagB)
kono
parents:
diff changeset
372 #endif
kono
parents:
diff changeset
373 bar ();
kono
parents:
diff changeset
374 ^ DON'T WARN HERE
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 if (flag)
kono
parents:
diff changeset
377 ;
kono
parents:
diff changeset
378 foo ();
kono
parents:
diff changeset
379 ^ DON'T WARN HERE
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 #define emit
kono
parents:
diff changeset
382 if (flag)
kono
parents:
diff changeset
383 foo ();
kono
parents:
diff changeset
384 emit bar ();
kono
parents:
diff changeset
385 ^ DON'T WARN HERE
kono
parents:
diff changeset
386
kono
parents:
diff changeset
387 */
kono
parents:
diff changeset
388 if (next_stmt_exploc.line > body_exploc.line)
kono
parents:
diff changeset
389 {
kono
parents:
diff changeset
390 /* Determine if GUARD_LOC and NEXT_STMT_LOC are aligned on the same
kono
parents:
diff changeset
391 "visual column"... */
kono
parents:
diff changeset
392 unsigned int next_stmt_vis_column;
kono
parents:
diff changeset
393 unsigned int next_stmt_line_first_nws;
kono
parents:
diff changeset
394 unsigned int body_vis_column;
kono
parents:
diff changeset
395 unsigned int body_line_first_nws;
kono
parents:
diff changeset
396 unsigned int guard_vis_column;
kono
parents:
diff changeset
397 unsigned int guard_line_first_nws;
kono
parents:
diff changeset
398 /* If we can't determine it, don't issue a warning. This is sometimes
kono
parents:
diff changeset
399 the case for input files containing #line directives, and these
kono
parents:
diff changeset
400 are often for autogenerated sources (e.g. from .md files), where
kono
parents:
diff changeset
401 it's not clear that it's meaningful to look at indentation. */
kono
parents:
diff changeset
402 if (!get_visual_column (next_stmt_exploc, next_stmt_loc,
kono
parents:
diff changeset
403 &next_stmt_vis_column,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
404 &next_stmt_line_first_nws, tab_width))
111
kono
parents:
diff changeset
405 return false;
kono
parents:
diff changeset
406 if (!get_visual_column (body_exploc, body_loc,
kono
parents:
diff changeset
407 &body_vis_column,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
408 &body_line_first_nws, tab_width))
111
kono
parents:
diff changeset
409 return false;
kono
parents:
diff changeset
410 if (!get_visual_column (guard_exploc, guard_loc,
kono
parents:
diff changeset
411 &guard_vis_column,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
412 &guard_line_first_nws, tab_width))
111
kono
parents:
diff changeset
413 return false;
kono
parents:
diff changeset
414
kono
parents:
diff changeset
415 /* If the line where the next stmt starts has non-whitespace
kono
parents:
diff changeset
416 on it before the stmt, then don't warn:
kono
parents:
diff changeset
417 #define emit
kono
parents:
diff changeset
418 if (flag)
kono
parents:
diff changeset
419 foo ();
kono
parents:
diff changeset
420 emit bar ();
kono
parents:
diff changeset
421 ^ DON'T WARN HERE
kono
parents:
diff changeset
422 (PR c/69122). */
kono
parents:
diff changeset
423 if (next_stmt_line_first_nws < next_stmt_vis_column)
kono
parents:
diff changeset
424 return false;
kono
parents:
diff changeset
425
kono
parents:
diff changeset
426 if ((body_type != CPP_SEMICOLON
kono
parents:
diff changeset
427 && next_stmt_vis_column == body_vis_column)
kono
parents:
diff changeset
428 /* As a special case handle the case where the body is a semicolon
kono
parents:
diff changeset
429 that may be hidden by a preceding comment, e.g. */
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 // if (p)
kono
parents:
diff changeset
432 // /* blah */;
kono
parents:
diff changeset
433 // foo (1);
kono
parents:
diff changeset
434
kono
parents:
diff changeset
435 /* by looking instead at the column of the first non-whitespace
kono
parents:
diff changeset
436 character on the body line. */
kono
parents:
diff changeset
437 || (body_type == CPP_SEMICOLON
kono
parents:
diff changeset
438 && body_exploc.line > guard_exploc.line
kono
parents:
diff changeset
439 && body_line_first_nws != body_vis_column
kono
parents:
diff changeset
440 && next_stmt_vis_column > guard_line_first_nws))
kono
parents:
diff changeset
441 {
kono
parents:
diff changeset
442 /* Don't warn if they are aligned on the same column
kono
parents:
diff changeset
443 as the guard itself (suggesting autogenerated code that doesn't
kono
parents:
diff changeset
444 bother indenting at all).
kono
parents:
diff changeset
445 For "else" clauses, we consider the column of the first
kono
parents:
diff changeset
446 non-whitespace character on the guard line instead of the column
kono
parents:
diff changeset
447 of the actual guard token itself because it is more sensible.
kono
parents:
diff changeset
448 Consider:
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 if (p) {
kono
parents:
diff changeset
451 foo (1);
kono
parents:
diff changeset
452 } else // GUARD
kono
parents:
diff changeset
453 foo (2); // BODY
kono
parents:
diff changeset
454 foo (3); // NEXT
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 and:
kono
parents:
diff changeset
457
kono
parents:
diff changeset
458 if (p)
kono
parents:
diff changeset
459 foo (1);
kono
parents:
diff changeset
460 } else // GUARD
kono
parents:
diff changeset
461 foo (2); // BODY
kono
parents:
diff changeset
462 foo (3); // NEXT
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 If we just used the column of the "else" token, we would warn on
kono
parents:
diff changeset
465 the first example and not warn on the second. But we want the
kono
parents:
diff changeset
466 exact opposite to happen: to not warn on the first example (which
kono
parents:
diff changeset
467 is probably autogenerated) and to warn on the second (whose
kono
parents:
diff changeset
468 indentation is misleading). Using the column of the first
kono
parents:
diff changeset
469 non-whitespace character on the guard line makes that
kono
parents:
diff changeset
470 happen. */
kono
parents:
diff changeset
471 unsigned int guard_column = (guard_tinfo.keyword == RID_ELSE
kono
parents:
diff changeset
472 ? guard_line_first_nws
kono
parents:
diff changeset
473 : guard_vis_column);
kono
parents:
diff changeset
474 if (guard_column == body_vis_column)
kono
parents:
diff changeset
475 return false;
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 /* We may have something like:
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 if (p)
kono
parents:
diff changeset
480 {
kono
parents:
diff changeset
481 foo (1);
kono
parents:
diff changeset
482 } else // GUARD
kono
parents:
diff changeset
483 foo (2); // BODY
kono
parents:
diff changeset
484 foo (3); // NEXT
kono
parents:
diff changeset
485
kono
parents:
diff changeset
486 in which case the columns are not aligned but the code is not
kono
parents:
diff changeset
487 misleadingly indented. If the column of the body isn't indented
kono
parents:
diff changeset
488 more than the guard line then don't warn. */
kono
parents:
diff changeset
489 if (body_vis_column <= guard_line_first_nws)
kono
parents:
diff changeset
490 return false;
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 /* Don't warn if there is an unindent between the two statements. */
kono
parents:
diff changeset
493 int vis_column = MIN (next_stmt_vis_column, body_vis_column);
kono
parents:
diff changeset
494 if (detect_intervening_unindent (body_exploc.file, body_exploc.line,
kono
parents:
diff changeset
495 next_stmt_exploc.line,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
496 vis_column, tab_width))
111
kono
parents:
diff changeset
497 return false;
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 /* Otherwise, they are visually aligned: issue a warning. */
kono
parents:
diff changeset
500 return true;
kono
parents:
diff changeset
501 }
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 /* Also issue a warning for code having the form:
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 if (flag);
kono
parents:
diff changeset
506 foo ();
kono
parents:
diff changeset
507
kono
parents:
diff changeset
508 while (flag);
kono
parents:
diff changeset
509 {
kono
parents:
diff changeset
510 ...
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 for (...);
kono
parents:
diff changeset
514 {
kono
parents:
diff changeset
515 ...
kono
parents:
diff changeset
516 }
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 if (flag)
kono
parents:
diff changeset
519 ;
kono
parents:
diff changeset
520 else if (flag);
kono
parents:
diff changeset
521 foo ();
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 where the semicolon at the end of each guard is most likely spurious.
kono
parents:
diff changeset
524
kono
parents:
diff changeset
525 But do not warn on:
kono
parents:
diff changeset
526
kono
parents:
diff changeset
527 for (..);
kono
parents:
diff changeset
528 foo ();
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 where the next statement is aligned with the guard.
kono
parents:
diff changeset
531 */
kono
parents:
diff changeset
532 if (body_type == CPP_SEMICOLON)
kono
parents:
diff changeset
533 {
kono
parents:
diff changeset
534 if (body_exploc.line == guard_exploc.line)
kono
parents:
diff changeset
535 {
kono
parents:
diff changeset
536 if (next_stmt_vis_column > guard_line_first_nws
kono
parents:
diff changeset
537 || (next_tok_type == CPP_OPEN_BRACE
kono
parents:
diff changeset
538 && next_stmt_vis_column == guard_line_first_nws))
kono
parents:
diff changeset
539 return true;
kono
parents:
diff changeset
540 }
kono
parents:
diff changeset
541 }
kono
parents:
diff changeset
542 }
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 return false;
kono
parents:
diff changeset
545 }
kono
parents:
diff changeset
546
kono
parents:
diff changeset
547 /* Return the string identifier corresponding to the given guard token. */
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549 const char *
kono
parents:
diff changeset
550 guard_tinfo_to_string (enum rid keyword)
kono
parents:
diff changeset
551 {
kono
parents:
diff changeset
552 switch (keyword)
kono
parents:
diff changeset
553 {
kono
parents:
diff changeset
554 case RID_FOR:
kono
parents:
diff changeset
555 return "for";
kono
parents:
diff changeset
556 case RID_ELSE:
kono
parents:
diff changeset
557 return "else";
kono
parents:
diff changeset
558 case RID_IF:
kono
parents:
diff changeset
559 return "if";
kono
parents:
diff changeset
560 case RID_WHILE:
kono
parents:
diff changeset
561 return "while";
kono
parents:
diff changeset
562 case RID_DO:
kono
parents:
diff changeset
563 return "do";
kono
parents:
diff changeset
564 case RID_SWITCH:
kono
parents:
diff changeset
565 return "switch";
kono
parents:
diff changeset
566 default:
kono
parents:
diff changeset
567 gcc_unreachable ();
kono
parents:
diff changeset
568 }
kono
parents:
diff changeset
569 }
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 /* Called by the C/C++ frontends when we have a guarding statement at
kono
parents:
diff changeset
572 GUARD_LOC containing a statement at BODY_LOC, where the block wasn't
kono
parents:
diff changeset
573 written using braces, like this:
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 if (flag)
kono
parents:
diff changeset
576 foo ();
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 along with the location of the next token, at NEXT_STMT_LOC,
kono
parents:
diff changeset
579 so that we can detect followup statements that are within
kono
parents:
diff changeset
580 the same "visual block" as the guarded statement, but which
kono
parents:
diff changeset
581 aren't logically grouped within the guarding statement, such
kono
parents:
diff changeset
582 as:
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 GUARD_LOC
kono
parents:
diff changeset
585 |
kono
parents:
diff changeset
586 V
kono
parents:
diff changeset
587 if (flag)
kono
parents:
diff changeset
588 foo (); <- BODY_LOC
kono
parents:
diff changeset
589 bar (); <- NEXT_STMT_LOC
kono
parents:
diff changeset
590
kono
parents:
diff changeset
591 In the above, "bar ();" isn't guarded by the "if", but
kono
parents:
diff changeset
592 is indented to misleadingly suggest that it is in the same
kono
parents:
diff changeset
593 block as "foo ();".
kono
parents:
diff changeset
594
kono
parents:
diff changeset
595 GUARD_KIND identifies the kind of clause e.g. "if", "else" etc. */
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 void
kono
parents:
diff changeset
598 warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
kono
parents:
diff changeset
599 const token_indent_info &body_tinfo,
kono
parents:
diff changeset
600 const token_indent_info &next_tinfo)
kono
parents:
diff changeset
601 {
kono
parents:
diff changeset
602 /* Early reject for the case where -Wmisleading-indentation is disabled,
kono
parents:
diff changeset
603 to avoid doing work only to have the warning suppressed inside the
kono
parents:
diff changeset
604 diagnostic machinery. */
kono
parents:
diff changeset
605 if (!warn_misleading_indentation)
kono
parents:
diff changeset
606 return;
kono
parents:
diff changeset
607
kono
parents:
diff changeset
608 if (should_warn_for_misleading_indentation (guard_tinfo,
kono
parents:
diff changeset
609 body_tinfo,
kono
parents:
diff changeset
610 next_tinfo))
kono
parents:
diff changeset
611 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
612 auto_diagnostic_group d;
111
kono
parents:
diff changeset
613 if (warning_at (guard_tinfo.location, OPT_Wmisleading_indentation,
kono
parents:
diff changeset
614 "this %qs clause does not guard...",
kono
parents:
diff changeset
615 guard_tinfo_to_string (guard_tinfo.keyword)))
kono
parents:
diff changeset
616 inform (next_tinfo.location,
kono
parents:
diff changeset
617 "...this statement, but the latter is misleadingly indented"
kono
parents:
diff changeset
618 " as if it were guarded by the %qs",
kono
parents:
diff changeset
619 guard_tinfo_to_string (guard_tinfo.keyword));
kono
parents:
diff changeset
620 }
kono
parents:
diff changeset
621 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
622
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
623 #if CHECKING_P
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
624
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
625 namespace selftest {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
626
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
627 /* Verify that next_tab_stop works as expected. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
628
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
629 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
630 test_next_tab_stop ()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
631 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
632 const unsigned int tab_width = 8;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
633
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
634 ASSERT_EQ (next_tab_stop (0, tab_width), 8);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
635 ASSERT_EQ (next_tab_stop (1, tab_width), 8);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
636 ASSERT_EQ (next_tab_stop (7, tab_width), 8);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
637
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
638 ASSERT_EQ (next_tab_stop (8, tab_width), 16);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
639 ASSERT_EQ (next_tab_stop (9, tab_width), 16);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
640 ASSERT_EQ (next_tab_stop (15, tab_width), 16);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
641
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
642 ASSERT_EQ (next_tab_stop (16, tab_width), 24);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
643 ASSERT_EQ (next_tab_stop (17, tab_width), 24);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
644 ASSERT_EQ (next_tab_stop (23, tab_width), 24);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
645 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
646
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
647 /* Verify that the given call to get_visual_column succeeds, with
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
648 the given results. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
649
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
650 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
651 assert_get_visual_column_succeeds (const location &loc,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
652 const char *file, int line, int column,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
653 const unsigned int tab_width,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
654 unsigned int expected_visual_column,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
655 unsigned int expected_first_nws)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
656 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
657 expanded_location exploc;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
658 exploc.file = file;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
659 exploc.line = line;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
660 exploc.column = column;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
661 exploc.data = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
662 exploc.sysp = false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
663 unsigned int actual_visual_column;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
664 unsigned int actual_first_nws;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
665 bool result = get_visual_column (exploc, UNKNOWN_LOCATION,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
666 &actual_visual_column,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
667 &actual_first_nws, tab_width);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
668 ASSERT_TRUE_AT (loc, result);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
669 ASSERT_EQ_AT (loc, actual_visual_column, expected_visual_column);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
670 ASSERT_EQ_AT (loc, actual_first_nws, expected_first_nws);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
671 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
672
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
673 /* Verify that the given call to get_visual_column succeeds, with
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
674 the given results. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
675
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
676 #define ASSERT_GET_VISUAL_COLUMN_SUCCEEDS(FILENAME, LINE, COLUMN, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
677 TAB_WIDTH, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
678 EXPECTED_VISUAL_COLUMN, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
679 EXPECTED_FIRST_NWS) \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
680 SELFTEST_BEGIN_STMT \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
681 assert_get_visual_column_succeeds (SELFTEST_LOCATION, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
682 FILENAME, LINE, COLUMN, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
683 TAB_WIDTH, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
684 EXPECTED_VISUAL_COLUMN, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
685 EXPECTED_FIRST_NWS); \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
686 SELFTEST_END_STMT
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
687
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
688 /* Verify that the given call to get_visual_column fails gracefully. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
689
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
690 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
691 assert_get_visual_column_fails (const location &loc,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
692 const char *file, int line, int column,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
693 const unsigned int tab_width)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
694 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
695 expanded_location exploc;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
696 exploc.file = file;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
697 exploc.line = line;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
698 exploc.column = column;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
699 exploc.data = NULL;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
700 exploc.sysp = false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
701 unsigned int actual_visual_column;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
702 unsigned int actual_first_nws;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
703 bool result = get_visual_column (exploc, UNKNOWN_LOCATION,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
704 &actual_visual_column,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
705 &actual_first_nws, tab_width);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
706 ASSERT_FALSE_AT (loc, result);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
707 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
708
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
709 /* Verify that the given call to get_visual_column fails gracefully. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
710
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
711 #define ASSERT_GET_VISUAL_COLUMN_FAILS(FILENAME, LINE, COLUMN, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
712 TAB_WIDTH) \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
713 SELFTEST_BEGIN_STMT \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
714 assert_get_visual_column_fails (SELFTEST_LOCATION, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
715 FILENAME, LINE, COLUMN, \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
716 TAB_WIDTH); \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
717 SELFTEST_END_STMT
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
718
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
719 /* Verify that get_visual_column works as expected. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
720
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
721 static void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
722 test_get_visual_column ()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
723 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
724 /* Create a tempfile with a mixture of tabs and spaces.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
725
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
726 Both lines have either a space or a tab, then " line N",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
727 for 8 characters in total.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
728
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
729 1-based "columns" (w.r.t. to line 1):
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
730 .....................0000000001111.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
731 .....................1234567890123. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
732 const char *content = (" line 1\n"
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
733 "\t line 2\n");
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
734 line_table_test ltt;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
735 temp_source_file tmp (SELFTEST_LOCATION, ".txt", content);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
736
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
737 const unsigned int tab_width = 8;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
738 const char *file = tmp.get_filename ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
739
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
740 /* Line 1 (space-based indentation). */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
741 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
742 const int line = 1;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
743 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 1, tab_width, 0, 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
744 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 2, tab_width, 1, 1);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
745 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 3, tab_width, 2, 2);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
746 /* first_nws should have stopped increasing. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
747 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 4, tab_width, 3, 2);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
748 /* Verify the end-of-line boundary. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
749 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 8, tab_width, 7, 2);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
750 ASSERT_GET_VISUAL_COLUMN_FAILS (file, line, 9, tab_width);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
751 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
752
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
753 /* Line 2 (tab-based indentation). */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
754 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
755 const int line = 2;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
756 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 1, tab_width, 0, 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
757 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 2, tab_width, 8, 8);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
758 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 3, tab_width, 9, 9);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
759 /* first_nws should have stopped increasing. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
760 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 4, tab_width, 10, 9);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
761 /* Verify the end-of-line boundary. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
762 ASSERT_GET_VISUAL_COLUMN_SUCCEEDS (file, line, 8, tab_width, 14, 9);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
763 ASSERT_GET_VISUAL_COLUMN_FAILS (file, line, 9, tab_width);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
764 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
765 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
766
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
767 /* Run all of the selftests within this file. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
768
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
769 void
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
770 c_indentation_c_tests ()
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
771 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
772 test_next_tab_stop ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
773 test_get_visual_column ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
774 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
775
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
776 } // namespace selftest
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
777
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
778 #endif /* CHECKING_P */