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