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