gcc/gcc/c-family/c-indentation.c

435 lines
12 KiB
C
Raw Normal View History

Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
/* Implementation of -Wmisleading-indentation
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "alias.h"
#include "tree.h"
#include "stringpool.h"
#include "stor-layout.h"
#include "c-common.h"
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
#include "c-indentation.h"
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
extern cpp_options *cpp_opts;
/* Convert libcpp's notion of a column (a 1-based char count) to
the "visual column" (0-based column, respecting tabs), by reading the
relevant line.
Returns true if a conversion was possible, writing the result to OUT,
otherwise returns false. */
static bool
get_visual_column (expanded_location exploc, unsigned int *out)
{
int line_len;
const char *line = location_get_source_line (exploc, &line_len);
if (!line)
return false;
unsigned int vis_column = 0;
for (int i = 1; i < exploc.column; i++)
{
unsigned char ch = line[i - 1];
if (ch == '\t')
{
/* Round up to nearest tab stop. */
const unsigned int tab_width = cpp_opts->tabstop;
vis_column = ((vis_column + tab_width) / tab_width) * tab_width;
}
else
vis_column++;
}
*out = vis_column;
return true;
}
/* Is the token at LOC the first non-whitespace on its line?
Helper function for should_warn_for_misleading_indentation. */
static bool
is_first_nonwhitespace_on_line (expanded_location exploc)
{
int line_len;
const char *line = location_get_source_line (exploc, &line_len);
/* If we can't determine it, return false so that we 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 (!line)
return false;
for (int i = 1; i < exploc.column; i++)
{
unsigned char ch = line[i - 1];
if (!ISSPACE (ch))
return false;
}
return true;
}
/* Does the given source line appear to contain a #if directive?
(or #ifdef/#ifndef). Ignore the possibility of it being inside a
comment, for simplicity.
Helper function for detect_preprocessor_logic. */
static bool
line_contains_hash_if (const char *file, int line_num)
{
expanded_location exploc;
exploc.file = file;
exploc.line = line_num;
exploc.column = 1;
int line_len;
const char *line = location_get_source_line (exploc, &line_len);
if (!line)
return false;
int idx;
/* Skip leading whitespace. */
for (idx = 0; idx < line_len; idx++)
if (!ISSPACE (line[idx]))
break;
if (idx == line_len)
return false;
/* Require a '#' character. */
if (line[idx] != '#')
return false;
idx++;
/* Skip whitespace. */
while (idx < line_len)
{
if (!ISSPACE (line[idx]))
break;
idx++;
}
/* Match #if/#ifdef/#ifndef. */
if (idx + 2 <= line_len)
if (line[idx] == 'i')
if (line[idx + 1] == 'f')
return true;
return false;
}
/* Determine if there is preprocessor logic between
BODY_EXPLOC and NEXT_STMT_EXPLOC, to ensure that we don't
issue a warning for cases like this:
if (flagA)
foo ();
^ BODY_EXPLOC
#if SOME_CONDITION_THAT_DOES_NOT_HOLD
if (flagB)
#endif
bar ();
^ NEXT_STMT_EXPLOC
despite "bar ();" being visually aligned below "foo ();" and
being (as far as the parser sees) the next token.
Return true if such logic is detected. */
static bool
detect_preprocessor_logic (expanded_location body_exploc,
expanded_location next_stmt_exploc)
{
gcc_assert (next_stmt_exploc.file == body_exploc.file);
gcc_assert (next_stmt_exploc.line > body_exploc.line);
if (next_stmt_exploc.line - body_exploc.line < 4)
return false;
/* Is there a #if/#ifdef/#ifndef directive somewhere in the lines
between the given locations?
This is something of a layering violation, but by necessity,
given the nature of what we're testing for. For example,
in theory we could be fooled by a #if within a comment, but
it's unlikely to matter. */
for (int line = body_exploc.line + 1; line < next_stmt_exploc.line; line++)
if (line_contains_hash_if (body_exploc.file, line))
return true;
/* Not found. */
return false;
}
/* Helper function for warn_for_misleading_indentation; see
description of that function below. */
static bool
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
const token_indent_info &body_tinfo,
const token_indent_info &next_tinfo)
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
{
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
location_t guard_loc = guard_tinfo.location;
location_t body_loc = body_tinfo.location;
location_t next_stmt_loc = next_tinfo.location;
enum cpp_ttype next_tok_type = next_tinfo.type;
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
/* Don't attempt to compare the indentation of BODY_LOC and NEXT_STMT_LOC
if either are within macros. */
if (linemap_location_from_macro_expansion_p (line_table, body_loc)
|| linemap_location_from_macro_expansion_p (line_table, next_stmt_loc))
return false;
/* Don't attempt to compare indentation if #line or # 44 "file"-style
directives are present, suggesting generated code.
All bets are off if these are present: the file that the #line
directive could have an entirely different coding layout to C/C++
(e.g. .md files).
To determine if a #line is present, in theory we could look for a
map with reason == LC_RENAME_VERBATIM. However, if there has
subsequently been a long line requiring a column number larger than
that representable by the original LC_RENAME_VERBATIM map, then
we'll have a map with reason LC_RENAME.
Rather than attempting to search all of the maps for a
LC_RENAME_VERBATIM, instead we have libcpp set a flag whenever one
is seen, and we check for the flag here.
*/
if (line_table->seen_line_directive)
return false;
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
/* If the token following the body is a close brace or an "else"
then while indentation may be sloppy, there is not much ambiguity
about control flow, e.g.
if (foo) <- GUARD
bar (); <- BODY
else baz (); <- NEXT
{
while (foo) <- GUARD
bar (); <- BODY
} <- NEXT
baz ();
*/
if (next_tok_type == CPP_CLOSE_BRACE
|| next_tinfo.keyword == RID_ELSE)
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
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);
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
/* They must be in the same file. */
if (next_stmt_exploc.file != body_exploc.file)
return false;
/* If NEXT_STMT_LOC and BODY_LOC are on the same line, consider
the location of the guard.
Cases where we want to issue a warning:
if (flag)
foo (); bar ();
^ WARN HERE
if (flag) foo (); bar ();
^ 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);
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
if (guard_exploc.file != body_exploc.file)
return true;
if (guard_exploc.line < body_exploc.line)
/* The guard is on a line before a line that contains both
the body and the next stmt. */
return true;
else if (guard_exploc.line == body_exploc.line)
{
/* They're all on the same line. */
gcc_assert (guard_exploc.file == next_stmt_exploc.file);
gcc_assert (guard_exploc.line == next_stmt_exploc.line);
/* Heuristic: only warn if the guard is the first thing
on its line. */
if (is_first_nonwhitespace_on_line (guard_exploc))
return true;
}
}
/* If NEXT_STMT_LOC is on a line after BODY_LOC, consider
their relative locations, and of the guard.
Cases where we want to issue a warning:
if (flag)
foo ();
bar ();
^ WARN HERE
Cases where we don't want to issue a warning:
if (flag)
foo ();
bar ();
^ DON'T WARN HERE (autogenerated code?)
if (flagA)
foo ();
#if SOME_CONDITION_THAT_DOES_NOT_HOLD
if (flagB)
#endif
bar ();
^ DON'T WARN HERE
if (flag) {
foo ();
} else
{
bar ();
}
baz ();
^ DON'T WARN HERE
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
*/
if (next_stmt_exploc.line > body_exploc.line)
{
/* Determine if GUARD_LOC and NEXT_STMT_LOC are aligned on the same
"visual column"... */
unsigned int next_stmt_vis_column;
unsigned int body_vis_column;
/* 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))
return false;
if (next_stmt_vis_column == body_vis_column)
{
/* 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);
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
unsigned int guard_vis_column;
if (!get_visual_column (guard_exploc, &guard_vis_column))
return false;
if (guard_vis_column == 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)
return false;
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
/* Don't warn if there is multiline preprocessor logic between
the two statements. */
if (detect_preprocessor_logic (body_exploc, next_stmt_exploc))
return false;
/* Otherwise, they are visually aligned: issue a warning. */
return true;
}
}
return false;
}
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
/* Return the string identifier corresponding to the given guard token. */
static const char *
guard_tinfo_to_string (const token_indent_info &guard_tinfo)
{
switch (guard_tinfo.keyword)
{
case RID_FOR:
return "for";
case RID_ELSE:
return "else";
case RID_IF:
return "if";
case RID_WHILE:
return "while";
case RID_DO:
return "do";
default:
gcc_unreachable ();
}
}
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
/* Called by the C/C++ frontends when we have a guarding statement at
GUARD_LOC containing a statement at BODY_LOC, where the block wasn't
written using braces, like this:
if (flag)
foo ();
along with the location of the next token, at NEXT_STMT_LOC,
so that we can detect followup statements that are within
the same "visual block" as the guarded statement, but which
aren't logically grouped within the guarding statement, such
as:
GUARD_LOC
|
V
if (flag)
foo (); <- BODY_LOC
bar (); <- NEXT_STMT_LOC
In the above, "bar ();" isn't guarded by the "if", but
is indented to misleadingly suggest that it is in the same
block as "foo ();".
GUARD_KIND identifies the kind of clause e.g. "if", "else" etc. */
void
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
const token_indent_info &body_tinfo,
const token_indent_info &next_tinfo)
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
{
/* Early reject for the case where -Wmisleading-indentation is disabled,
to avoid doing work only to have the warning suppressed inside the
diagnostic machinery. */
if (!warn_misleading_indentation)
return;
Refactor entry point to -Wmisleading-indentation gcc/c-family/ChangeLog: * c-indentation.h (struct token_indent_info): Define. (get_token_indent_info): Define. (warn_for_misleading_information): Declare. * c-common.h (warn_for_misleading_information): Remove. * c-identation.c (warn_for_misleading_indentation): Change declaration to take three token_indent_infos. Adjust accordingly. * c-identation.c (should_warn_for_misleading_indentation): Likewise. Bail out early if the body is a compound statement. (guard_tinfo_to_string): Define. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Take token_indent_info argument. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. (c_parser_else_body): Likewise. (c_parser_if_statement): Likewise. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Move handling of semicolon body to ... (cp_parser_implicitly_scoped_statement): .. here. Call warn_for_misleading_indentation even when the body is a semicolon. Extract token_indent_infos corresponding to the guard, body and next tokens. Adjust call to warn_for_misleading_indentation accordingly. Take token_indent_info argument. (cp_parser_already_scoped_statement): Likewise. (cp_parser_selection_statement, cp_parser_iteration_statement): Extract a token_indent_info corresponding to the guard token. From-SVN: r226477
2015-08-02 19:31:55 +02:00
if (should_warn_for_misleading_indentation (guard_tinfo,
body_tinfo,
next_tinfo))
{
if (warning_at (next_tinfo.location, OPT_Wmisleading_indentation,
"statement is indented as if it were guarded by..."))
inform (guard_tinfo.location,
"...this %qs clause, but it is not",
guard_tinfo_to_string (guard_tinfo));
}
Implement -Wmisleading-indentation gcc/ChangeLog: * doc/invoke.texi (Warning Options): Add -Wmisleading-indentation. (-Wmisleading-indentation): New option. * Makefile.in (C_COMMON_OBJS): Add c-family/c-indentation.o. gcc/c-family/ChangeLog: * c-common.h (warn_for_misleading_indentation): New prototype. * c-indentation.c: New file. * c.opt (Wmisleading-indentation): New option. gcc/c/ChangeLog: * c-parser.c (c_parser_if_body): Add param "if_loc", use it to add a call to warn_for_misleading_indentation. (c_parser_else_body): Likewise, adding param "else_loc". (c_parser_if_statement): Check for misleading indentation. (c_parser_while_statement): Likewise. (c_parser_for_statement): Likewise. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Add location and guard_kind arguments to calls to cp_parser_implicitly_scoped_statement. (cp_parser_iteration_statement): Likewise for calls to cp_parser_already_scoped_statement. (cp_parser_implicitly_scoped_statement): Add "guard_loc" and "guard_kind" params; use them to warn for misleading indentation. (cp_parser_already_scoped_statement): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wmisleading-indentation.c: New testcase. * c-c++-common/Wmisleading-indentation-2.c: New testcase. * c-c++-common/Wmisleading-indentation-2.md: New file. libcpp/ChangeLog: * directives.c (do_line): Set seen_line_directive on line_table. (do_linemarker): Likewise. * include/line-map.h (struct line_maps): Add new field "seen_line_directive". From-SVN: r223098
2015-05-12 22:57:38 +02:00
}