diff gcc/opt-suggestions.c @ 132:d34655255c78

update gcc-8.2
author mir3636
date Thu, 25 Oct 2018 10:21:07 +0900
parents 84e7813d76e9
children 1830386684a0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/opt-suggestions.c	Thu Oct 25 10:21:07 2018 +0900
@@ -0,0 +1,436 @@
+/* Provide option suggestion for --complete option and a misspelled
+   used by a user.
+   Copyright (C) 2016-2018 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 "params.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);
+
+  /* Handle OPTION_PREFIX starting with "-param".  */
+  const char *prefix = "-param";
+  if (length >= strlen (prefix)
+      && strstr (option_prefix, prefix) == option_prefix)
+    {
+      /* We support both '-param-xyz=123' and '-param xyz=123' */
+      option_prefix += strlen (prefix);
+      char separator = option_prefix[0];
+      option_prefix++;
+      if (separator == ' ' || separator == '=')
+	find_param_completions (separator, option_prefix, results);
+    }
+  else
+    {
+      /* 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);
+		}
+	    }
+	  else
+	    {
+	      if (option->flags & CL_TARGET)
+		{
+		  vec<const char *> option_values
+		    = targetm_common.get_valid_option_values (i, prefix);
+		  if (!option_values.is_empty ())
+		    {
+		      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 ();
+		}
+	      else
+		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).  */
+	  {
+	    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;
+	}
+    }
+}
+
+/* Find parameter completions for --param format with SEPARATOR.
+   Again, save the completions into results.  */
+
+void
+option_proposer::find_param_completions (const char separator,
+					 const char *param_prefix,
+					 auto_string_vec &results)
+{
+  char separator_str[] = {separator, '\0'};
+  size_t length = strlen (param_prefix);
+  for (unsigned i = 0; i < get_num_compiler_params (); ++i)
+    {
+      const char *candidate = compiler_params[i].option;
+      if (strlen (candidate) >= length
+	  && strstr (candidate, param_prefix) == candidate)
+	results.safe_push (concat ("--param", separator_str, candidate, NULL));
+    }
+}
+
+#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",
+    "-fbtr-bb-exclusive",
+    "-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 */