From: David Malcolm Date: Fri, 13 Nov 2015 01:59:03 +0000 (+0000) Subject: PR driver/67613 - spell suggestions for misspelled command line options X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=93ebf1fdbe35eadc5e54934061a7a4d7bcdc8262;p=gcc.git PR driver/67613 - spell suggestions for misspelled command line options gcc/ChangeLog: PR driver/67613 * Makefile.in (GCC_OBJS): Add spellcheck.o. (OBJS): Add spellcheck-tree.o. * gcc.c: Include "spellcheck.h". (suggest_option): New function. (driver::handle_unrecognized_options): Call suggest_option to provide a hint about misspelled options. * spellcheck.c: Update file comment. (levenshtein_distance): Convert 4-param implementation from static to extern scope. Remove note about unit tests from leading comment for const char * implementation. Move tree implementation to... * spellcheck-tree.c: New file. * spellcheck.h (levenshtein_distance): Add 4-param decl. gcc/testsuite/ChangeLog: PR driver/67613 * gcc/testsuite/gcc.dg/spellcheck-options-1.c: New file. * gcc/testsuite/gcc.dg/spellcheck-options-2.c: New file. From-SVN: r230285 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1febdcf6feb..0c03eb0769e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2015-11-13 David Malcolm + + PR driver/67613 + * Makefile.in (GCC_OBJS): Add spellcheck.o. + (OBJS): Add spellcheck-tree.o. + * gcc.c: Include "spellcheck.h". + (suggest_option): New function. + (driver::handle_unrecognized_options): Call suggest_option to + provide a hint about misspelled options. + * spellcheck.c: Update file comment. + (levenshtein_distance): Convert 4-param implementation from static + to extern scope. Remove note about unit tests from leading + comment for const char * implementation. Move tree + implementation to... + * spellcheck-tree.c: New file. + * spellcheck.h (levenshtein_distance): Add 4-param decl. + 2015-11-13 David Malcolm * Makefile.in (OBJS): Add spellcheck.o. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index f17234d7870..21796f233ab 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1158,7 +1158,7 @@ CXX_TARGET_OBJS=@cxx_target_objs@ FORTRAN_TARGET_OBJS=@fortran_target_objs@ # Object files for gcc many-languages driver. -GCC_OBJS = gcc.o gcc-main.o ggc-none.o +GCC_OBJS = gcc.o gcc-main.o ggc-none.o spellcheck.o c-family-warn = $(STRICT_WARN) @@ -1404,6 +1404,7 @@ OBJS = \ simplify-rtx.o \ sparseset.o \ spellcheck.o \ + spellcheck-tree.o \ sreal.o \ stack-ptr-mod.o \ statistics.o \ diff --git a/gcc/gcc.c b/gcc/gcc.c index 87d19799266..6fceca23552 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -42,6 +42,7 @@ compilation is specified by a string called a "spec". */ #include "opts.h" #include "params.h" #include "filenames.h" +#include "spellcheck.h" @@ -7601,6 +7602,45 @@ driver::maybe_putenv_OFFLOAD_TARGETS () const offload_targets = NULL; } +/* Helper function for driver::handle_unrecognized_options. + + Given an unrecognized option BAD_OPT (without the leading dash), + locate the closest reasonable matching option (again, without the + leading dash), or NULL. */ + +static const char * +suggest_option (const char *bad_opt) +{ + const cl_option *best_option = NULL; + edit_distance_t best_distance = MAX_EDIT_DISTANCE; + + for (unsigned int i = 0; i < cl_options_count; i++) + { + edit_distance_t dist = levenshtein_distance (bad_opt, + cl_options[i].opt_text + 1); + if (dist < best_distance) + { + best_distance = dist; + best_option = &cl_options[i]; + } + } + + if (!best_option) + return NULL; + + /* If more than half of the letters were misspelled, the suggestion is + likely to be meaningless. */ + if (best_option) + { + unsigned int cutoff = MAX (strlen (bad_opt), + strlen (best_option->opt_text + 1)) / 2; + if (best_distance > cutoff) + return NULL; + } + + return best_option->opt_text + 1; +} + /* Reject switches that no pass was interested in. */ void @@ -7608,7 +7648,16 @@ driver::handle_unrecognized_options () const { for (size_t i = 0; (int) i < n_switches; i++) if (! switches[i].validated) - error ("unrecognized command line option %<-%s%>", switches[i].part1); + { + const char *hint = suggest_option (switches[i].part1); + if (hint) + error ("unrecognized command line option %<-%s%>;" + " did you mean %<-%s%>?", + switches[i].part1, hint); + else + error ("unrecognized command line option %<-%s%>", + switches[i].part1); + } } /* Handle the various -print-* options, returning 0 if the driver diff --git a/gcc/spellcheck-tree.c b/gcc/spellcheck-tree.c new file mode 100644 index 00000000000..d2037766eca --- /dev/null +++ b/gcc/spellcheck-tree.c @@ -0,0 +1,39 @@ +/* Find near-matches for identifiers. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "spellcheck.h" + +/* Calculate Levenshtein distance between two identifiers. */ + +edit_distance_t +levenshtein_distance (tree ident_s, tree ident_t) +{ + gcc_assert (TREE_CODE (ident_s) == IDENTIFIER_NODE); + gcc_assert (TREE_CODE (ident_t) == IDENTIFIER_NODE); + + return levenshtein_distance (IDENTIFIER_POINTER (ident_s), + IDENTIFIER_LENGTH (ident_s), + IDENTIFIER_POINTER (ident_t), + IDENTIFIER_LENGTH (ident_t)); +} diff --git a/gcc/spellcheck.c b/gcc/spellcheck.c index 31ce3224546..32854cf760e 100644 --- a/gcc/spellcheck.c +++ b/gcc/spellcheck.c @@ -1,4 +1,4 @@ -/* Find near-matches for strings and identifiers. +/* Find near-matches for strings. Copyright (C) 2015 Free Software Foundation, Inc. This file is part of GCC. @@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see This implementation uses the Wagner-Fischer algorithm. */ -static edit_distance_t +edit_distance_t levenshtein_distance (const char *s, int len_s, const char *t, int len_t) { @@ -112,25 +112,10 @@ levenshtein_distance (const char *s, int len_s, return result; } -/* Calculate Levenshtein distance between two nil-terminated strings. - This exists purely for the unit tests. */ +/* Calculate Levenshtein distance between two nil-terminated strings. */ edit_distance_t levenshtein_distance (const char *s, const char *t) { return levenshtein_distance (s, strlen (s), t, strlen (t)); } - -/* Calculate Levenshtein distance between two identifiers. */ - -edit_distance_t -levenshtein_distance (tree ident_s, tree ident_t) -{ - gcc_assert (TREE_CODE (ident_s) == IDENTIFIER_NODE); - gcc_assert (TREE_CODE (ident_t) == IDENTIFIER_NODE); - - return levenshtein_distance (IDENTIFIER_POINTER (ident_s), - IDENTIFIER_LENGTH (ident_s), - IDENTIFIER_POINTER (ident_t), - IDENTIFIER_LENGTH (ident_t)); -} diff --git a/gcc/spellcheck.h b/gcc/spellcheck.h index 58355d60e92..673a7562510 100644 --- a/gcc/spellcheck.h +++ b/gcc/spellcheck.h @@ -23,6 +23,10 @@ along with GCC; see the file COPYING3. If not see typedef unsigned int edit_distance_t; const edit_distance_t MAX_EDIT_DISTANCE = UINT_MAX; +extern edit_distance_t +levenshtein_distance (const char *s, int len_s, + const char *t, int len_t); + extern edit_distance_t levenshtein_distance (const char *s, const char *t); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 67299e015cd..409020aaab9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2015-11-13 David Malcolm + + PR driver/67613 + * gcc/testsuite/gcc.dg/spellcheck-options-1.c: New file. + * gcc/testsuite/gcc.dg/spellcheck-options-2.c: New file. + 2015-11-13 David Malcolm * gcc.dg/plugin/levenshtein-test-1.c: New file. diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-1.c b/gcc/testsuite/gcc.dg/spellcheck-options-1.c new file mode 100644 index 00000000000..cd5fdcacfdb --- /dev/null +++ b/gcc/testsuite/gcc.dg/spellcheck-options-1.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-Wcoercion" } */ +/* { dg-error "unrecognized command line option '-Wcoercion'; did you mean '-Wconversion'?" "" { target *-*-* } 0 } */ + diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-2.c b/gcc/testsuite/gcc.dg/spellcheck-options-2.c new file mode 100644 index 00000000000..786266df390 --- /dev/null +++ b/gcc/testsuite/gcc.dg/spellcheck-options-2.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-Wthis-should-not-get-a-hint" } */ +/* { dg-bogus "did you mean" "" { target *-*-* } 0 } */ +/* { dg-error "unrecognized command line option '-Wthis-should-not-get-a-hint'" "" { target *-*-* } 0 } */ +