8cc5fcaf1f
2019-11-12 Martin Liska <mliska@suse.cz> * common.opt: Remove param_values. * config/i386/i386-options.c (ix86_valid_target_attribute_p): Remove finalize_options_struct. * gcc.c (driver::decode_argv): Do not call global_init_params and finish_params. (driver::finalize): Do not call params_c_finalize and finalize_options_struct. * opt-suggestions.c (option_proposer::get_completions): Remove special casing of params. (option_proposer::find_param_completions): Remove. (test_completion_partial_match): Update expected output. * opt-suggestions.h: Remove find_param_completions. * opts-common.c (add_misspelling_candidates): Add --param with a space. * opts.c (handle_param): Remove. (init_options_struct):. Remove init_options_struct and similar calls. (finalize_options_struct): Remove. (common_handle_option): Use SET_OPTION_IF_UNSET. * opts.h (finalize_options_struct): Remove. * toplev.c (general_init): Do not call global_init_params. (toplev::finalize): Do not call params_c_finalize and finalize_options_struct. From-SVN: r278087
412 lines
12 KiB
C
412 lines
12 KiB
C
/* Provide option suggestion for --complete option and a misspelled
|
|
used by a user.
|
|
Copyright (C) 2016-2019 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 "opts.h"
|
|
#include "spellcheck.h"
|
|
#include "opt-suggestions.h"
|
|
#include "common/common-target.h"
|
|
#include "selftest.h"
|
|
|
|
option_proposer::~option_proposer ()
|
|
{
|
|
delete m_option_suggestions;
|
|
}
|
|
|
|
const char *
|
|
option_proposer::suggest_option (const char *bad_opt)
|
|
{
|
|
/* Lazily populate m_option_suggestions. */
|
|
if (!m_option_suggestions)
|
|
build_option_suggestions (NULL);
|
|
gcc_assert (m_option_suggestions);
|
|
|
|
/* "m_option_suggestions" is now populated. Use it. */
|
|
return find_closest_string
|
|
(bad_opt,
|
|
(auto_vec <const char *> *) m_option_suggestions);
|
|
}
|
|
|
|
/* Populate RESULTS with valid completions of options that begin
|
|
with OPTION_PREFIX. */
|
|
|
|
void
|
|
option_proposer::get_completions (const char *option_prefix,
|
|
auto_string_vec &results)
|
|
{
|
|
/* Bail out for an invalid input. */
|
|
if (option_prefix == NULL || option_prefix[0] == '\0')
|
|
return;
|
|
|
|
/* Option suggestions are built without first leading dash character. */
|
|
if (option_prefix[0] == '-')
|
|
option_prefix++;
|
|
|
|
size_t length = strlen (option_prefix);
|
|
|
|
/* Lazily populate m_option_suggestions. */
|
|
if (!m_option_suggestions)
|
|
build_option_suggestions (option_prefix);
|
|
gcc_assert (m_option_suggestions);
|
|
|
|
for (unsigned i = 0; i < m_option_suggestions->length (); i++)
|
|
{
|
|
char *candidate = (*m_option_suggestions)[i];
|
|
if (strlen (candidate) >= length
|
|
&& strstr (candidate, option_prefix) == candidate)
|
|
results.safe_push (concat ("-", candidate, NULL));
|
|
}
|
|
}
|
|
|
|
/* Print on stdout a list of valid options that begin with OPTION_PREFIX,
|
|
one per line, suitable for use by Bash completion.
|
|
|
|
Implementation of the "-completion=" option. */
|
|
|
|
void
|
|
option_proposer::suggest_completion (const char *option_prefix)
|
|
{
|
|
auto_string_vec results;
|
|
get_completions (option_prefix, results);
|
|
for (unsigned i = 0; i < results.length (); i++)
|
|
printf ("%s\n", results[i]);
|
|
}
|
|
|
|
void
|
|
option_proposer::build_option_suggestions (const char *prefix)
|
|
{
|
|
gcc_assert (m_option_suggestions == NULL);
|
|
m_option_suggestions = new auto_string_vec ();
|
|
|
|
/* 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++)
|
|
{
|
|
const struct cl_option *option = &cl_options[i];
|
|
const char *opt_text = option->opt_text;
|
|
switch (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, option,
|
|
with_arg);
|
|
free (with_arg);
|
|
}
|
|
|
|
/* Add also variant without an option argument. */
|
|
add_misspelling_candidates (m_option_suggestions, option,
|
|
opt_text);
|
|
}
|
|
else
|
|
{
|
|
bool option_added = false;
|
|
if (option->flags & CL_TARGET)
|
|
{
|
|
vec<const char *> option_values
|
|
= targetm_common.get_valid_option_values (i, prefix);
|
|
if (!option_values.is_empty ())
|
|
{
|
|
option_added = true;
|
|
for (unsigned j = 0; j < option_values.length (); j++)
|
|
{
|
|
char *with_arg = concat (opt_text, option_values[j],
|
|
NULL);
|
|
add_misspelling_candidates (m_option_suggestions, option,
|
|
with_arg);
|
|
free (with_arg);
|
|
}
|
|
}
|
|
option_values.release ();
|
|
}
|
|
|
|
if (!option_added)
|
|
add_misspelling_candidates (m_option_suggestions, option,
|
|
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). */
|
|
{
|
|
/* Add also variant without an option argument. */
|
|
add_misspelling_candidates (m_option_suggestions, option,
|
|
opt_text);
|
|
|
|
for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
|
|
{
|
|
struct cl_option optb;
|
|
/* -fsanitize=all is not valid, only -fno-sanitize=all.
|
|
So don't register the positive misspelling candidates
|
|
for it. */
|
|
if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
|
|
{
|
|
optb = *option;
|
|
optb.opt_text = opt_text = "-fno-sanitize=";
|
|
optb.cl_reject_negative = true;
|
|
option = &optb;
|
|
}
|
|
/* 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, option,
|
|
with_arg);
|
|
free (with_arg);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if CHECKING_P
|
|
|
|
namespace selftest {
|
|
|
|
/* Verify that PROPOSER generates sane auto-completion suggestions
|
|
for OPTION_PREFIX. */
|
|
|
|
static void
|
|
verify_autocompletions (option_proposer &proposer, const char *option_prefix)
|
|
{
|
|
auto_string_vec suggestions;
|
|
proposer.get_completions (option_prefix, suggestions);
|
|
|
|
/* There must be at least one suggestion, and every suggestion must
|
|
indeed begin with OPTION_PREFIX. */
|
|
|
|
ASSERT_GT (suggestions.length (), 0);
|
|
|
|
for (unsigned i = 0; i < suggestions.length (); i++)
|
|
ASSERT_STR_STARTSWITH (suggestions[i], option_prefix);
|
|
}
|
|
|
|
/* Verify that valid options are auto-completed correctly. */
|
|
|
|
static void
|
|
test_completion_valid_options (option_proposer &proposer)
|
|
{
|
|
const char *option_prefixes[] =
|
|
{
|
|
"-fno-var-tracking-assignments-toggle",
|
|
"-fpredictive-commoning",
|
|
"--param=stack-clash-protection-guard-size",
|
|
"--param=max-predicted-iterations",
|
|
"-ftree-loop-distribute-patterns",
|
|
"-fno-var-tracking",
|
|
"-Walloc-zero",
|
|
"--param=ipa-cp-value-list-size",
|
|
"-Wsync-nand",
|
|
"-Wno-attributes",
|
|
"--param=tracer-dynamic-coverage-feedback",
|
|
"-Wno-format-contains-nul",
|
|
"-Wnamespaces",
|
|
"-fisolate-erroneous-paths-attribute",
|
|
"-Wno-underflow",
|
|
"-Wtarget-lifetime",
|
|
"--param=asan-globals",
|
|
"-Wno-empty-body",
|
|
"-Wno-odr",
|
|
"-Wformat-zero-length",
|
|
"-Wstringop-truncation",
|
|
"-fno-ipa-vrp",
|
|
"-fmath-errno",
|
|
"-Warray-temporaries",
|
|
"-Wno-unused-label",
|
|
"-Wreturn-local-addr",
|
|
"--param=sms-dfa-history",
|
|
"--param=asan-instrument-reads",
|
|
"-Wreturn-type",
|
|
"-Wc++17-compat",
|
|
"-Wno-effc++",
|
|
"--param=max-fields-for-field-sensitive",
|
|
"-fisolate-erroneous-paths-dereference",
|
|
"-fno-defer-pop",
|
|
"-Wcast-align=strict",
|
|
"-foptimize-strlen",
|
|
"-Wpacked-not-aligned",
|
|
"-funroll-loops",
|
|
"-fif-conversion2",
|
|
"-Wdesignated-init",
|
|
"--param=max-iterations-computation-cost",
|
|
"-Wmultiple-inheritance",
|
|
"-fno-sel-sched-reschedule-pipelined",
|
|
"-Wassign-intercept",
|
|
"-Wno-format-security",
|
|
"-fno-sched-stalled-insns",
|
|
"-fno-tree-tail-merge",
|
|
"-Wlong-long",
|
|
"-Wno-unused-but-set-parameter",
|
|
NULL
|
|
};
|
|
|
|
for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
|
|
verify_autocompletions (proposer, *ptr);
|
|
}
|
|
|
|
/* Verify that valid parameters are auto-completed correctly,
|
|
both with the "--param=PARAM" form and the "--param PARAM" form. */
|
|
|
|
static void
|
|
test_completion_valid_params (option_proposer &proposer)
|
|
{
|
|
const char *option_prefixes[] =
|
|
{
|
|
"--param=sched-state-edge-prob-cutoff",
|
|
"--param=iv-consider-all-candidates-bound",
|
|
"--param=align-threshold",
|
|
"--param=prefetch-min-insn-to-mem-ratio",
|
|
"--param=max-unrolled-insns",
|
|
"--param=max-early-inliner-iterations",
|
|
"--param=max-vartrack-reverse-op-size",
|
|
"--param=ipa-cp-loop-hint-bonus",
|
|
"--param=tracer-min-branch-ratio",
|
|
"--param=graphite-max-arrays-per-scop",
|
|
"--param=sink-frequency-threshold",
|
|
"--param=max-cse-path-length",
|
|
"--param=sra-max-scalarization-size-Osize",
|
|
"--param=prefetch-latency",
|
|
"--param=dse-max-object-size",
|
|
"--param=asan-globals",
|
|
"--param=max-vartrack-size",
|
|
"--param=case-values-threshold",
|
|
"--param=max-slsr-cand-scan",
|
|
"--param=min-insn-to-prefetch-ratio",
|
|
"--param=tracer-min-branch-probability",
|
|
"--param sink-frequency-threshold",
|
|
"--param max-cse-path-length",
|
|
"--param sra-max-scalarization-size-Osize",
|
|
"--param prefetch-latency",
|
|
"--param dse-max-object-size",
|
|
"--param asan-globals",
|
|
"--param max-vartrack-size",
|
|
NULL
|
|
};
|
|
|
|
for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
|
|
verify_autocompletions (proposer, *ptr);
|
|
}
|
|
|
|
/* Return true when EXPECTED is one of completions for OPTION_PREFIX string. */
|
|
|
|
static bool
|
|
in_completion_p (option_proposer &proposer, const char *option_prefix,
|
|
const char *expected)
|
|
{
|
|
auto_string_vec suggestions;
|
|
proposer.get_completions (option_prefix, suggestions);
|
|
|
|
for (unsigned i = 0; i < suggestions.length (); i++)
|
|
{
|
|
char *r = suggestions[i];
|
|
if (strcmp (r, expected) == 0)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Return true when PROPOSER does not find any partial completion
|
|
for OPTION_PREFIX. */
|
|
|
|
static bool
|
|
empty_completion_p (option_proposer &proposer, const char *option_prefix)
|
|
{
|
|
auto_string_vec suggestions;
|
|
proposer.get_completions (option_prefix, suggestions);
|
|
return suggestions.is_empty ();
|
|
}
|
|
|
|
/* Verify autocompletions of partially-complete options. */
|
|
|
|
static void
|
|
test_completion_partial_match (option_proposer &proposer)
|
|
{
|
|
ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
|
|
ASSERT_TRUE (in_completion_p (proposer, "-fsani",
|
|
"-fsanitize-address-use-after-scope"));
|
|
ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
|
|
ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
|
|
ASSERT_TRUE (in_completion_p (proposer, "--param=",
|
|
"--param=max-vartrack-reverse-op-size="));
|
|
ASSERT_TRUE (in_completion_p (proposer, "--param ",
|
|
"--param max-vartrack-reverse-op-size="));
|
|
|
|
ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
|
|
ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
|
|
|
|
ASSERT_FALSE (empty_completion_p (proposer, "-"));
|
|
ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
|
|
ASSERT_FALSE (empty_completion_p (proposer, "--par"));
|
|
}
|
|
|
|
/* Verify that autocompletion does not return any match for garbage inputs. */
|
|
|
|
static void
|
|
test_completion_garbage (option_proposer &proposer)
|
|
{
|
|
ASSERT_TRUE (empty_completion_p (proposer, NULL));
|
|
ASSERT_TRUE (empty_completion_p (proposer, ""));
|
|
ASSERT_TRUE (empty_completion_p (proposer, "- "));
|
|
ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
|
|
ASSERT_TRUE (empty_completion_p (proposer, "---------"));
|
|
ASSERT_TRUE (empty_completion_p (proposer, "#########"));
|
|
ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
|
|
ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
|
|
}
|
|
|
|
/* Run all of the selftests within this file. */
|
|
|
|
void
|
|
opt_proposer_c_tests ()
|
|
{
|
|
option_proposer proposer;
|
|
|
|
test_completion_valid_options (proposer);
|
|
test_completion_valid_params (proposer);
|
|
test_completion_partial_match (proposer);
|
|
test_completion_garbage (proposer);
|
|
}
|
|
|
|
} // namespace selftest
|
|
|
|
#endif /* #if CHECKING_P */
|