Mercurial > hg > CbC > CbC_gcc
diff gcc/opt-suggestions.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | |
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 07:37:49 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 */