aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.c
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2016-06-22 15:20:41 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2016-06-22 15:20:41 +0000
commit1a4f11c88ae761d4c618e540e07e4e32e85850d1 (patch)
tree6249c6a772dc9140476eee29b52cfe04dbe0e29d /gcc/c/c-parser.c
parent6f99ef82f1457d2f71121853ef2f006d0800bd19 (diff)
downloadgcc-1a4f11c88ae761d4c618e540e07e4e32e85850d1.zip
gcc-1a4f11c88ae761d4c618e540e07e4e32e85850d1.tar.gz
gcc-1a4f11c88ae761d4c618e540e07e4e32e85850d1.tar.bz2
C FE: suggest corrections for misspelled identifiers and type names
gcc/c-family/ChangeLog: PR c/70339 * c-common.h (enum lookup_name_fuzzy_kind): New enum. (lookup_name_fuzzy): New prototype. gcc/c/ChangeLog: PR c/70339 * c-decl.c: Include spellcheck-tree.h and gcc-rich-location.h. (implicit_decl_warning): When issuing warnings for implicit declarations, attempt to provide a suggestion via lookup_name_fuzzy. (undeclared_variable): Likewise when issuing errors. (lookup_name_in_scope): Likewise. (struct edit_distance_traits<cpp_hashnode *>): New struct. (best_macro_match): New typedef. (find_closest_macro_cpp_cb): New function. (lookup_name_fuzzy): New function. * c-parser.c: Include gcc-rich-location.h. (c_token_starts_typename): Split out case CPP_KEYWORD into... (c_keyword_starts_typename): ...this new function. (c_parser_declaration_or_fndef): When issuing errors about missing "struct" etc, add a fixit. For other kinds of errors, attempt to provide a suggestion via lookup_name_fuzzy. (c_parser_parms_declarator): When looking ahead to detect typos in type names, also reject CPP_KEYWORD. (c_parser_parameter_declaration): When issuing errors about unknown type names, attempt to provide a suggestion via lookup_name_fuzzy. * c-tree.h (c_keyword_starts_typename): New prototype. gcc/ChangeLog: PR c/70339 * diagnostic-core.h (pedwarn_at_rich_loc): New prototype. * diagnostic.c (pedwarn_at_rich_loc): New function. * spellcheck.h (best_match::best_match): Add a "best_distance_so_far" optional parameter. (best_match::set_best_so_far): New method. (best_match::get_best_distance): New accessor. (best_match::get_best_candidate_length): New accessor. gcc/testsuite/ChangeLog: PR c/70339 * c-c++-common/attributes-1.c: Update dg-prune-output to include hint. * gcc.dg/diagnostic-token-ranges.c (undeclared_identifier): Update expected results due to builtin "nanl" now being suggested for "name". * gcc.dg/pr67580.c: Update expected messages. * gcc.dg/spellcheck-identifiers.c: New testcase. * gcc.dg/spellcheck-typenames.c: New testcase. From-SVN: r237714
Diffstat (limited to 'gcc/c/c-parser.c')
-rw-r--r--gcc/c/c-parser.c144
1 files changed, 99 insertions, 45 deletions
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 78bf68e..7f491f1 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see
#include "c-family/c-indentation.h"
#include "gimple-expr.h"
#include "context.h"
+#include "gcc-rich-location.h"
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
@@ -518,6 +519,48 @@ c_parser_peek_nth_token (c_parser *parser, unsigned int n)
return &parser->tokens[n - 1];
}
+bool
+c_keyword_starts_typename (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPEOF:
+ case RID_CONST:
+ case RID_ATOMIC:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_AUTO_TYPE:
+ return true;
+ default:
+ if (keyword >= RID_FIRST_INT_N
+ && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
+ && int_n_enabled_p[keyword - RID_FIRST_INT_N])
+ return true;
+ return false;
+ }
+}
+
/* Return true if TOKEN can start a type name,
false otherwise. */
static bool
@@ -541,43 +584,7 @@ c_token_starts_typename (c_token *token)
gcc_unreachable ();
}
case CPP_KEYWORD:
- switch (token->keyword)
- {
- case RID_UNSIGNED:
- case RID_LONG:
- case RID_SHORT:
- case RID_SIGNED:
- case RID_COMPLEX:
- case RID_INT:
- case RID_CHAR:
- case RID_FLOAT:
- case RID_DOUBLE:
- case RID_VOID:
- case RID_DFLOAT32:
- case RID_DFLOAT64:
- case RID_DFLOAT128:
- case RID_BOOL:
- case RID_ENUM:
- case RID_STRUCT:
- case RID_UNION:
- case RID_TYPEOF:
- case RID_CONST:
- case RID_ATOMIC:
- case RID_VOLATILE:
- case RID_RESTRICT:
- case RID_ATTRIBUTE:
- case RID_FRACT:
- case RID_ACCUM:
- case RID_SAT:
- case RID_AUTO_TYPE:
- return true;
- default:
- if (token->keyword >= RID_FIRST_INT_N
- && token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
- && int_n_enabled_p[token->keyword - RID_FIRST_INT_N])
- return true;
- return false;
- }
+ return c_keyword_starts_typename (token->keyword);
case CPP_LESS:
if (c_dialect_objc ())
return true;
@@ -1655,15 +1662,50 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
&& (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
{
tree name = c_parser_peek_token (parser)->value;
- error_at (here, "unknown type name %qE", name);
- /* Give a hint to the user. This is not C++ with its implicit
- typedef. */
+
+ /* Issue a warning about NAME being an unknown type name, perhaps
+ with some kind of hint.
+ If the user forgot a "struct" etc, suggest inserting
+ it. Otherwise, attempt to look for misspellings. */
+ gcc_rich_location richloc (here);
if (tag_exists_p (RECORD_TYPE, name))
- inform (here, "use %<struct%> keyword to refer to the type");
+ {
+ /* This is not C++ with its implicit typedef. */
+ richloc.add_fixit_insert (here, "struct");
+ error_at_rich_loc (&richloc,
+ "unknown type name %qE;"
+ " use %<struct%> keyword to refer to the type",
+ name);
+ }
else if (tag_exists_p (UNION_TYPE, name))
- inform (here, "use %<union%> keyword to refer to the type");
+ {
+ richloc.add_fixit_insert (here, "union");
+ error_at_rich_loc (&richloc,
+ "unknown type name %qE;"
+ " use %<union%> keyword to refer to the type",
+ name);
+ }
else if (tag_exists_p (ENUMERAL_TYPE, name))
- inform (here, "use %<enum%> keyword to refer to the type");
+ {
+ richloc.add_fixit_insert (here, "enum");
+ error_at_rich_loc (&richloc,
+ "unknown type name %qE;"
+ " use %<enum%> keyword to refer to the type",
+ name);
+ }
+ else
+ {
+ tree hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME);
+ if (hint)
+ {
+ richloc.add_fixit_misspelled_id (here, hint);
+ error_at_rich_loc (&richloc,
+ "unknown type name %qE; did you mean %qE?",
+ name, hint);
+ }
+ else
+ error_at (here, "unknown type name %qE", name);
+ }
/* Parse declspecs normally to get a correct pointer type, but avoid
a further "fails to be a type name" error. Refuse nested functions
@@ -3632,7 +3674,8 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
&& c_parser_peek_2nd_token (parser)->type != CPP_NAME
&& c_parser_peek_2nd_token (parser)->type != CPP_MULT
&& c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
- && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE)
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE
+ && c_parser_peek_2nd_token (parser)->type != CPP_KEYWORD)
{
tree list = NULL_TREE, *nextp = &list;
while (c_parser_next_token_is (parser, CPP_NAME)
@@ -3807,7 +3850,18 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
c_parser_set_source_position_from_token (token);
if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
{
- error_at (token->location, "unknown type name %qE", token->value);
+ tree hint = lookup_name_fuzzy (token->value, FUZZY_LOOKUP_TYPENAME);
+ if (hint)
+ {
+ gcc_assert (TREE_CODE (hint) == IDENTIFIER_NODE);
+ gcc_rich_location richloc (token->location);
+ richloc.add_fixit_misspelled_id (token->location, hint);
+ error_at_rich_loc (&richloc,
+ "unknown type name %qE; did you mean %qE?",
+ token->value, hint);
+ }
+ else
+ error_at (token->location, "unknown type name %qE", token->value);
parser->error = true;
}
/* ??? In some Objective-C cases '...' isn't applicable so there