Come up with TARGET_GET_VALID_OPTION_VALUES option hook (PR driver/83193).
[official-gcc.git] / gcc / opt-suggestions.c
blobc68c9eedaf6c59c5a890e17daff2bbce63c047e3
1 /* Provide option suggestion for --complete option and a misspelled
2 used by a user.
3 Copyright (C) 2016-2018 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "opts.h"
26 #include "params.h"
27 #include "spellcheck.h"
28 #include "opt-suggestions.h"
29 #include "common/common-target.h"
30 #include "selftest.h"
32 option_proposer::~option_proposer ()
34 delete m_option_suggestions;
37 const char *
38 option_proposer::suggest_option (const char *bad_opt)
40 /* Lazily populate m_option_suggestions. */
41 if (!m_option_suggestions)
42 build_option_suggestions (NULL);
43 gcc_assert (m_option_suggestions);
45 /* "m_option_suggestions" is now populated. Use it. */
46 return find_closest_string
47 (bad_opt,
48 (auto_vec <const char *> *) m_option_suggestions);
51 /* Populate RESULTS with valid completions of options that begin
52 with OPTION_PREFIX. */
54 void
55 option_proposer::get_completions (const char *option_prefix,
56 auto_string_vec &results)
58 /* Bail out for an invalid input. */
59 if (option_prefix == NULL || option_prefix[0] == '\0')
60 return;
62 /* Option suggestions are built without first leading dash character. */
63 if (option_prefix[0] == '-')
64 option_prefix++;
66 size_t length = strlen (option_prefix);
68 /* Handle OPTION_PREFIX starting with "-param". */
69 const char *prefix = "-param";
70 if (length >= strlen (prefix)
71 && strstr (option_prefix, prefix) == option_prefix)
73 /* We support both '-param-xyz=123' and '-param xyz=123' */
74 option_prefix += strlen (prefix);
75 char separator = option_prefix[0];
76 option_prefix++;
77 if (separator == ' ' || separator == '=')
78 find_param_completions (separator, option_prefix, results);
80 else
82 /* Lazily populate m_option_suggestions. */
83 if (!m_option_suggestions)
84 build_option_suggestions (option_prefix);
85 gcc_assert (m_option_suggestions);
87 for (unsigned i = 0; i < m_option_suggestions->length (); i++)
89 char *candidate = (*m_option_suggestions)[i];
90 if (strlen (candidate) >= length
91 && strstr (candidate, option_prefix) == candidate)
92 results.safe_push (concat ("-", candidate, NULL));
97 /* Print on stdout a list of valid options that begin with OPTION_PREFIX,
98 one per line, suitable for use by Bash completion.
100 Implementation of the "-completion=" option. */
102 void
103 option_proposer::suggest_completion (const char *option_prefix)
105 auto_string_vec results;
106 get_completions (option_prefix, results);
107 for (unsigned i = 0; i < results.length (); i++)
108 printf ("%s\n", results[i]);
111 void
112 option_proposer::build_option_suggestions (const char *prefix)
114 gcc_assert (m_option_suggestions == NULL);
115 m_option_suggestions = new auto_string_vec ();
117 /* We build a vec of m_option_suggestions, using add_misspelling_candidates
118 to add copies of strings, without a leading dash. */
120 for (unsigned int i = 0; i < cl_options_count; i++)
122 const struct cl_option *option = &cl_options[i];
123 const char *opt_text = option->opt_text;
124 switch (i)
126 default:
127 if (option->var_type == CLVC_ENUM)
129 const struct cl_enum *e = &cl_enums[option->var_enum];
130 for (unsigned j = 0; e->values[j].arg != NULL; j++)
132 char *with_arg = concat (opt_text, e->values[j].arg, NULL);
133 add_misspelling_candidates (m_option_suggestions, option,
134 with_arg);
135 free (with_arg);
138 else
140 if (option->flags & CL_TARGET)
142 vec<const char *> option_values
143 = targetm_common.get_valid_option_values (i, prefix);
144 if (!option_values.is_empty ())
146 for (unsigned j = 0; j < option_values.length (); j++)
148 char *with_arg = concat (opt_text, option_values[j],
149 NULL);
150 add_misspelling_candidates (m_option_suggestions, option,
151 with_arg);
152 free (with_arg);
156 else
157 add_misspelling_candidates (m_option_suggestions, option,
158 opt_text);
160 break;
162 case OPT_fsanitize_:
163 case OPT_fsanitize_recover_:
164 /* -fsanitize= and -fsanitize-recover= can take
165 a comma-separated list of arguments. Given that combinations
166 are supported, we can't add all potential candidates to the
167 vec, but if we at least add them individually without commas,
168 we should do a better job e.g. correcting
169 "-sanitize=address"
171 "-fsanitize=address"
172 rather than to "-Wframe-address" (PR driver/69265). */
174 for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
176 struct cl_option optb;
177 /* -fsanitize=all is not valid, only -fno-sanitize=all.
178 So don't register the positive misspelling candidates
179 for it. */
180 if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
182 optb = *option;
183 optb.opt_text = opt_text = "-fno-sanitize=";
184 optb.cl_reject_negative = true;
185 option = &optb;
187 /* Get one arg at a time e.g. "-fsanitize=address". */
188 char *with_arg = concat (opt_text,
189 sanitizer_opts[j].name,
190 NULL);
191 /* Add with_arg and all of its variant spellings e.g.
192 "-fno-sanitize=address" to candidates (albeit without
193 leading dashes). */
194 add_misspelling_candidates (m_option_suggestions, option,
195 with_arg);
196 free (with_arg);
199 break;
204 /* Find parameter completions for --param format with SEPARATOR.
205 Again, save the completions into results. */
207 void
208 option_proposer::find_param_completions (const char separator,
209 const char *param_prefix,
210 auto_string_vec &results)
212 char separator_str[] = {separator, '\0'};
213 size_t length = strlen (param_prefix);
214 for (unsigned i = 0; i < get_num_compiler_params (); ++i)
216 const char *candidate = compiler_params[i].option;
217 if (strlen (candidate) >= length
218 && strstr (candidate, param_prefix) == candidate)
219 results.safe_push (concat ("--param", separator_str, candidate, NULL));
223 #if CHECKING_P
225 namespace selftest {
227 /* Verify that PROPOSER generates sane auto-completion suggestions
228 for OPTION_PREFIX. */
230 static void
231 verify_autocompletions (option_proposer &proposer, const char *option_prefix)
233 auto_string_vec suggestions;
234 proposer.get_completions (option_prefix, suggestions);
236 /* There must be at least one suggestion, and every suggestion must
237 indeed begin with OPTION_PREFIX. */
239 ASSERT_GT (suggestions.length (), 0);
241 for (unsigned i = 0; i < suggestions.length (); i++)
242 ASSERT_STR_STARTSWITH (suggestions[i], option_prefix);
245 /* Verify that valid options are auto-completed correctly. */
247 static void
248 test_completion_valid_options (option_proposer &proposer)
250 const char *option_prefixes[] =
252 "-fno-var-tracking-assignments-toggle",
253 "-fpredictive-commoning",
254 "--param=stack-clash-protection-guard-size",
255 "--param=max-predicted-iterations",
256 "-ftree-loop-distribute-patterns",
257 "-fno-var-tracking",
258 "-Walloc-zero",
259 "--param=ipa-cp-value-list-size",
260 "-Wsync-nand",
261 "-Wno-attributes",
262 "--param=tracer-dynamic-coverage-feedback",
263 "-Wno-format-contains-nul",
264 "-Wnamespaces",
265 "-fisolate-erroneous-paths-attribute",
266 "-Wno-underflow",
267 "-Wtarget-lifetime",
268 "--param=asan-globals",
269 "-Wno-empty-body",
270 "-Wno-odr",
271 "-Wformat-zero-length",
272 "-Wstringop-truncation",
273 "-fno-ipa-vrp",
274 "-fmath-errno",
275 "-Warray-temporaries",
276 "-Wno-unused-label",
277 "-Wreturn-local-addr",
278 "--param=sms-dfa-history",
279 "--param=asan-instrument-reads",
280 "-Wreturn-type",
281 "-Wc++17-compat",
282 "-Wno-effc++",
283 "--param=max-fields-for-field-sensitive",
284 "-fisolate-erroneous-paths-dereference",
285 "-fno-defer-pop",
286 "-Wcast-align=strict",
287 "-foptimize-strlen",
288 "-Wpacked-not-aligned",
289 "-funroll-loops",
290 "-fif-conversion2",
291 "-Wdesignated-init",
292 "--param=max-iterations-computation-cost",
293 "-Wmultiple-inheritance",
294 "-fno-sel-sched-reschedule-pipelined",
295 "-Wassign-intercept",
296 "-Wno-format-security",
297 "-fno-sched-stalled-insns",
298 "-fbtr-bb-exclusive",
299 "-fno-tree-tail-merge",
300 "-Wlong-long",
301 "-Wno-unused-but-set-parameter",
302 NULL
305 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
306 verify_autocompletions (proposer, *ptr);
309 /* Verify that valid parameters are auto-completed correctly,
310 both with the "--param=PARAM" form and the "--param PARAM" form. */
312 static void
313 test_completion_valid_params (option_proposer &proposer)
315 const char *option_prefixes[] =
317 "--param=sched-state-edge-prob-cutoff",
318 "--param=iv-consider-all-candidates-bound",
319 "--param=align-threshold",
320 "--param=prefetch-min-insn-to-mem-ratio",
321 "--param=max-unrolled-insns",
322 "--param=max-early-inliner-iterations",
323 "--param=max-vartrack-reverse-op-size",
324 "--param=ipa-cp-loop-hint-bonus",
325 "--param=tracer-min-branch-ratio",
326 "--param=graphite-max-arrays-per-scop",
327 "--param=sink-frequency-threshold",
328 "--param=max-cse-path-length",
329 "--param=sra-max-scalarization-size-Osize",
330 "--param=prefetch-latency",
331 "--param=dse-max-object-size",
332 "--param=asan-globals",
333 "--param=max-vartrack-size",
334 "--param=case-values-threshold",
335 "--param=max-slsr-cand-scan",
336 "--param=min-insn-to-prefetch-ratio",
337 "--param=tracer-min-branch-probability",
338 "--param sink-frequency-threshold",
339 "--param max-cse-path-length",
340 "--param sra-max-scalarization-size-Osize",
341 "--param prefetch-latency",
342 "--param dse-max-object-size",
343 "--param asan-globals",
344 "--param max-vartrack-size",
345 NULL
348 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
349 verify_autocompletions (proposer, *ptr);
352 /* Return true when EXPECTED is one of completions for OPTION_PREFIX string. */
354 static bool
355 in_completion_p (option_proposer &proposer, const char *option_prefix,
356 const char *expected)
358 auto_string_vec suggestions;
359 proposer.get_completions (option_prefix, suggestions);
361 for (unsigned i = 0; i < suggestions.length (); i++)
363 char *r = suggestions[i];
364 if (strcmp (r, expected) == 0)
365 return true;
368 return false;
371 /* Return true when PROPOSER does not find any partial completion
372 for OPTION_PREFIX. */
374 static bool
375 empty_completion_p (option_proposer &proposer, const char *option_prefix)
377 auto_string_vec suggestions;
378 proposer.get_completions (option_prefix, suggestions);
379 return suggestions.is_empty ();
382 /* Verify autocompletions of partially-complete options. */
384 static void
385 test_completion_partial_match (option_proposer &proposer)
387 ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
388 ASSERT_TRUE (in_completion_p (proposer, "-fsani",
389 "-fsanitize-address-use-after-scope"));
390 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
391 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
392 ASSERT_TRUE (in_completion_p (proposer, "--param=",
393 "--param=max-vartrack-reverse-op-size"));
394 ASSERT_TRUE (in_completion_p (proposer, "--param ",
395 "--param max-vartrack-reverse-op-size"));
397 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
398 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
400 ASSERT_FALSE (empty_completion_p (proposer, "-"));
401 ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
402 ASSERT_FALSE (empty_completion_p (proposer, "--par"));
405 /* Verify that autocompletion does not return any match for garbage inputs. */
407 static void
408 test_completion_garbage (option_proposer &proposer)
410 ASSERT_TRUE (empty_completion_p (proposer, NULL));
411 ASSERT_TRUE (empty_completion_p (proposer, ""));
412 ASSERT_TRUE (empty_completion_p (proposer, "- "));
413 ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
414 ASSERT_TRUE (empty_completion_p (proposer, "---------"));
415 ASSERT_TRUE (empty_completion_p (proposer, "#########"));
416 ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
417 ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
420 /* Run all of the selftests within this file. */
422 void
423 opt_proposer_c_tests ()
425 option_proposer proposer;
427 test_completion_valid_options (proposer);
428 test_completion_valid_params (proposer);
429 test_completion_partial_match (proposer);
430 test_completion_garbage (proposer);
433 } // namespace selftest
435 #endif /* #if CHECKING_P */