Home | History | Annotate | Line # | Download | only in c-family
c-indentation.cc revision 1.1
      1 /* Implementation of -Wmisleading-indentation
      2    Copyright (C) 2015-2022 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
     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
     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
     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
    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
    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 *
    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
    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
    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
    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
    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
    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
    807 c_indentation_cc_tests ()
    808 {
    809   test_next_tab_stop ();
    810   test_get_visual_column ();
    811 }
    812 
    813 } // namespace selftest
    814 
    815 #endif /* CHECKING_P */
    816