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