Re: [PATCH] PR driver/67613 - spell suggestions for misspelled command line options

2015-11-06 Thread Bernd Schmidt

On 11/04/2015 03:53 PM, David Malcolm wrote:

This patch adds hints to the option-not-found error in the driver,
using the Levenshtein distance implementation posted here:
"[PATCH 0/2] Levenshtein-based suggestions (v3)"
   https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03379.html

It splits out the identifier-based implementation into a new
spellcheck-tree.c, keeping the core in spellcheck.c, since the tree
checking code needed for IDENTIFIER_POINTER etc isn't available in
the driver.


Nice. Ok.


Bernd


[PATCH] PR driver/67613 - spell suggestions for misspelled command line options

2015-11-04 Thread David Malcolm
This patch adds hints to the option-not-found error in the driver,
using the Levenshtein distance implementation posted here:
"[PATCH 0/2] Levenshtein-based suggestions (v3)"
  https://gcc.gnu.org/ml/gcc-patches/2015-10/msg03379.html

It splits out the identifier-based implementation into a new
spellcheck-tree.c, keeping the core in spellcheck.c, since the tree
checking code needed for IDENTIFIER_POINTER etc isn't available in
the driver.

Bootstrapped on top of the other patch kit (with nit fixes)
on x86_64-pc-linux-gnu; adds 5 PASS results to gcc.sum.

OK for trunk as a followup to that patch kit?

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.
---
 gcc/Makefile.in |  3 +-
 gcc/gcc.c   | 51 -
 gcc/spellcheck-tree.c   | 39 ++
 gcc/spellcheck.c| 21 ++--
 gcc/spellcheck.h|  4 +++
 gcc/testsuite/gcc.dg/spellcheck-options-1.c |  4 +++
 gcc/testsuite/gcc.dg/spellcheck-options-2.c |  5 +++
 7 files changed, 107 insertions(+), 20 deletions(-)
 create mode 100644 gcc/spellcheck-tree.c
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-1.c
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-2.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 9fb643e..a57bd40 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1151,7 +1151,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)
 
@@ -1395,6 +1395,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 bbc9b23..ef0fb4e 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"
 
 
 
@@ -7598,6 +7599,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 = _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
@@ -7605,7 +7645,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