LCOV - code coverage report
Current view: top level - gcc/c-family - c-indentation.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 98.1 % 210 206
Test Date: 2025-09-20 13:40:47 Functions: 91.7 % 12 11
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

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

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.