]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/opt-suggestions.c
* doc/install.texi (Specific, alpha): Remove note to use
[thirdparty/gcc.git] / gcc / opt-suggestions.c
CommitLineData
2abdff38 1/* Provide option suggestion for --complete option and a misspelled
2 used by a user.
fbd26352 3 Copyright (C) 2016-2019 Free Software Foundation, Inc.
2abdff38 4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
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"
b2903606 29#include "common/common-target.h"
2abdff38 30#include "selftest.h"
31
32option_proposer::~option_proposer ()
33{
34 delete m_option_suggestions;
35}
36
37const char *
38option_proposer::suggest_option (const char *bad_opt)
39{
40 /* Lazily populate m_option_suggestions. */
41 if (!m_option_suggestions)
b2903606 42 build_option_suggestions (NULL);
2abdff38 43 gcc_assert (m_option_suggestions);
44
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);
49}
50
6e8a18d1 51/* Populate RESULTS with valid completions of options that begin
52 with OPTION_PREFIX. */
53
54void
55option_proposer::get_completions (const char *option_prefix,
56 auto_string_vec &results)
57{
58 /* Bail out for an invalid input. */
59 if (option_prefix == NULL || option_prefix[0] == '\0')
60 return;
61
62 /* Option suggestions are built without first leading dash character. */
63 if (option_prefix[0] == '-')
64 option_prefix++;
65
66 size_t length = strlen (option_prefix);
67
68 /* Handle OPTION_PREFIX starting with "-param". */
69 const char *prefix = "-param";
70 if (length >= strlen (prefix)
71 && strstr (option_prefix, prefix) == option_prefix)
72 {
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);
79 }
80 else
81 {
82 /* Lazily populate m_option_suggestions. */
83 if (!m_option_suggestions)
b2903606 84 build_option_suggestions (option_prefix);
6e8a18d1 85 gcc_assert (m_option_suggestions);
86
87 for (unsigned i = 0; i < m_option_suggestions->length (); i++)
88 {
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));
93 }
94 }
95}
96
97/* Print on stdout a list of valid options that begin with OPTION_PREFIX,
98 one per line, suitable for use by Bash completion.
99
100 Implementation of the "-completion=" option. */
101
102void
103option_proposer::suggest_completion (const char *option_prefix)
104{
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]);
109}
110
2abdff38 111void
b2903606 112option_proposer::build_option_suggestions (const char *prefix)
2abdff38 113{
114 gcc_assert (m_option_suggestions == NULL);
115 m_option_suggestions = new auto_string_vec ();
116
117 /* We build a vec of m_option_suggestions, using add_misspelling_candidates
118 to add copies of strings, without a leading dash. */
119
120 for (unsigned int i = 0; i < cl_options_count; i++)
121 {
122 const struct cl_option *option = &cl_options[i];
123 const char *opt_text = option->opt_text;
124 switch (i)
125 {
126 default:
127 if (option->var_type == CLVC_ENUM)
128 {
129 const struct cl_enum *e = &cl_enums[option->var_enum];
130 for (unsigned j = 0; e->values[j].arg != NULL; j++)
131 {
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);
136 }
806ba310 137
138 /* Add also variant without an option argument. */
139 add_misspelling_candidates (m_option_suggestions, option,
140 opt_text);
2abdff38 141 }
142 else
b2903606 143 {
037b9c2b 144 bool option_added = false;
b2903606 145 if (option->flags & CL_TARGET)
146 {
147 vec<const char *> option_values
148 = targetm_common.get_valid_option_values (i, prefix);
149 if (!option_values.is_empty ())
150 {
037b9c2b 151 option_added = true;
b2903606 152 for (unsigned j = 0; j < option_values.length (); j++)
153 {
154 char *with_arg = concat (opt_text, option_values[j],
155 NULL);
156 add_misspelling_candidates (m_option_suggestions, option,
157 with_arg);
158 free (with_arg);
159 }
160 }
b363f27e 161 option_values.release ();
b2903606 162 }
037b9c2b 163
164 if (!option_added)
b2903606 165 add_misspelling_candidates (m_option_suggestions, option,
166 opt_text);
167 }
2abdff38 168 break;
169
170 case OPT_fsanitize_:
171 case OPT_fsanitize_recover_:
172 /* -fsanitize= and -fsanitize-recover= can take
173 a comma-separated list of arguments. Given that combinations
174 are supported, we can't add all potential candidates to the
175 vec, but if we at least add them individually without commas,
176 we should do a better job e.g. correcting
177 "-sanitize=address"
178 to
179 "-fsanitize=address"
180 rather than to "-Wframe-address" (PR driver/69265). */
181 {
806ba310 182 /* Add also variant without an option argument. */
183 add_misspelling_candidates (m_option_suggestions, option,
184 opt_text);
185
2abdff38 186 for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
187 {
188 struct cl_option optb;
189 /* -fsanitize=all is not valid, only -fno-sanitize=all.
190 So don't register the positive misspelling candidates
191 for it. */
192 if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
193 {
194 optb = *option;
195 optb.opt_text = opt_text = "-fno-sanitize=";
196 optb.cl_reject_negative = true;
197 option = &optb;
198 }
199 /* Get one arg at a time e.g. "-fsanitize=address". */
200 char *with_arg = concat (opt_text,
201 sanitizer_opts[j].name,
202 NULL);
203 /* Add with_arg and all of its variant spellings e.g.
204 "-fno-sanitize=address" to candidates (albeit without
205 leading dashes). */
206 add_misspelling_candidates (m_option_suggestions, option,
207 with_arg);
208 free (with_arg);
209 }
210 }
211 break;
212 }
213 }
214}
6e8a18d1 215
216/* Find parameter completions for --param format with SEPARATOR.
217 Again, save the completions into results. */
218
219void
220option_proposer::find_param_completions (const char separator,
221 const char *param_prefix,
222 auto_string_vec &results)
223{
224 char separator_str[] = {separator, '\0'};
225 size_t length = strlen (param_prefix);
226 for (unsigned i = 0; i < get_num_compiler_params (); ++i)
227 {
228 const char *candidate = compiler_params[i].option;
229 if (strlen (candidate) >= length
230 && strstr (candidate, param_prefix) == candidate)
231 results.safe_push (concat ("--param", separator_str, candidate, NULL));
232 }
233}
234
235#if CHECKING_P
236
237namespace selftest {
238
239/* Verify that PROPOSER generates sane auto-completion suggestions
240 for OPTION_PREFIX. */
241
242static void
243verify_autocompletions (option_proposer &proposer, const char *option_prefix)
244{
245 auto_string_vec suggestions;
246 proposer.get_completions (option_prefix, suggestions);
247
248 /* There must be at least one suggestion, and every suggestion must
249 indeed begin with OPTION_PREFIX. */
250
251 ASSERT_GT (suggestions.length (), 0);
252
253 for (unsigned i = 0; i < suggestions.length (); i++)
254 ASSERT_STR_STARTSWITH (suggestions[i], option_prefix);
255}
256
257/* Verify that valid options are auto-completed correctly. */
258
259static void
260test_completion_valid_options (option_proposer &proposer)
261{
262 const char *option_prefixes[] =
263 {
264 "-fno-var-tracking-assignments-toggle",
265 "-fpredictive-commoning",
266 "--param=stack-clash-protection-guard-size",
267 "--param=max-predicted-iterations",
268 "-ftree-loop-distribute-patterns",
269 "-fno-var-tracking",
270 "-Walloc-zero",
271 "--param=ipa-cp-value-list-size",
272 "-Wsync-nand",
273 "-Wno-attributes",
274 "--param=tracer-dynamic-coverage-feedback",
275 "-Wno-format-contains-nul",
276 "-Wnamespaces",
277 "-fisolate-erroneous-paths-attribute",
278 "-Wno-underflow",
279 "-Wtarget-lifetime",
280 "--param=asan-globals",
281 "-Wno-empty-body",
282 "-Wno-odr",
283 "-Wformat-zero-length",
284 "-Wstringop-truncation",
285 "-fno-ipa-vrp",
286 "-fmath-errno",
287 "-Warray-temporaries",
288 "-Wno-unused-label",
289 "-Wreturn-local-addr",
290 "--param=sms-dfa-history",
291 "--param=asan-instrument-reads",
292 "-Wreturn-type",
293 "-Wc++17-compat",
294 "-Wno-effc++",
295 "--param=max-fields-for-field-sensitive",
296 "-fisolate-erroneous-paths-dereference",
297 "-fno-defer-pop",
298 "-Wcast-align=strict",
299 "-foptimize-strlen",
300 "-Wpacked-not-aligned",
301 "-funroll-loops",
302 "-fif-conversion2",
303 "-Wdesignated-init",
304 "--param=max-iterations-computation-cost",
305 "-Wmultiple-inheritance",
306 "-fno-sel-sched-reschedule-pipelined",
307 "-Wassign-intercept",
308 "-Wno-format-security",
309 "-fno-sched-stalled-insns",
310 "-fbtr-bb-exclusive",
311 "-fno-tree-tail-merge",
312 "-Wlong-long",
313 "-Wno-unused-but-set-parameter",
314 NULL
315 };
316
317 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
318 verify_autocompletions (proposer, *ptr);
319}
320
321/* Verify that valid parameters are auto-completed correctly,
322 both with the "--param=PARAM" form and the "--param PARAM" form. */
323
324static void
325test_completion_valid_params (option_proposer &proposer)
326{
327 const char *option_prefixes[] =
328 {
329 "--param=sched-state-edge-prob-cutoff",
330 "--param=iv-consider-all-candidates-bound",
331 "--param=align-threshold",
332 "--param=prefetch-min-insn-to-mem-ratio",
333 "--param=max-unrolled-insns",
334 "--param=max-early-inliner-iterations",
335 "--param=max-vartrack-reverse-op-size",
336 "--param=ipa-cp-loop-hint-bonus",
337 "--param=tracer-min-branch-ratio",
338 "--param=graphite-max-arrays-per-scop",
339 "--param=sink-frequency-threshold",
340 "--param=max-cse-path-length",
341 "--param=sra-max-scalarization-size-Osize",
342 "--param=prefetch-latency",
343 "--param=dse-max-object-size",
344 "--param=asan-globals",
345 "--param=max-vartrack-size",
346 "--param=case-values-threshold",
347 "--param=max-slsr-cand-scan",
348 "--param=min-insn-to-prefetch-ratio",
349 "--param=tracer-min-branch-probability",
350 "--param sink-frequency-threshold",
351 "--param max-cse-path-length",
352 "--param sra-max-scalarization-size-Osize",
353 "--param prefetch-latency",
354 "--param dse-max-object-size",
355 "--param asan-globals",
356 "--param max-vartrack-size",
357 NULL
358 };
359
360 for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
361 verify_autocompletions (proposer, *ptr);
362}
363
364/* Return true when EXPECTED is one of completions for OPTION_PREFIX string. */
365
366static bool
367in_completion_p (option_proposer &proposer, const char *option_prefix,
368 const char *expected)
369{
370 auto_string_vec suggestions;
371 proposer.get_completions (option_prefix, suggestions);
372
373 for (unsigned i = 0; i < suggestions.length (); i++)
374 {
375 char *r = suggestions[i];
376 if (strcmp (r, expected) == 0)
377 return true;
378 }
379
380 return false;
381}
382
383/* Return true when PROPOSER does not find any partial completion
384 for OPTION_PREFIX. */
385
386static bool
387empty_completion_p (option_proposer &proposer, const char *option_prefix)
388{
389 auto_string_vec suggestions;
390 proposer.get_completions (option_prefix, suggestions);
391 return suggestions.is_empty ();
392}
393
394/* Verify autocompletions of partially-complete options. */
395
396static void
397test_completion_partial_match (option_proposer &proposer)
398{
399 ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
400 ASSERT_TRUE (in_completion_p (proposer, "-fsani",
401 "-fsanitize-address-use-after-scope"));
402 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
403 ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
404 ASSERT_TRUE (in_completion_p (proposer, "--param=",
405 "--param=max-vartrack-reverse-op-size"));
406 ASSERT_TRUE (in_completion_p (proposer, "--param ",
407 "--param max-vartrack-reverse-op-size"));
408
409 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
410 ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
411
412 ASSERT_FALSE (empty_completion_p (proposer, "-"));
413 ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
414 ASSERT_FALSE (empty_completion_p (proposer, "--par"));
415}
416
417/* Verify that autocompletion does not return any match for garbage inputs. */
418
419static void
420test_completion_garbage (option_proposer &proposer)
421{
422 ASSERT_TRUE (empty_completion_p (proposer, NULL));
423 ASSERT_TRUE (empty_completion_p (proposer, ""));
424 ASSERT_TRUE (empty_completion_p (proposer, "- "));
425 ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
426 ASSERT_TRUE (empty_completion_p (proposer, "---------"));
427 ASSERT_TRUE (empty_completion_p (proposer, "#########"));
428 ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
429 ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
430}
431
432/* Run all of the selftests within this file. */
433
434void
435opt_proposer_c_tests ()
436{
437 option_proposer proposer;
438
439 test_completion_valid_options (proposer);
440 test_completion_valid_params (proposer);
441 test_completion_partial_match (proposer);
442 test_completion_garbage (proposer);
443}
444
445} // namespace selftest
446
447#endif /* #if CHECKING_P */