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