diff options
Diffstat (limited to 'gcc/gcc.c')
-rw-r--r-- | gcc/gcc.c | 112 |
1 files changed, 84 insertions, 28 deletions
@@ -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) |