summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2016-02-12 17:39:27 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2016-02-12 17:39:27 +0000
commit61789eedf831541b415691f7376a83fa81e6d73b (patch)
tree570dfb8c0732f310844f592f252d735a0da81372 /gcc
parentc3090c1f521bb5fedd5e7f977bce1bf0e1fc0a8e (diff)
PR driver/69265 and 69453: improved suggestions for various misspelled options
gcc/ChangeLog: PR driver/69265 PR driver/69453 * gcc.c (driver::driver): Initialize m_option_suggestions. (driver::~driver): Clean up m_option_suggestions. (suggest_option): Convert to... (driver::suggest_option): ...this, and split out into driver::build_option_suggestions and find_closest_string. (driver::build_option_suggestions): New function, from first half of suggest_option. Special-case OPT_fsanitize_ and OPT_fsanitize_recover_, making use of the sanitizer_opts array. For options of enum types, add the various enum values to the candidate strings. (driver::handle_unrecognized_options): Remove "const". * gcc.h (driver::handle_unrecognized_options): Likewise. (driver::build_option_suggestions): New decl. (driver::suggest_option): New decl. (driver::m_option_suggestions): New field. * opts-common.c (add_misspelling_candidates): New function. * opts.c (sanitizer_opts): Remove decl of struct sanitizer_opts_s and make non-static. * opts.h (sanitizer_opts): New array decl. (add_misspelling_candidates): New function decl. * spellcheck.c (find_closest_string): New function. * spellcheck.h (find_closest_string): New function decl. gcc/testsuite/ChangeLog: PR driver/69265 PR driver/69453 * gcc.dg/spellcheck-options-3.c: New test case. * gcc.dg/spellcheck-options-4.c: New test case. * gcc.dg/spellcheck-options-5.c: New test case. * gcc.dg/spellcheck-options-6.c: New test case. * gcc.dg/spellcheck-options-7.c: New test case. * gcc.dg/spellcheck-options-8.c: New test case. * gcc.dg/spellcheck-options-9.c: New test case. * gcc.dg/spellcheck-options-10.c: New test case. From-SVN: r233382
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog27
-rw-r--r--gcc/gcc.c112
-rw-r--r--gcc/gcc.h5
-rw-r--r--gcc/opts-common.c41
-rw-r--r--gcc/opts.c7
-rw-r--r--gcc/opts.h11
-rw-r--r--gcc/spellcheck.c46
-rw-r--r--gcc/spellcheck.h4
-rw-r--r--gcc/testsuite/ChangeLog13
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-10.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-3.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-4.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-5.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-6.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-7.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-8.c6
-rw-r--r--gcc/testsuite/gcc.dg/spellcheck-options-9.c6
17 files changed, 279 insertions, 35 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 871a2f076ee..729034caff4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,30 @@
+2016-02-12 David Malcolm <dmalcolm@redhat.com>
+
+ PR driver/69265
+ PR driver/69453
+ * gcc.c (driver::driver): Initialize m_option_suggestions.
+ (driver::~driver): Clean up m_option_suggestions.
+ (suggest_option): Convert to...
+ (driver::suggest_option): ...this, and split out into
+ driver::build_option_suggestions and find_closest_string.
+ (driver::build_option_suggestions): New function, from
+ first half of suggest_option. Special-case
+ OPT_fsanitize_ and OPT_fsanitize_recover_, making use of
+ the sanitizer_opts array. For options of enum types, add the
+ various enum values to the candidate strings.
+ (driver::handle_unrecognized_options): Remove "const".
+ * gcc.h (driver::handle_unrecognized_options): Likewise.
+ (driver::build_option_suggestions): New decl.
+ (driver::suggest_option): New decl.
+ (driver::m_option_suggestions): New field.
+ * opts-common.c (add_misspelling_candidates): New function.
+ * opts.c (sanitizer_opts): Remove decl of struct sanitizer_opts_s
+ and make non-static.
+ * opts.h (sanitizer_opts): New array decl.
+ (add_misspelling_candidates): New function decl.
+ * spellcheck.c (find_closest_string): New function.
+ * spellcheck.h (find_closest_string): New function decl.
+
2016-02-12 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/69764
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 683b30fcbab..99fa5e386a5 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -7135,7 +7135,8 @@ compare_files (char *cmpfile[])
driver::driver (bool can_finalize, bool debug) :
explicit_link_files (NULL),
- decoded_options (NULL)
+ decoded_options (NULL),
+ m_option_suggestions (NULL)
{
env.init (can_finalize, debug);
}
@@ -7144,6 +7145,14 @@ driver::~driver ()
{
XDELETEVEC (explicit_link_files);
XDELETEVEC (decoded_options);
+ if (m_option_suggestions)
+ {
+ int i;
+ char *str;
+ FOR_EACH_VEC_ELT (*m_option_suggestions, i, str)
+ free (str);
+ delete m_option_suggestions;
+ }
}
/* driver::main is implemented as a series of driver:: method calls. */
@@ -7632,49 +7641,96 @@ driver::maybe_putenv_OFFLOAD_TARGETS () const
offload_targets = NULL;
}
-/* Helper function for driver::handle_unrecognized_options.
+/* Helper function for driver::suggest_option. Populate
+ m_option_suggestions with candidate strings for misspelled options.
+ The strings will be freed by the driver's dtor. */
- 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)
+void
+driver::build_option_suggestions (void)
{
- const cl_option *best_option = NULL;
- edit_distance_t best_distance = MAX_EDIT_DISTANCE;
+ gcc_assert (m_option_suggestions == NULL);
+ m_option_suggestions = new auto_vec <char *> ();
+
+ /* We build a vec of m_option_suggestions, using add_misspelling_candidates
+ to add copies of strings, without a leading dash. */
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)
+ const struct cl_option *option = &cl_options[i];
+ const char *opt_text = option->opt_text;
+ switch (i)
{
- best_distance = dist;
- best_option = &cl_options[i];
+ default:
+ if (option->var_type == CLVC_ENUM)
+ {
+ const struct cl_enum *e = &cl_enums[option->var_enum];
+ for (unsigned j = 0; e->values[j].arg != NULL; j++)
+ {
+ char *with_arg = concat (opt_text, e->values[j].arg, NULL);
+ add_misspelling_candidates (m_option_suggestions, with_arg);
+ free (with_arg);
+ }
+ }
+ else
+ add_misspelling_candidates (m_option_suggestions, opt_text);
+ break;
+
+ case OPT_fsanitize_:
+ case OPT_fsanitize_recover_:
+ /* -fsanitize= and -fsanitize-recover= can take
+ a comma-separated list of arguments. Given that combinations
+ are supported, we can't add all potential candidates to the
+ vec, but if we at least add them individually without commas,
+ we should do a better job e.g. correcting
+ "-sanitize=address"
+ to
+ "-fsanitize=address"
+ rather than to "-Wframe-address" (PR driver/69265). */
+ {
+ for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
+ {
+ /* Get one arg at a time e.g. "-fsanitize=address". */
+ char *with_arg = concat (opt_text,
+ sanitizer_opts[j].name,
+ NULL);
+ /* Add with_arg and all of its variant spellings e.g.
+ "-fno-sanitize=address" to candidates (albeit without
+ leading dashes). */
+ add_misspelling_candidates (m_option_suggestions, with_arg);
+ free (with_arg);
+ }
+ }
+ break;
}
}
+}
- if (!best_option)
- return NULL;
+/* Helper function for driver::handle_unrecognized_options.
- /* 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;
- }
+ Given an unrecognized option BAD_OPT (without the leading dash),
+ locate the closest reasonable matching option (again, without the
+ leading dash), or NULL.
+
+ The returned string is owned by the driver instance. */
+
+const char *
+driver::suggest_option (const char *bad_opt)
+{
+ /* Lazily populate m_option_suggestions. */
+ if (!m_option_suggestions)
+ build_option_suggestions ();
+ gcc_assert (m_option_suggestions);
- return best_option->opt_text + 1;
+ /* "m_option_suggestions" is now populated. Use it. */
+ return find_closest_string
+ (bad_opt,
+ (auto_vec <const char *> *) m_option_suggestions);
}
/* Reject switches that no pass was interested in. */
void
-driver::handle_unrecognized_options () const
+driver::handle_unrecognized_options ()
{
for (size_t i = 0; (int) i < n_switches; i++)
if (! switches[i].validated)
diff --git a/gcc/gcc.h b/gcc/gcc.h
index 4fa0f4f2178..cb7081fc2df 100644
--- a/gcc/gcc.h
+++ b/gcc/gcc.h
@@ -45,7 +45,9 @@ class driver
void putenv_COLLECT_GCC (const char *argv0) const;
void maybe_putenv_COLLECT_LTO_WRAPPER () const;
void maybe_putenv_OFFLOAD_TARGETS () const;
- void handle_unrecognized_options () const;
+ void build_option_suggestions (void);
+ const char *suggest_option (const char *bad_opt);
+ void handle_unrecognized_options ();
int maybe_print_and_exit () const;
bool prepare_infiles ();
void do_spec_on_infiles () const;
@@ -57,6 +59,7 @@ class driver
char *explicit_link_files;
struct cl_decoded_option *decoded_options;
unsigned int decoded_options_count;
+ auto_vec <char *> *m_option_suggestions;
};
/* The mapping of a spec function name to the C function that
diff --git a/gcc/opts-common.c b/gcc/opts-common.c
index 38c805837d4..bb689827227 100644
--- a/gcc/opts-common.c
+++ b/gcc/opts-common.c
@@ -365,6 +365,47 @@ static const struct option_map option_map[] =
{ "--no-", NULL, "-f", false, true }
};
+/* Helper function for gcc.c's driver::suggest_option, for populating the
+ vec of suggestions for misspelled options.
+
+ option_map above provides various prefixes for spelling command-line
+ options, which decode_cmdline_option uses to map spellings of options
+ to specific options. We want to do the reverse: to find all the ways
+ that a user could validly spell an option.
+
+ Given valid OPT_TEXT (with a leading dash), add it and all of its valid
+ variant spellings to CANDIDATES, each without a leading dash.
+
+ For example, given "-Wabi-tag", the following are added to CANDIDATES:
+ "Wabi-tag"
+ "Wno-abi-tag"
+ "-warn-abi-tag"
+ "-warn-no-abi-tag".
+
+ The added strings must be freed using free. */
+
+void
+add_misspelling_candidates (auto_vec<char *> *candidates,
+ const char *opt_text)
+{
+ gcc_assert (candidates);
+ gcc_assert (opt_text);
+ candidates->safe_push (xstrdup (opt_text + 1));
+ for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++)
+ {
+ const char *opt0 = option_map[i].opt0;
+ const char *new_prefix = option_map[i].new_prefix;
+ size_t new_prefix_len = strlen (new_prefix);
+
+ if (strncmp (opt_text, new_prefix, new_prefix_len) == 0)
+ {
+ char *alternative = concat (opt0 + 1, opt_text + new_prefix_len,
+ NULL);
+ candidates->safe_push (alternative);
+ }
+ }
+}
+
/* Decode the switch beginning at ARGV for the language indicated by
LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into
the structure *DECODED. Returns the number of switches
diff --git a/gcc/opts.c b/gcc/opts.c
index 0a18c26d6e1..2f453122b09 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1434,12 +1434,7 @@ enable_fdo_optimizations (struct gcc_options *opts,
}
/* -f{,no-}sanitize{,-recover}= suboptions. */
-static const struct sanitizer_opts_s
-{
- const char *const name;
- unsigned int flag;
- size_t len;
-} sanitizer_opts[] =
+const struct sanitizer_opts_s sanitizer_opts[] =
{
#define SANITIZER_OPT(name, flags) { #name, flags, sizeof #name - 1 }
SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS),
diff --git a/gcc/opts.h b/gcc/opts.h
index 6e6dbead946..fa479d83da5 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -404,4 +404,15 @@ extern void set_struct_debug_option (struct gcc_options *opts,
const char *value);
extern bool opt_enum_arg_to_value (size_t opt_index, const char *arg,
int *value, unsigned int lang_mask);
+
+extern const struct sanitizer_opts_s
+{
+ const char *const name;
+ unsigned int flag;
+ size_t len;
+} sanitizer_opts[];
+
+extern void add_misspelling_candidates (auto_vec<char *> *candidates,
+ const char *base_option);
+
#endif
diff --git a/gcc/spellcheck.c b/gcc/spellcheck.c
index bf74015509d..e4e83a5ae16 100644
--- a/gcc/spellcheck.c
+++ b/gcc/spellcheck.c
@@ -119,3 +119,49 @@ levenshtein_distance (const char *s, const char *t)
{
return levenshtein_distance (s, strlen (s), t, strlen (t));
}
+
+/* Given TARGET, a non-NULL string, and CANDIDATES, a non-NULL ptr to
+ an autovec of non-NULL strings, determine which element within
+ CANDIDATES has the lowest edit distance to TARGET. If there are
+ multiple elements with the same minimal distance, the first in the
+ vector wins.
+
+ If more than half of the letters were misspelled, the suggestion is
+ likely to be meaningless, so return NULL for this case. */
+
+const char *
+find_closest_string (const char *target,
+ const auto_vec<const char *> *candidates)
+{
+ gcc_assert (target);
+ gcc_assert (candidates);
+
+ int i;
+ const char *candidate;
+ const char *best_candidate = NULL;
+ edit_distance_t best_distance = MAX_EDIT_DISTANCE;
+ size_t len_target = strlen (target);
+ FOR_EACH_VEC_ELT (*candidates, i, candidate)
+ {
+ gcc_assert (candidate);
+ edit_distance_t dist
+ = levenshtein_distance (target, len_target,
+ candidate, strlen (candidate));
+ if (dist < best_distance)
+ {
+ best_distance = dist;
+ best_candidate = candidate;
+ }
+ }
+
+ /* If more than half of the letters were misspelled, the suggestion is
+ likely to be meaningless. */
+ if (best_candidate)
+ {
+ unsigned int cutoff = MAX (len_target, strlen (best_candidate)) / 2;
+ if (best_distance > cutoff)
+ return NULL;
+ }
+
+ return best_candidate;
+}
diff --git a/gcc/spellcheck.h b/gcc/spellcheck.h
index 4c662a7c247..040c33ef571 100644
--- a/gcc/spellcheck.h
+++ b/gcc/spellcheck.h
@@ -31,6 +31,10 @@ levenshtein_distance (const char *s, int len_s,
extern edit_distance_t
levenshtein_distance (const char *s, const char *t);
+extern const char *
+find_closest_string (const char *target,
+ const auto_vec<const char *> *candidates);
+
/* spellcheck-tree.c */
extern edit_distance_t
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index dfae7fc6321..ffe2f2a2687 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,16 @@
+2016-02-12 David Malcolm <dmalcolm@redhat.com>
+
+ PR driver/69265
+ PR driver/69453
+ * gcc.dg/spellcheck-options-3.c: New test case.
+ * gcc.dg/spellcheck-options-4.c: New test case.
+ * gcc.dg/spellcheck-options-5.c: New test case.
+ * gcc.dg/spellcheck-options-6.c: New test case.
+ * gcc.dg/spellcheck-options-7.c: New test case.
+ * gcc.dg/spellcheck-options-8.c: New test case.
+ * gcc.dg/spellcheck-options-9.c: New test case.
+ * gcc.dg/spellcheck-options-10.c: New test case.
+
2016-02-12 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/69764
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-10.c b/gcc/testsuite/gcc.dg/spellcheck-options-10.c
new file mode 100644
index 00000000000..1957205593b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-10.c
@@ -0,0 +1,6 @@
+/* Verify that we include -Wno- variants when considering hints
+ for misspelled options (PR driver/69453). */
+
+/* { dg-do compile } */
+/* { dg-options "-fno-if-convert" } */
+/* { dg-error "unrecognized command line option .-fno-if-convert.; did you mean .-fno-if-conversion.?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-3.c b/gcc/testsuite/gcc.dg/spellcheck-options-3.c
new file mode 100644
index 00000000000..4133df9555e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-3.c
@@ -0,0 +1,6 @@
+/* Verify that we provide simple suggestions for the arguments of
+ "-fsanitize=" when it is misspelled (PR driver/69265). */
+
+/* { dg-do compile } */
+/* { dg-options "-sanitize=address" } */
+/* { dg-error "unrecognized command line option '-sanitize=address'; did you mean '-fsanitize=address'?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-4.c b/gcc/testsuite/gcc.dg/spellcheck-options-4.c
new file mode 100644
index 00000000000..252376fd757
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-4.c
@@ -0,0 +1,6 @@
+/* Verify that we provide simple suggestions for the arguments of
+ "-fsanitize-recover=" when it is misspelled (PR driver/69265). */
+
+/* { dg-do compile } */
+/* { dg-options "-sanitize-recover=integer-divide-by-0" } */
+/* { dg-error "unrecognized command line option '-sanitize-recover=integer-divide-by-0'; did you mean '-fsanitize-recover=integer-divide-by-zero'?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-5.c b/gcc/testsuite/gcc.dg/spellcheck-options-5.c
new file mode 100644
index 00000000000..9a02bb7afbb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-5.c
@@ -0,0 +1,6 @@
+/* Verify that we provide suggestions (with arguments) for the "-fno-"
+ variant of "-fsanitize=" when it is misspelled (PR driver/69265). */
+
+/* { dg-do compile } */
+/* { dg-options "-no-sanitize=all" } */
+/* { dg-error "unrecognized command line option '-no-sanitize=all'; did you mean '-fno-sanitize=all'?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-6.c b/gcc/testsuite/gcc.dg/spellcheck-options-6.c
new file mode 100644
index 00000000000..4d6bf0d945d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-6.c
@@ -0,0 +1,6 @@
+/* Verify that we can generate a suggestion of "--warn-no-abi-tag"
+ from c.opt's "Wabi-tag" (PR driver/69265). */
+
+/* { dg-do compile } */
+/* { dg-options "-fwarn-no-abi-tag" } */
+/* { dg-error "unrecognized command line option '-fwarn-no-abi-tag'; did you mean '--warn-no-abi-tag'?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-7.c b/gcc/testsuite/gcc.dg/spellcheck-options-7.c
new file mode 100644
index 00000000000..ca893994983
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-7.c
@@ -0,0 +1,6 @@
+/* Verify that we provide a hint if the user misspells an option that
+ takes an argument (PR driver/69265). */
+
+/* { dg-do compile } */
+/* { dg-options "-tls-model=global-dynamic" } */
+/* { dg-error "unrecognized command line option '-tls-model=global-dynamic'; did you mean '-ftls-model=global-dynamic'?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-8.c b/gcc/testsuite/gcc.dg/spellcheck-options-8.c
new file mode 100644
index 00000000000..2cc6c1ff1fe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-8.c
@@ -0,0 +1,6 @@
+/* Verify that we include -Wno- variants when considering hints
+ for misspelled options (PR driver/69453). */
+
+/* { dg-do compile } */
+/* { dg-options "--Wno-narrowing" } */
+/* { dg-error "unrecognized command line option '--Wno-narrowing'; did you mean '-Wno-narrowing'?" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-9.c b/gcc/testsuite/gcc.dg/spellcheck-options-9.c
new file mode 100644
index 00000000000..768b6f8c2a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-9.c
@@ -0,0 +1,6 @@
+/* Verify that we include -Wno- variants when considering hints
+ for misspelled options (PR driver/69453). */
+
+/* { dg-do compile } */
+/* { dg-options "-fmo-unroll-loops" } */
+/* { dg-error "unrecognized command line option '-fmo-unroll-loops'; did you mean '-fno-unroll-loops'?" "" { target *-*-* } 0 } */