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: 2026-02-28 14:20:25 Functions: 100.0 % 12 12
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-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.