Fix PR target/93932
[official-gcc.git] / gcc / opt-suggestions.c
blob833c8c902bded4ef1572003354cb3f0880991494
1 /* Provide option suggestion for --complete option and a misspelled
2 used by a user.
3 Copyright (C) 2016-2020 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 "spellcheck.h"
27 #include "opt-suggestions.h"
28 #include "common/common-target.h"
29 #include "selftest.h"
31 option_proposer::~option_proposer ()
33 delete m_option_suggestions;
36 const char *
37 option_proposer::suggest_option (const char *bad_opt)
39 /* Lazily populate m_option_suggestions. */
40 if (!m_option_suggestions)
41 build_option_suggestions (NULL);
42 gcc_assert (m_option_suggestions);
44 /* "m_option_suggestions" is now populated. Use it. */
45 return find_closest_string
46 (bad_opt,
47 (auto_vec <const char *> *) m_option_suggestions);
50 /* Populate RESULTS with valid completions of options that begin
51 with OPTION_PREFIX. */
53 void
54 option_proposer::get_completions (const char *option_prefix,
55 auto_string_vec &results)
57 /* Bail out for an invalid input. */
58 if (option_prefix == NULL || option_prefix[0] == '\0')
59 return;
61 /* Option suggestions are built without first leading dash character. */
62 if (option_prefix[0] == '-')
63 option_prefix++;
65 size_t length = strlen (option_prefix);
67 /* Lazily populate m_option_suggestions. */
68 if (!m_option_suggestions)
69 build_option_suggestions (option_prefix);
70 gcc_assert (m_option_suggestions);
72 for (unsigned i = 0; i < m_option_suggestions->length (); i++)
74 char *candidate = (*m_option_suggestions)[i];
75 if (strlen (candidate) >= length
76 && strstr (candidate, option_prefix) == candidate)
77 results.safe_push (concat ("-", candidate, NULL));
81 /* Print on stdout a list of valid options that begin with OPTION_PREFIX,
82 one per line, suitable for use by Bash completion.
84 Implementation of the "-completion=" option. */
86 void
87 option_proposer::suggest_completion (const char *option_prefix)
89 auto_string_vec results;
90 get_completions (option_prefix, results);
91 for (unsigned i = 0; i < results.length (); i++)
92 printf ("%s\n", results[i]);
95 void
96 option_proposer::build_option_suggestions (const char *prefix)
98 gcc_assert (m_option_suggestions == NULL);
99 m_option_suggestions = new auto_string_vec ();
101 /* We build a vec of m_option_suggestions, using add_misspelling_candidates
102 to add copies of strings, without a leading dash. */
104 for (unsigned int i = 0; i < cl_options_count; i++)
106 const struct cl_option *option = &cl_options[i];
107 const char *opt_text = option->opt_text;
108 switch (i)
110 default:
111 if (option->var_type == CLVC_ENUM)
113 const struct cl_enum *e = &cl_enums[option->var_enum];
114 for (unsigned j = 0; e->values[j].arg != NULL; j++)
116 char *with_arg = concat (opt_text, e->values[j].arg, NULL);
117 add_misspelling_candidates (m_option_suggestions, option,
118 with_arg);
119 free (with_arg);
122 /* Add also variant without an option argument. */
123 add_misspelling_candidates (m_option_suggestions, option,
124 opt_text);
126 else
128 bool option_added = false;
129 if (option->flags & CL_TARGET)
131 vec<const char *> option_values
132 = targetm_common.get_valid_option_values (i, prefix);
133 if (!option_values.is_empty ())
135 option_added = true;
136 for (unsigned j = 0; j < option_values.length (); j++)
138 char *with_arg = concat (opt_text, option_values[j],
139 NULL);
140 add_misspelling_candidates (m_option_suggestions, option,
141 with_arg);
142 free (with_arg);
145 option_values.release ();
148 if (!option_added)
149 add_misspelling_candidates (m_option_suggestions, option,
150 opt_text);
152 break;
154 case OPT_fsanitize_:
155 case OPT_fsanitize_recover_:
156 /* -fsanitize= and -fsanitize-recover= can take
157 a comma-separated list of arguments. Given that combinations
158 are supported, we can't add all potential candidates to the
159 vec, but if we at least add them individually without commas,
160 we should do a better job e.g. correcting
161 "-sanitize=address"
163 "-fsanitize=address"
164 rather than to "-Wframe-address" (PR driver/69265). */
166 /* Add also variant without an option argument. */
167 add_misspelling_candidates (m_option_suggestions, option,
168 opt_text);
170 for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
172 struct cl_option optb;
173 /* -fsanitize=all is not valid, only -fno-sanitize=all.
174 So don't register the positive misspelling candidates
175 for it. */
176 if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
178 optb = *option;
179 optb.opt_text = opt_text = "-fno-sanitize=";
180 optb.cl_reject_negative = true;
181 option = &optb;
183 /* Get one arg at a time e.g. "-fsanitize=address". */
184 char *with_arg = concat (opt_text,
185 sanitizer_opts[j].name,
186 NULL);
187 /* Add with_arg and all of its variant spellings e.g.
188 "-fno-sanitize=address" to candidates (albeit without
189 leading dashes). */
190 add_misspelling_candidates (m_option_suggestions, option,
191 with_arg);
192 free (with_arg);
195 break;
200 #if CHECKING_P
202 namespace selftest {
204 /* Verify that PROPOSER generates sane auto-completion suggestions
205 for OPTION_PREFIX. */
207 static void
208 verify_autocompletions (option_proposer &proposer, const char *option_prefix)
210 auto_string_vec suggestions;
211 proposer.get_completions (option_prefix, suggestions);
213 /* There must be at least one suggestion, and every suggestion must
214 indeed begin with OPTION_PREFIX. */
216 ASSERT_GT (suggestions.length (), 0);
218 for (unsigned i = 0; i < suggestions.length (); i++)
219 ASSERT_STR_STARTSWITH (suggestions[i], option_prefix);
222 /* Verify that valid options are auto-completed correctly. */
224 static void
225 test_completion_valid_options (option_proposer &proposer)
227 const char *option_prefixes[] =
229 "-fno-var-tracking-assignments-toggle",
230 "-fpredictive-commoning",
231 "--param=stack-clash-protection-guard-size",
232 "--param=max-predicted-iterations",
233 "-ftree-loop-distribute-patterns",
234 "-fno-var-tracking",
235 "-Walloc-zero",
236 "--param=ipa-cp-value-list-size",
237 "-Wsync-nand",
238 "-Wno-attributes",
239 "--param=tracer-dynamic-coverage-feedback",
240 "-Wno-format-contains-nul",
241 "-Wnamespaces",
242 "-fisolate-erroneous-paths-attribute",
243 "-Wno-underflow",
244 "-Wtarget-lifetime",
245 "--param=asan-globals",
246 "-Wno-empty-body",
247 "-Wno-odr",
248 "-Wformat-zero-length",
249 "-Wstringop-truncation",
250 "-fno-ipa-vrp",
251 "-fmath-errno",
252 "-Warray-temporaries",
253 "-Wno-unused-label",
254 "-Wreturn-local-addr",
255 "--param=sms-dfa-history",
256 "--param=asan-instrument-reads",
257 "-Wreturn-type",
258 "-Wc++17-compat",
259 "-Wno-effc++",
260 "--param=max-fields-for-field-sensitive",
261 "-fisolate-erroneous-paths-dereference",
262 "-fno-defer-pop",
263 "-Wcast-align=strict",
264 "-foptimize-strlen",
265 "-Wpacked-not-aligned",
266 "-funroll-loops",
267 "-fif-conversion2",
268 "-Wdesignated-init",
269 "--param=max-iterations-computation-cost",
270 "-Wmultiple-inheritance",
271 "-fno-sel-sched-reschedule-pipelined",
272 "-Wassign-intercept",
273 "-Wno-format-security",
274 "-fno-sched-stalled-insns",
275 "-fno-tree-tail-merge",
276 "-Wlong-long",
277 "-Wno-unused-but-set-parameter",
278 NULL
281 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
282 verify_autocompletions (proposer, *ptr);
285 /* Verify that valid parameters are auto-completed correctly,
286 both with the "--param=PARAM" form and the "--param PARAM" form. */
288 static void
289 test_completion_valid_params (option_proposer &proposer)
291 const char *option_prefixes[] =
293 "--param=sched-state-edge-prob-cutoff",
294 "--param=iv-consider-all-candidates-bound",
295 "--param=align-threshold",
296 "--param=prefetch-min-insn-to-mem-ratio",
297 "--param=max-unrolled-insns",
298 "--param=max-early-inliner-iterations",
299 "--param=max-vartrack-reverse-op-size",
300 "--param=ipa-cp-loop-hint-bonus",
301 "--param=tracer-min-branch-ratio",
302 "--param=graphite-max-arrays-per-scop",
303 "--param=sink-frequency-threshold",
304 "--param=max-cse-path-length",
305 "--param=sra-max-scalarization-size-Osize",
306 "--param=prefetch-latency",
307 "--param=dse-max-object-size",
308 "--param=asan-globals",
309 "--param=max-vartrack-size",
310 "--param=case-values-threshold",
311 "--param=max-slsr-cand-scan",
312 "--param=min-insn-to-prefetch-ratio",
313 "--param=tracer-min-branch-probability",
314 "--param sink-frequency-threshold",
315 "--param max-cse-path-length",
316 "--param sra-max-scalarization-size-Osize",
317 "--param prefetch-latency",
318 "--param dse-max-object-size",
319 "--param asan-globals",
320 "--param max-vartrack-size",
321 NULL
324 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
325 verify_autocompletions (proposer, *ptr);
328 /* Return true when EXPECTED is one of completions for OPTION_PREFIX string. */
330 static bool
331 in_completion_p (option_proposer &proposer, const char *option_prefix,
332 const char *expected)
334 auto_string_vec suggestions;
335 proposer.get_completions (option_prefix, suggestions);
337 for (unsigned i = 0; i < suggestions.length (); i++)
339 char *r = suggestions[i];
340 if (strcmp (r, expected) == 0)
341 return true;
344 return false;
347 /* Return true when PROPOSER does not find any partial completion
348 for OPTION_PREFIX. */
350 static bool
351 empty_completion_p (option_proposer &proposer, const char *option_prefix)
353 auto_string_vec suggestions;
354 proposer.get_completions (option_prefix, suggestions);
355 return suggestions.is_empty ();
358 /* Verify autocompletions of partially-complete options. */
360 static void
361 test_completion_partial_match (option_proposer &proposer)
363 ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
364 ASSERT_TRUE (in_completion_p (proposer, "-fsani",
365 "-fsanitize-address-use-after-scope"));
366 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
367 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
368 ASSERT_TRUE (in_completion_p (proposer, "--param=",
369 "--param=max-vartrack-reverse-op-size="));
370 ASSERT_TRUE (in_completion_p (proposer, "--param ",
371 "--param max-vartrack-reverse-op-size="));
373 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
374 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
376 ASSERT_FALSE (empty_completion_p (proposer, "-"));
377 ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
378 ASSERT_FALSE (empty_completion_p (proposer, "--par"));
381 /* Verify that autocompletion does not return any match for garbage inputs. */
383 static void
384 test_completion_garbage (option_proposer &proposer)
386 ASSERT_TRUE (empty_completion_p (proposer, NULL));
387 ASSERT_TRUE (empty_completion_p (proposer, ""));
388 ASSERT_TRUE (empty_completion_p (proposer, "- "));
389 ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
390 ASSERT_TRUE (empty_completion_p (proposer, "---------"));
391 ASSERT_TRUE (empty_completion_p (proposer, "#########"));
392 ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
393 ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
396 /* Run all of the selftests within this file. */
398 void
399 opt_proposer_c_tests ()
401 option_proposer proposer;
403 test_completion_valid_options (proposer);
404 test_completion_valid_params (proposer);
405 test_completion_partial_match (proposer);
406 test_completion_garbage (proposer);
409 } // namespace selftest
411 #endif /* #if CHECKING_P */