/* Provide option suggestion for --complete option and a misspelled
used by a user.
- Copyright (C) 2016-2018 Free Software Foundation, Inc.
+ Copyright (C) 2016-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "opts.h"
-#include "params.h"
#include "spellcheck.h"
#include "opt-suggestions.h"
+#include "common/common-target.h"
#include "selftest.h"
option_proposer::~option_proposer ()
{
/* Lazily populate m_option_suggestions. */
if (!m_option_suggestions)
- build_option_suggestions ();
+ build_option_suggestions (NULL);
gcc_assert (m_option_suggestions);
/* "m_option_suggestions" is now populated. Use it. */
(auto_vec <const char *> *) m_option_suggestions);
}
+/* Populate RESULTS with valid completions of options that begin
+ with OPTION_PREFIX. */
+
void
-option_proposer::build_option_suggestions (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 ();
with_arg);
free (with_arg);
}
+
+ /* Add also variant without an option argument. */
+ add_misspelling_candidates (m_option_suggestions, option,
+ opt_text);
}
else
- add_misspelling_candidates (m_option_suggestions, option,
- opt_text);
+ {
+ 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_:
"-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;
}
}
}
+
+#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 */