xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/c-family/c-indentation.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* Implementation of -Wmisleading-indentation
2    Copyright (C) 2015-2020 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 
28 extern cpp_options *cpp_opts;
29 
30 /* Round up VIS_COLUMN to nearest tab stop. */
31 
32 static unsigned int
next_tab_stop(unsigned int vis_column,unsigned int tab_width)33 next_tab_stop (unsigned int vis_column, unsigned int tab_width)
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
46    on the line (up to or before EXPLOC).  */
47 
48 static bool
get_visual_column(expanded_location exploc,location_t loc,unsigned int * out,unsigned int * first_nws,unsigned int tab_width)49 get_visual_column (expanded_location exploc, location_t loc,
50 		   unsigned int *out,
51 		   unsigned int *first_nws,
52 		   unsigned int tab_width)
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,
67 		  "%<-Wmisleading-indentation%> is disabled from this point"
68 		  " onwards, since column-tracking was disabled due to"
69 		  " the size of the code/headers");
70 	}
71       return false;
72     }
73 
74   char_span line = location_get_source_line (exploc.file, exploc.line);
75   if (!line)
76     return false;
77   if ((size_t)exploc.column > line.length ())
78     return false;
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')
91 	vis_column = next_tab_stop (vis_column, tab_width);
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
get_first_nws_vis_column(const char * file,int line_num,unsigned int * first_nws,unsigned int tab_width)111 get_first_nws_vis_column (const char *file, int line_num,
112 			  unsigned int *first_nws,
113 			  unsigned int tab_width)
114 {
115   gcc_assert (first_nws);
116 
117   char_span line = location_get_source_line (file, line_num);
118   if (!line)
119     return false;
120   unsigned int vis_column = 0;
121   for (size_t i = 1; i < line.length (); i++)
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')
132 	vis_column = next_tab_stop (vis_column, tab_width);
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
detect_intervening_unindent(const char * file,int body_line,int next_stmt_line,unsigned int vis_column,unsigned int tab_width)182 detect_intervening_unindent (const char *file,
183 			     int body_line,
184 			     int next_stmt_line,
185 			     unsigned int vis_column,
186 			     unsigned int tab_width)
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;
194       if (get_first_nws_vis_column (file, line, &line_vis_column, tab_width))
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
should_warn_for_misleading_indentation(const token_indent_info & guard_tinfo,const token_indent_info & body_tinfo,const token_indent_info & next_tinfo)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 
297   const unsigned int tab_width = cpp_opts->tabstop;
298 
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,
344 				  &guard_line_first_nws, tab_width))
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,
404 			      &next_stmt_line_first_nws, tab_width))
405 	return false;
406       if (!get_visual_column (body_exploc, body_loc,
407 			      &body_vis_column,
408 			      &body_line_first_nws, tab_width))
409 	return false;
410       if (!get_visual_column (guard_exploc, guard_loc,
411 			      &guard_vis_column,
412 			      &guard_line_first_nws, tab_width))
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,
496 					   vis_column, tab_width))
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 *
guard_tinfo_to_string(enum rid keyword)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
warn_for_misleading_indentation(const token_indent_info & guard_tinfo,const token_indent_info & body_tinfo,const token_indent_info & next_tinfo)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     {
612       auto_diagnostic_group d;
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 }
622 
623 #if CHECKING_P
624 
625 namespace selftest {
626 
627 /* Verify that next_tab_stop works as expected.  */
628 
629 static void
test_next_tab_stop()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
assert_get_visual_column_succeeds(const location & loc,const char * file,int line,int column,const unsigned int tab_width,unsigned int expected_visual_column,unsigned int expected_first_nws)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
assert_get_visual_column_fails(const location & loc,const char * file,int line,int column,const unsigned int tab_width)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
test_get_visual_column()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
c_indentation_c_tests()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 */
779