gcc:
[official-gcc.git] / gcc / opt-suggestions.c
blob894eea5f37c0bd01a90039ba106571114961c903
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 "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 ();
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 /* Handle OPTION_PREFIX starting with "-param". */
68 const char *prefix = "-param";
69 if (length >= strlen (prefix)
70 && strstr (option_prefix, prefix) == option_prefix)
72 /* We support both '-param-xyz=123' and '-param xyz=123' */
73 option_prefix += strlen (prefix);
74 char separator = option_prefix[0];
75 option_prefix++;
76 if (separator == ' ' || separator == '=')
77 find_param_completions (separator, option_prefix, results);
79 else
81 /* Lazily populate m_option_suggestions. */
82 if (!m_option_suggestions)
83 build_option_suggestions ();
84 gcc_assert (m_option_suggestions);
86 for (unsigned i = 0; i < m_option_suggestions->length (); i++)
88 char *candidate = (*m_option_suggestions)[i];
89 if (strlen (candidate) >= length
90 && strstr (candidate, option_prefix) == candidate)
91 results.safe_push (concat ("-", candidate, NULL));
96 /* Print on stdout a list of valid options that begin with OPTION_PREFIX,
97 one per line, suitable for use by Bash completion.
99 Implementation of the "-completion=" option. */
101 void
102 option_proposer::suggest_completion (const char *option_prefix)
104 auto_string_vec results;
105 get_completions (option_prefix, results);
106 for (unsigned i = 0; i < results.length (); i++)
107 printf ("%s\n", results[i]);
110 void
111 option_proposer::build_option_suggestions (void)
113 gcc_assert (m_option_suggestions == NULL);
114 m_option_suggestions = new auto_string_vec ();
116 /* We build a vec of m_option_suggestions, using add_misspelling_candidates
117 to add copies of strings, without a leading dash. */
119 for (unsigned int i = 0; i < cl_options_count; i++)
121 const struct cl_option *option = &cl_options[i];
122 const char *opt_text = option->opt_text;
123 switch (i)
125 default:
126 if (option->var_type == CLVC_ENUM)
128 const struct cl_enum *e = &cl_enums[option->var_enum];
129 for (unsigned j = 0; e->values[j].arg != NULL; j++)
131 char *with_arg = concat (opt_text, e->values[j].arg, NULL);
132 add_misspelling_candidates (m_option_suggestions, option,
133 with_arg);
134 free (with_arg);
137 else
138 add_misspelling_candidates (m_option_suggestions, option,
139 opt_text);
140 break;
142 case OPT_fsanitize_:
143 case OPT_fsanitize_recover_:
144 /* -fsanitize= and -fsanitize-recover= can take
145 a comma-separated list of arguments. Given that combinations
146 are supported, we can't add all potential candidates to the
147 vec, but if we at least add them individually without commas,
148 we should do a better job e.g. correcting
149 "-sanitize=address"
151 "-fsanitize=address"
152 rather than to "-Wframe-address" (PR driver/69265). */
154 for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
156 struct cl_option optb;
157 /* -fsanitize=all is not valid, only -fno-sanitize=all.
158 So don't register the positive misspelling candidates
159 for it. */
160 if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
162 optb = *option;
163 optb.opt_text = opt_text = "-fno-sanitize=";
164 optb.cl_reject_negative = true;
165 option = &optb;
167 /* Get one arg at a time e.g. "-fsanitize=address". */
168 char *with_arg = concat (opt_text,
169 sanitizer_opts[j].name,
170 NULL);
171 /* Add with_arg and all of its variant spellings e.g.
172 "-fno-sanitize=address" to candidates (albeit without
173 leading dashes). */
174 add_misspelling_candidates (m_option_suggestions, option,
175 with_arg);
176 free (with_arg);
179 break;
184 /* Find parameter completions for --param format with SEPARATOR.
185 Again, save the completions into results. */
187 void
188 option_proposer::find_param_completions (const char separator,
189 const char *param_prefix,
190 auto_string_vec &results)
192 char separator_str[] = {separator, '\0'};
193 size_t length = strlen (param_prefix);
194 for (unsigned i = 0; i < get_num_compiler_params (); ++i)
196 const char *candidate = compiler_params[i].option;
197 if (strlen (candidate) >= length
198 && strstr (candidate, param_prefix) == candidate)
199 results.safe_push (concat ("--param", separator_str, candidate, NULL));
203 #if CHECKING_P
205 namespace selftest {
207 /* Verify that PROPOSER generates sane auto-completion suggestions
208 for OPTION_PREFIX. */
210 static void
211 verify_autocompletions (option_proposer &proposer, const char *option_prefix)
213 auto_string_vec suggestions;
214 proposer.get_completions (option_prefix, suggestions);
216 /* There must be at least one suggestion, and every suggestion must
217 indeed begin with OPTION_PREFIX. */
219 ASSERT_GT (suggestions.length (), 0);
221 for (unsigned i = 0; i < suggestions.length (); i++)
222 ASSERT_STR_STARTSWITH (suggestions[i], option_prefix);
225 /* Verify that valid options are auto-completed correctly. */
227 static void
228 test_completion_valid_options (option_proposer &proposer)
230 const char *option_prefixes[] =
232 "-fno-var-tracking-assignments-toggle",
233 "-fpredictive-commoning",
234 "--param=stack-clash-protection-guard-size",
235 "--param=max-predicted-iterations",
236 "-ftree-loop-distribute-patterns",
237 "-fno-var-tracking",
238 "-Walloc-zero",
239 "--param=ipa-cp-value-list-size",
240 "-Wsync-nand",
241 "-Wno-attributes",
242 "--param=tracer-dynamic-coverage-feedback",
243 "-Wno-format-contains-nul",
244 "-Wnamespaces",
245 "-fisolate-erroneous-paths-attribute",
246 "-Wno-underflow",
247 "-Wtarget-lifetime",
248 "--param=asan-globals",
249 "-Wno-empty-body",
250 "-Wno-odr",
251 "-Wformat-zero-length",
252 "-Wstringop-truncation",
253 "-fno-ipa-vrp",
254 "-fmath-errno",
255 "-Warray-temporaries",
256 "-Wno-unused-label",
257 "-Wreturn-local-addr",
258 "--param=sms-dfa-history",
259 "--param=asan-instrument-reads",
260 "-Wreturn-type",
261 "-Wc++17-compat",
262 "-Wno-effc++",
263 "--param=max-fields-for-field-sensitive",
264 "-fisolate-erroneous-paths-dereference",
265 "-fno-defer-pop",
266 "-Wcast-align=strict",
267 "-foptimize-strlen",
268 "-Wpacked-not-aligned",
269 "-funroll-loops",
270 "-fif-conversion2",
271 "-Wdesignated-init",
272 "--param=max-iterations-computation-cost",
273 "-Wmultiple-inheritance",
274 "-fno-sel-sched-reschedule-pipelined",
275 "-Wassign-intercept",
276 "-Wno-format-security",
277 "-fno-sched-stalled-insns",
278 "-fbtr-bb-exclusive",
279 "-fno-tree-tail-merge",
280 "-Wlong-long",
281 "-Wno-unused-but-set-parameter",
282 NULL
285 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
286 verify_autocompletions (proposer, *ptr);
289 /* Verify that valid parameters are auto-completed correctly,
290 both with the "--param=PARAM" form and the "--param PARAM" form. */
292 static void
293 test_completion_valid_params (option_proposer &proposer)
295 const char *option_prefixes[] =
297 "--param=sched-state-edge-prob-cutoff",
298 "--param=iv-consider-all-candidates-bound",
299 "--param=align-threshold",
300 "--param=prefetch-min-insn-to-mem-ratio",
301 "--param=max-unrolled-insns",
302 "--param=max-early-inliner-iterations",
303 "--param=max-vartrack-reverse-op-size",
304 "--param=ipa-cp-loop-hint-bonus",
305 "--param=tracer-min-branch-ratio",
306 "--param=graphite-max-arrays-per-scop",
307 "--param=sink-frequency-threshold",
308 "--param=max-cse-path-length",
309 "--param=sra-max-scalarization-size-Osize",
310 "--param=prefetch-latency",
311 "--param=dse-max-object-size",
312 "--param=asan-globals",
313 "--param=max-vartrack-size",
314 "--param=case-values-threshold",
315 "--param=max-slsr-cand-scan",
316 "--param=min-insn-to-prefetch-ratio",
317 "--param=tracer-min-branch-probability",
318 "--param sink-frequency-threshold",
319 "--param max-cse-path-length",
320 "--param sra-max-scalarization-size-Osize",
321 "--param prefetch-latency",
322 "--param dse-max-object-size",
323 "--param asan-globals",
324 "--param max-vartrack-size",
325 NULL
328 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
329 verify_autocompletions (proposer, *ptr);
332 /* Return true when EXPECTED is one of completions for OPTION_PREFIX string. */
334 static bool
335 in_completion_p (option_proposer &proposer, const char *option_prefix,
336 const char *expected)
338 auto_string_vec suggestions;
339 proposer.get_completions (option_prefix, suggestions);
341 for (unsigned i = 0; i < suggestions.length (); i++)
343 char *r = suggestions[i];
344 if (strcmp (r, expected) == 0)
345 return true;
348 return false;
351 /* Return true when PROPOSER does not find any partial completion
352 for OPTION_PREFIX. */
354 static bool
355 empty_completion_p (option_proposer &proposer, const char *option_prefix)
357 auto_string_vec suggestions;
358 proposer.get_completions (option_prefix, suggestions);
359 return suggestions.is_empty ();
362 /* Verify autocompletions of partially-complete options. */
364 static void
365 test_completion_partial_match (option_proposer &proposer)
367 ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
368 ASSERT_TRUE (in_completion_p (proposer, "-fsani",
369 "-fsanitize-address-use-after-scope"));
370 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
371 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
372 ASSERT_TRUE (in_completion_p (proposer, "--param=",
373 "--param=max-vartrack-reverse-op-size"));
374 ASSERT_TRUE (in_completion_p (proposer, "--param ",
375 "--param max-vartrack-reverse-op-size"));
377 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
378 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
380 ASSERT_FALSE (empty_completion_p (proposer, "-"));
381 ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
382 ASSERT_FALSE (empty_completion_p (proposer, "--par"));
385 /* Verify that autocompletion does not return any match for garbage inputs. */
387 static void
388 test_completion_garbage (option_proposer &proposer)
390 ASSERT_TRUE (empty_completion_p (proposer, NULL));
391 ASSERT_TRUE (empty_completion_p (proposer, ""));
392 ASSERT_TRUE (empty_completion_p (proposer, "- "));
393 ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
394 ASSERT_TRUE (empty_completion_p (proposer, "---------"));
395 ASSERT_TRUE (empty_completion_p (proposer, "#########"));
396 ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
397 ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
400 /* Run all of the selftests within this file. */
402 void
403 opt_proposer_c_tests ()
405 option_proposer proposer;
407 test_completion_valid_options (proposer);
408 test_completion_valid_params (proposer);
409 test_completion_partial_match (proposer);
410 test_completion_garbage (proposer);
413 } // namespace selftest
415 #endif /* #if CHECKING_P */