1 /* Provide option suggestion for --complete option and a misspelled
3 Copyright (C) 2016-2023 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
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
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/>. */
23 #include "coretypes.h"
26 #include "spellcheck.h"
27 #include "opt-suggestions.h"
28 #include "common/common-target.h"
31 option_proposer::~option_proposer ()
33 delete m_option_suggestions
;
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
47 (auto_vec
<const char *> *) m_option_suggestions
);
50 /* Populate RESULTS with valid completions of options that begin
51 with OPTION_PREFIX. */
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')
61 /* Option suggestions are built without first leading dash character. */
62 if (option_prefix
[0] == '-')
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. */
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
]);
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
;
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
,
122 /* Add also variant without an option argument. */
123 add_misspelling_candidates (m_option_suggestions
, option
,
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 ())
136 for (unsigned j
= 0; j
< option_values
.length (); j
++)
138 char *with_arg
= concat (opt_text
, option_values
[j
],
140 add_misspelling_candidates (m_option_suggestions
, option
,
145 option_values
.release ();
149 add_misspelling_candidates (m_option_suggestions
, option
,
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
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
,
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
176 if (sanitizer_opts
[j
].flag
== ~0U && i
== OPT_fsanitize_
)
179 optb
.opt_text
= opt_text
= "-fno-sanitize=";
180 optb
.cl_reject_negative
= true;
183 /* Get one arg at a time e.g. "-fsanitize=address". */
184 char *with_arg
= concat (opt_text
,
185 sanitizer_opts
[j
].name
,
187 /* Add with_arg and all of its variant spellings e.g.
188 "-fno-sanitize=address" to candidates (albeit without
190 add_misspelling_candidates (m_option_suggestions
, option
,
204 /* Verify that PROPOSER generates sane auto-completion suggestions
205 for OPTION_PREFIX. */
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. */
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",
236 "--param=ipa-cp-value-list-size",
239 "--param=tracer-dynamic-coverage-feedback",
240 "-Wno-format-contains-nul",
242 "-fisolate-erroneous-paths-attribute",
245 "--param=asan-globals",
248 "-Wformat-zero-length",
249 "-Wstringop-truncation",
252 "-Warray-temporaries",
254 "-Wreturn-local-addr",
255 "--param=sms-dfa-history",
256 "--param=asan-instrument-reads",
260 "--param=max-fields-for-field-sensitive",
261 "-fisolate-erroneous-paths-dereference",
263 "-Wcast-align=strict",
265 "-Wpacked-not-aligned",
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",
277 "-Wno-unused-but-set-parameter",
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. */
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",
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. */
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)
347 /* Return true when PROPOSER does not find any partial completion
348 for OPTION_PREFIX. */
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. */
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. */
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. */
399 opt_suggestions_cc_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 */