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

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.