aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-indentation.c
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@gcc.gnu.org>2015-08-02 17:39:23 +0000
committerPatrick Palka <ppalka@gcc.gnu.org>2015-08-02 17:39:23 +0000
commit8ebca419e837774146ef77574580456107d7315b (patch)
treebb853556afc05d1d755f8887612038504e3c912d /gcc/c-family/c-indentation.c
parent1a1e101ff50564a44dcd12522236f04caaa6dcab (diff)
downloadgcc-8ebca419e837774146ef77574580456107d7315b.zip
gcc-8ebca419e837774146ef77574580456107d7315b.tar.gz
gcc-8ebca419e837774146ef77574580456107d7315b.tar.bz2
Improve -Wmisleading-indentation heuristics
gcc/c-family/ChangeLog: * c-indentation.c (should_warn_for_misleading_indentation): Improve heuristics. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: Add more tests. From-SVN: r226479
Diffstat (limited to 'gcc/c-family/c-indentation.c')
-rw-r--r--gcc/c-family/c-indentation.c167
1 files changed, 147 insertions, 20 deletions
diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
index cdf0372..fdfe0a9 100644
--- a/gcc/c-family/c-indentation.c
+++ b/gcc/c-family/c-indentation.c
@@ -182,6 +182,7 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
location_t body_loc = body_tinfo.location;
location_t next_stmt_loc = next_tinfo.location;
+ enum cpp_ttype body_type = body_tinfo.type;
enum cpp_ttype next_tok_type = next_tinfo.type;
/* Don't attempt to compare the indentation of BODY_LOC and NEXT_STMT_LOC
@@ -227,12 +228,33 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
|| next_tinfo.keyword == RID_ELSE)
return false;
+ /* Likewise, if the body of the guard is a compound statement then control
+ flow is quite visually explicit regardless of the code's possibly poor
+ indentation, e.g.
+
+ while (foo) <- GUARD
+ { <- BODY
+ bar ();
+ }
+ baz (); <- NEXT
+
+ Things only get muddy when the body of the guard does not have
+ braces, e.g.
+
+ if (foo) <- GUARD
+ bar (); <- BODY
+ baz (); <- NEXT
+ */
+ if (body_type == CPP_OPEN_BRACE)
+ return false;
+
/* Don't warn here about spurious semicolons. */
if (next_tok_type == CPP_SEMICOLON)
return false;
expanded_location body_exploc = expand_location (body_loc);
expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
+ expanded_location guard_exploc = expand_location (guard_loc);
/* They must be in the same file. */
if (next_stmt_exploc.file != body_exploc.file)
@@ -250,13 +272,20 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
if (flag) foo (); bar ();
^ WARN HERE
+
+ if (flag) ; {
+ ^ WARN HERE
+
+ if (flag)
+ ; {
+ ^ WARN HERE
+
Cases where we don't want to issue a warning:
various_code (); if (flag) foo (); bar (); more_code ();
^ DON'T WARN HERE. */
if (next_stmt_exploc.line == body_exploc.line)
{
- expanded_location guard_exploc = expand_location (guard_loc);
if (guard_exploc.file != body_exploc.file)
return true;
if (guard_exploc.line < body_exploc.line)
@@ -304,14 +333,10 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
bar ();
^ DON'T WARN HERE
- if (flag) {
- foo ();
- } else
- {
- bar ();
- }
- baz ();
- ^ DON'T WARN HERE
+ if (flag)
+ ;
+ foo ();
+ ^ DON'T WARN HERE
*/
if (next_stmt_exploc.line > body_exploc.line)
{
@@ -319,29 +344,84 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
"visual column"... */
unsigned int next_stmt_vis_column;
unsigned int body_vis_column;
+ unsigned int body_line_first_nws;
/* If we can't determine it, don't issue a warning. This is sometimes
the case for input files containing #line directives, and these
are often for autogenerated sources (e.g. from .md files), where
it's not clear that it's meaningful to look at indentation. */
if (!get_visual_column (next_stmt_exploc, &next_stmt_vis_column))
return false;
- if (!get_visual_column (body_exploc, &body_vis_column))
+ if (!get_visual_column (body_exploc,
+ &body_vis_column,
+ &body_line_first_nws))
return false;
- if (next_stmt_vis_column == body_vis_column)
+ if ((body_type != CPP_SEMICOLON
+ && next_stmt_vis_column == body_vis_column)
+ /* As a special case handle the case where the body is a semicolon
+ that may be hidden by a preceding comment, e.g. */
+
+ // if (p)
+ // /* blah */;
+ // foo (1);
+
+ /* by looking instead at the column of the first non-whitespace
+ character on the body line. */
+ || (body_type == CPP_SEMICOLON
+ && body_exploc.line > guard_exploc.line
+ && body_line_first_nws != body_vis_column
+ && next_stmt_vis_column == body_line_first_nws))
{
- /* Don't warn if they aren't aligned on the same column
- as the guard itself (suggesting autogenerated code that
- doesn't bother indenting at all). */
- expanded_location guard_exploc = expand_location (guard_loc);
+ /* Don't warn if they are aligned on the same column
+ as the guard itself (suggesting autogenerated code that doesn't
+ bother indenting at all). We consider the column of the first
+ non-whitespace character on the guard line instead of the column
+ of the actual guard token itself because it is more sensible.
+ Consider:
+
+ if (p) {
+ foo (1);
+ } else // GUARD
+ foo (2); // BODY
+ foo (3); // NEXT
+
+ and:
+
+ if (p)
+ foo (1);
+ } else // GUARD
+ foo (2); // BODY
+ foo (3); // NEXT
+
+ If we just used the column of the guard token, we would warn on
+ the first example and not warn on the second. But we want the
+ exact opposite to happen: to not warn on the first example (which
+ is probably autogenerated) and to warn on the second (whose
+ indentation is misleading). Using the column of the first
+ non-whitespace character on the guard line makes that
+ happen. */
unsigned int guard_vis_column;
- if (!get_visual_column (guard_exploc, &guard_vis_column))
+ unsigned int guard_line_first_nws;
+ if (!get_visual_column (guard_exploc,
+ &guard_vis_column,
+ &guard_line_first_nws))
return false;
- if (guard_vis_column == body_vis_column)
+
+ if (guard_line_first_nws == body_vis_column)
return false;
- /* PR 66220: Don't warn if the guarding statement is more
- indented than the next/body stmts. */
- if (guard_vis_column > body_vis_column)
+ /* We may have something like:
+
+ if (p)
+ {
+ foo (1);
+ } else // GUARD
+ foo (2); // BODY
+ foo (3); // NEXT
+
+ in which case the columns are not aligned but the code is not
+ misleadingly indented. If the column of the body is less than
+ that of the guard line then don't warn. */
+ if (body_vis_column < guard_line_first_nws)
return false;
/* Don't warn if there is multiline preprocessor logic between
@@ -352,6 +432,53 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
/* Otherwise, they are visually aligned: issue a warning. */
return true;
}
+
+ /* Also issue a warning for code having the form:
+
+ if (flag);
+ foo ();
+
+ while (flag);
+ {
+ ...
+ }
+
+ for (...);
+ {
+ ...
+ }
+
+ if (flag)
+ ;
+ else if (flag);
+ foo ();
+
+ where the semicolon at the end of each guard is most likely spurious.
+
+ But do not warn on:
+
+ for (..);
+ foo ();
+
+ where the next statement is aligned with the guard.
+ */
+ if (body_type == CPP_SEMICOLON)
+ {
+ if (body_exploc.line == guard_exploc.line)
+ {
+ unsigned int guard_vis_column;
+ unsigned int guard_line_first_nws;
+ if (!get_visual_column (guard_exploc,
+ &guard_vis_column,
+ &guard_line_first_nws))
+ return false;
+
+ if (next_stmt_vis_column > guard_line_first_nws
+ || (next_tok_type == CPP_OPEN_BRACE
+ && next_stmt_vis_column == guard_vis_column))
+ return true;
+ }
+ }
}
return false;