PR driver/67613 - spell suggestions for misspelled command line options
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 13 Nov 2015 01:59:03 +0000 (01:59 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 13 Nov 2015 01:59:03 +0000 (01:59 +0000)
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

gcc/ChangeLog
gcc/Makefile.in
gcc/gcc.c
gcc/spellcheck-tree.c [new file with mode: 0644]
gcc/spellcheck.c
gcc/spellcheck.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/spellcheck-options-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/spellcheck-options-2.c [new file with mode: 0644]

index 1febdcf6febd9413369d7221c4b1ef0f2407e258..0c03eb0769e0780842d2b8900a3daefdf1fa8c29 100644 (file)
@@ -1,3 +1,20 @@
+2015-11-13  David Malcolm  <dmalcolm@redhat.com>
+
+       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  <dmalcolm@redhat.com>
 
        * Makefile.in (OBJS): Add spellcheck.o.
index f17234d78708ac65555c3bec1a4ec3c20e955f4e..21796f233ab9eac20b8c7788a8ef3bdb41cfdf6f 100644 (file)
@@ -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 \
index 87d19799266d09a00c32e27eb2cbc713c8765ed6..6fceca235529ee500de206f459e81ae5ef2a0a16 100644 (file)
--- 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"
 
 \f
 
@@ -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 (file)
index 0000000..d203776
--- /dev/null
@@ -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
+<http://www.gnu.org/licenses/>.  */
+
+#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));
+}
index 31ce32245461fed3772caa0dce6dd944479e4b0b..32854cf760eb08583cf4972a4252bd45395cdba9 100644 (file)
@@ -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));
-}
index 58355d60e92166188963f57ddbe2cec0eef19e28..673a75625109d7c282cec41a71aee714e7cbcfef 100644 (file)
@@ -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);
 
index 67299e015cdad0e0f035df228c66fd4ba931b72f..409020aaab9f5b5f21e7fb7f63c140aff67b1500 100644 (file)
@@ -1,3 +1,9 @@
+2015-11-13  David Malcolm  <dmalcolm@redhat.com>
+
+       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  <dmalcolm@redhat.com>
 
        * 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 (file)
index 0000000..cd5fdca
--- /dev/null
@@ -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 (file)
index 0000000..786266d
--- /dev/null
@@ -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 } */
+