1 /* Implementation of -Wmisleading-indentation
2    Copyright (C) 2015-2021 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 
29 /* Round up VIS_COLUMN to nearest tab stop. */
30 
31 static unsigned int
next_tab_stop(unsigned int vis_column,unsigned int tab_width)32 next_tab_stop (unsigned int vis_column, unsigned int tab_width)
33 {
34   vis_column = ((vis_column + tab_width) / tab_width) * tab_width;
35   return vis_column;
36 }
37 
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.
41 
42    Returns true if a conversion was possible, writing the result to OUT,
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
45    on the line (up to or before EXPLOC).  */
46 
47 static bool
get_visual_column(expanded_location exploc,unsigned int * out,unsigned int * first_nws,unsigned int tab_width)48 get_visual_column (expanded_location exploc,
49 		   unsigned int *out,
50 		   unsigned int *first_nws,
51 		   unsigned int tab_width)
52 {
53   char_span line = location_get_source_line (exploc.file, exploc.line);
54   if (!line)
55     return false;
56   if ((size_t)exploc.column > line.length ())
57     return false;
58   unsigned int vis_column = 0;
59   for (int i = 1; i < exploc.column; i++)
60     {
61       unsigned char ch = line[i - 1];
62 
63       if (first_nws != NULL && !ISSPACE (ch))
64 	{
65 	  *first_nws = vis_column;
66 	  first_nws = NULL;
67 	}
68 
69       if (ch == '\t')
70 	vis_column = next_tab_stop (vis_column, tab_width);
71       else
72        vis_column++;
73     }
74 
75   if (first_nws != NULL)
76     *first_nws = vis_column;
77 
78   *out = vis_column;
79   return true;
80 }
81 
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.  */
88 
89 static bool
get_first_nws_vis_column(const char * file,int line_num,unsigned int * first_nws,unsigned int tab_width)90 get_first_nws_vis_column (const char *file, int line_num,
91 			  unsigned int *first_nws,
92 			  unsigned int tab_width)
93 {
94   gcc_assert (first_nws);
95 
96   char_span line = location_get_source_line (file, line_num);
97   if (!line)
98     return false;
99   unsigned int vis_column = 0;
100   for (size_t i = 1; i < line.length (); i++)
101     {
102       unsigned char ch = line[i - 1];
103 
104       if (!ISSPACE (ch))
105 	{
106 	  *first_nws = vis_column;
107 	  return true;
108 	}
109 
110       if (ch == '\t')
111 	vis_column = next_tab_stop (vis_column, tab_width);
112       else
113 	vis_column++;
114     }
115 
116   /* No non-whitespace characters found.  */
117   return false;
118 }
119 
120 /* Determine if there is an unindent/outdent between
121    BODY_EXPLOC and NEXT_STMT_EXPLOC, to ensure that we don't
122    issue a warning for cases like the following:
123 
124    (1) Preprocessor logic
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 
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.
138 
139    (2) Empty macro with bad indentation
140 
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.
147 
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;
157 
158    Return true if such an unindent/outdent is detected.  */
159 
160 static bool
detect_intervening_unindent(const char * file,int body_line,int next_stmt_line,unsigned int vis_column,unsigned int tab_width)161 detect_intervening_unindent (const char *file,
162 			     int body_line,
163 			     int next_stmt_line,
164 			     unsigned int vis_column,
165 			     unsigned int tab_width)
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;
173       if (get_first_nws_vis_column (file, line, &line_vis_column, tab_width))
174 	if (line_vis_column < vis_column)
175 	  return true;
176     }
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 
186 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)187 should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
188 					const token_indent_info &body_tinfo,
189 					const token_indent_info &next_tinfo)
190 {
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 
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)
215     return false;
216 
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   */
231   enum cpp_ttype next_tok_type = next_tinfo.type;
232   if (next_tok_type == CPP_CLOSE_BRACE
233       || next_tinfo.keyword == RID_ELSE)
234     return false;
235 
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   */
253   enum cpp_ttype body_type = body_tinfo.type;
254   if (body_type == CPP_OPEN_BRACE)
255     return false;
256 
257   /* Don't warn here about spurious semicolons.  */
258   if (next_tok_type == CPP_SEMICOLON)
259     return false;
260 
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 
303   expanded_location body_exploc = expand_location (body_loc);
304   expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
305   expanded_location guard_exploc = expand_location (guard_loc);
306 
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 
334   const unsigned int tab_width = global_dc->tabstop;
335 
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 
352 
353        if (flag) ; {
354                    ^ WARN HERE
355 
356        if (flag)
357         ; {
358           ^ WARN HERE
359 
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     {
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);
377 	  unsigned int guard_vis_column;
378 	  unsigned int guard_line_first_nws;
379 	  if (!get_visual_column (guard_exploc,
380 				  &guard_vis_column,
381 				  &guard_line_first_nws, tab_width))
382 	    return false;
383 	  /* Heuristic: only warn if the guard is the first thing
384 	     on its line.  */
385 	  if (guard_vis_column == guard_line_first_nws)
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
412 
413 	if (flag)
414 	  ;
415 	  foo ();
416 	  ^ DON'T WARN HERE
417 
418 	#define emit
419 	if (flag)
420 	     foo ();
421 	emit bar ();
422 	     ^ DON'T WARN HERE
423 
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;
430       unsigned int next_stmt_line_first_nws;
431       unsigned int body_vis_column;
432       unsigned int body_line_first_nws;
433       unsigned int guard_vis_column;
434       unsigned int guard_line_first_nws;
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.  */
439       if (!get_visual_column (next_stmt_exploc,
440 			      &next_stmt_vis_column,
441 			      &next_stmt_line_first_nws, tab_width))
442 	return false;
443       if (!get_visual_column (body_exploc,
444 			      &body_vis_column,
445 			      &body_line_first_nws, tab_width))
446 	return false;
447       if (!get_visual_column (guard_exploc,
448 			      &guard_vis_column,
449 			      &guard_line_first_nws, tab_width))
450 	return false;
451 
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 
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
477 	      && next_stmt_vis_column > guard_line_first_nws))
478 	{
479           /* Don't warn if they are aligned on the same column
480 	     as the guard itself (suggesting autogenerated code that doesn't
481 	     bother indenting at all).
482 	     For "else" clauses, we consider the column of the first
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 
501 	     If we just used the column of the "else" token, we would warn on
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.  */
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)
512 	    return false;
513 
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
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)
527 	    return false;
528 
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,
533 					   vis_column, tab_width))
534 	    return false;
535 
536 	  /* Otherwise, they are visually aligned: issue a warning.  */
537 	  return true;
538 	}
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 	      {
573 		if (next_stmt_vis_column > guard_line_first_nws
574 		    || (next_tok_type == CPP_OPEN_BRACE
575 			&& next_stmt_vis_column == guard_line_first_nws))
576 		  return true;
577 	      }
578 	  }
579     }
580 
581   return false;
582 }
583 
584 /* Return the string identifier corresponding to the given guard token.  */
585 
586 const char *
guard_tinfo_to_string(enum rid keyword)587 guard_tinfo_to_string (enum rid keyword)
588 {
589   switch (keyword)
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";
601     case RID_SWITCH:
602       return "switch";
603     default:
604       gcc_unreachable ();
605     }
606 }
607 
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 
634 void
warn_for_misleading_indentation(const token_indent_info & guard_tinfo,const token_indent_info & body_tinfo,const token_indent_info & next_tinfo)635 warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
636 				 const token_indent_info &body_tinfo,
637 				 const token_indent_info &next_tinfo)
638 {
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 
645   if (should_warn_for_misleading_indentation (guard_tinfo,
646 					      body_tinfo,
647 					      next_tinfo))
648     {
649       auto_diagnostic_group d;
650       if (warning_at (guard_tinfo.location, OPT_Wmisleading_indentation,
651 		      "this %qs clause does not guard...",
652 		      guard_tinfo_to_string (guard_tinfo.keyword)))
653 	inform (next_tinfo.location,
654 		"...this statement, but the latter is misleadingly indented"
655 		" as if it were guarded by the %qs",
656 		guard_tinfo_to_string (guard_tinfo.keyword));
657     }
658 }
659 
660 #if CHECKING_P
661 
662 namespace selftest {
663 
664 /* Verify that next_tab_stop works as expected.  */
665 
666 static void
test_next_tab_stop()667 test_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 
687 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)688 assert_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;
702   bool result = get_visual_column (exploc,
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 
727 static void
assert_get_visual_column_fails(const location & loc,const char * file,int line,int column,const unsigned int tab_width)728 assert_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;
740   bool result = get_visual_column (exploc,
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 
758 static void
test_get_visual_column()759 test_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 
806 void
c_indentation_c_tests()807 c_indentation_c_tests ()
808 {
809   test_next_tab_stop ();
810   test_get_visual_column ();
811 }
812 
813 } // namespace selftest
814 
815 #endif /* CHECKING_P */
816