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