LCOV - code coverage report
Current view: top level - gcc - opt-suggestions.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 97.0 % 132 128
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Provide option suggestion for --complete option and a misspelled
       2              :    used by a user.
       3              :    Copyright (C) 2016-2026 Free Software Foundation, Inc.
       4              : 
       5              : This file is part of GCC.
       6              : 
       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.
      11              : 
      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.
      16              : 
      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/>.  */
      20              : 
      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"
      30              : 
      31       293520 : option_proposer::~option_proposer ()
      32              : {
      33       293520 :   delete m_option_suggestions;
      34       293520 : }
      35              : 
      36              : const char *
      37          605 : option_proposer::suggest_option (const char *bad_opt)
      38              : {
      39              :   /* Lazily populate m_option_suggestions.  */
      40          605 :   if (!m_option_suggestions)
      41          567 :     build_option_suggestions (NULL);
      42          605 :   gcc_assert (m_option_suggestions);
      43              : 
      44              :   /* "m_option_suggestions" is now populated.  Use it.  */
      45          605 :   return find_closest_string
      46          605 :     (bad_opt,
      47          605 :      (auto_vec <const char *> *) m_option_suggestions);
      48              : }
      49              : 
      50              : /* Populate RESULTS with valid completions of options that begin
      51              :    with OPTION_PREFIX.  */
      52              : 
      53              : void
      54          389 : option_proposer::get_completions (const char *option_prefix,
      55              :                                   auto_string_vec &results)
      56              : {
      57              :   /* Bail out for an invalid input.  */
      58          389 :   if (option_prefix == NULL || option_prefix[0] == '\0')
      59              :     return;
      60              : 
      61              :   /* Option suggestions are built without first leading dash character.  */
      62          381 :   if (option_prefix[0] == '-')
      63          373 :     option_prefix++;
      64              : 
      65          381 :   size_t length = strlen (option_prefix);
      66              : 
      67              :   /* Lazily populate m_option_suggestions.  */
      68          381 :   if (!m_option_suggestions)
      69            9 :     build_option_suggestions (option_prefix);
      70          381 :   gcc_assert (m_option_suggestions);
      71              : 
      72      3934968 :   for (unsigned i = 0; i < m_option_suggestions->length (); i++)
      73              :     {
      74      3934587 :       char *candidate = (*m_option_suggestions)[i];
      75      3934587 :       if (strlen (candidate) >= length
      76      1978216 :           && strstr (candidate, option_prefix) == candidate)
      77        47798 :         results.safe_push (concat ("-", candidate, NULL));
      78              :     }
      79              : }
      80              : 
      81              : /* Print on stdout a list of valid options that begin with OPTION_PREFIX,
      82              :    one per line, suitable for use by Bash completion.
      83              : 
      84              :    Implementation of the "-completion=" option.  */
      85              : 
      86              : void
      87            5 : option_proposer::suggest_completion (const char *option_prefix)
      88              : {
      89            5 :   auto_string_vec results;
      90            5 :   get_completions (option_prefix, results);
      91           27 :   for (unsigned i = 0; i < results.length (); i++)
      92           22 :     printf ("%s\n", results[i]);
      93            5 : }
      94              : 
      95              : void
      96          576 : option_proposer::build_option_suggestions (const char *prefix)
      97              : {
      98          576 :   gcc_assert (m_option_suggestions == NULL);
      99          576 :   m_option_suggestions = new auto_string_vec ();
     100              : 
     101              :   /* We build a vec of m_option_suggestions, using add_misspelling_candidates
     102              :      to add copies of strings, without a leading dash.  */
     103              : 
     104      1471104 :   for (unsigned int i = 0; i < cl_options_count; i++)
     105              :     {
     106      1470528 :       const struct cl_option *option = &cl_options[i];
     107      1470528 :       const char *opt_text = option->opt_text;
     108      1470528 :       switch (i)
     109              :         {
     110      1469376 :         default:
     111      1469376 :           if (option->var_type == CLVC_ENUM)
     112              :             {
     113        51840 :               const struct cl_enum *e = &cl_enums[option->var_enum];
     114       236160 :               for (unsigned j = 0; e->values[j].arg != NULL; j++)
     115              :                 {
     116       184320 :                   char *with_arg = concat (opt_text, e->values[j].arg, NULL);
     117       184320 :                   add_misspelling_candidates (m_option_suggestions, option,
     118              :                                               with_arg);
     119       184320 :                   free (with_arg);
     120              :                 }
     121              : 
     122              :               /* Add also variant without an option argument.  */
     123        51840 :               add_misspelling_candidates (m_option_suggestions, option,
     124              :                                           opt_text);
     125              :             }
     126              :           else
     127              :             {
     128      1417536 :               bool option_added = false;
     129      1417536 :               if (option->flags & CL_TARGET)
     130              :                 {
     131       126144 :                   vec<const char *> option_values
     132       126144 :                     = targetm_common.get_valid_option_values (i, prefix);
     133       126144 :                   if (!option_values.is_empty ())
     134              :                     {
     135       102528 :                       option_added = true;
     136       102528 :                       for (unsigned j = 0; j < option_values.length (); j++)
     137              :                         {
     138       101376 :                           char *with_arg = concat (opt_text, option_values[j],
     139              :                                                    NULL);
     140       101376 :                           add_misspelling_candidates (m_option_suggestions, option,
     141              :                                                       with_arg);
     142       101376 :                           free (with_arg);
     143              :                         }
     144              :                     }
     145       126144 :                   option_values.release ();
     146              :                 }
     147              : 
     148       126144 :               if (!option_added)
     149      1416384 :                 add_misspelling_candidates (m_option_suggestions, option,
     150              :                                             opt_text);
     151              :             }
     152              :           break;
     153              : 
     154         1152 :         case OPT_fsanitize_:
     155         1152 :         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"
     162              :              to
     163              :                "-fsanitize=address"
     164              :              rather than to "-Wframe-address" (PR driver/69265).  */
     165         1152 :           {
     166              :             /* Add also variant without an option argument.  */
     167         1152 :             add_misspelling_candidates (m_option_suggestions, option,
     168              :                                         opt_text);
     169              : 
     170         1152 :             struct cl_option optb;
     171        40320 :             for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
     172              :               {
     173              :                 /* -fsanitize=all is not valid, only -fno-sanitize=all.
     174              :                    So don't register the positive misspelling candidates
     175              :                    for it.  */
     176        39168 :                 if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
     177              :                   {
     178            0 :                     optb = *option;
     179            0 :                     optb.opt_text = opt_text = "-fno-sanitize=";
     180            0 :                     optb.cl_reject_negative = true;
     181            0 :                     option = &optb;
     182              :                   }
     183              :                 /* Get one arg at a time e.g. "-fsanitize=address".  */
     184        39168 :                 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        39168 :                 add_misspelling_candidates (m_option_suggestions, option,
     191              :                                             with_arg);
     192        39168 :                 free (with_arg);
     193              :               }
     194              :           }
     195         1152 :           break;
     196              :         }
     197              :     }
     198          576 : }
     199              : 
     200              : #if CHECKING_P
     201              : 
     202              : namespace selftest {
     203              : 
     204              : /* Verify that PROPOSER generates sane auto-completion suggestions
     205              :    for OPTION_PREFIX.  */
     206              : 
     207              : static void
     208          308 : verify_autocompletions (option_proposer &proposer, const char *option_prefix)
     209              : {
     210          308 :   auto_string_vec suggestions;
     211          308 :   proposer.get_completions (option_prefix, suggestions);
     212              : 
     213              :   /* There must be at least one suggestion, and every suggestion must
     214              :      indeed begin with OPTION_PREFIX.  */
     215              : 
     216          308 :   ASSERT_GT (suggestions.length (), 0);
     217              : 
     218          640 :   for (unsigned i = 0; i < suggestions.length (); i++)
     219          332 :     ASSERT_STR_STARTSWITH (suggestions[i], option_prefix);
     220          308 : }
     221              : 
     222              : /* Verify that valid options are auto-completed correctly.  */
     223              : 
     224              : static void
     225            4 : test_completion_valid_options (option_proposer &proposer)
     226              : {
     227            4 :   const char *option_prefixes[] =
     228              :   {
     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
     279              :   };
     280              : 
     281          200 :   for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
     282          196 :     verify_autocompletions (proposer, *ptr);
     283            4 : }
     284              : 
     285              : /* Verify that valid parameters are auto-completed correctly,
     286              :    both with the "--param=PARAM" form and the "--param PARAM" form.  */
     287              : 
     288              : static void
     289            4 : test_completion_valid_params (option_proposer &proposer)
     290              : {
     291            4 :   const char *option_prefixes[] =
     292              :   {
     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
     322              :   };
     323              : 
     324          116 :   for (const char **ptr = option_prefixes; *ptr != NULL; ptr++)
     325          112 :     verify_autocompletions (proposer, *ptr);
     326            4 : }
     327              : 
     328              : /* Return true when EXPECTED is one of completions for OPTION_PREFIX string.  */
     329              : 
     330              : static bool
     331           32 : in_completion_p (option_proposer &proposer, const char *option_prefix,
     332              :                  const char *expected)
     333              : {
     334           32 :   auto_string_vec suggestions;
     335           32 :   proposer.get_completions (option_prefix, suggestions);
     336              : 
     337         1928 :   for (unsigned i = 0; i < suggestions.length (); i++)
     338              :     {
     339         1920 :       char *r = suggestions[i];
     340         1920 :       if (strcmp (r, expected) == 0)
     341              :         return true;
     342              :     }
     343              : 
     344              :   return false;
     345           32 : }
     346              : 
     347              : /* Return true when PROPOSER does not find any partial completion
     348              :    for OPTION_PREFIX.  */
     349              : 
     350              : static bool
     351           44 : empty_completion_p (option_proposer &proposer, const char *option_prefix)
     352              : {
     353           44 :   auto_string_vec suggestions;
     354           44 :   proposer.get_completions (option_prefix, suggestions);
     355           44 :   return suggestions.is_empty ();
     356           44 : }
     357              : 
     358              : /* Verify autocompletions of partially-complete options.  */
     359              : 
     360              : static void
     361            4 : test_completion_partial_match (option_proposer &proposer)
     362              : {
     363            4 :   ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
     364            4 :   ASSERT_TRUE (in_completion_p (proposer, "-fsani",
     365              :                                 "-fsanitize-address-use-after-scope"));
     366            4 :   ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
     367            4 :   ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
     368            4 :   ASSERT_TRUE (in_completion_p (proposer, "--param=",
     369              :                                 "--param=max-vartrack-reverse-op-size="));
     370            4 :   ASSERT_TRUE (in_completion_p (proposer, "--param ",
     371              :                                 "--param max-vartrack-reverse-op-size="));
     372              : 
     373            4 :   ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
     374            4 :   ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
     375              : 
     376            4 :   ASSERT_FALSE (empty_completion_p (proposer, "-"));
     377            4 :   ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
     378            4 :   ASSERT_FALSE (empty_completion_p (proposer, "--par"));
     379            4 : }
     380              : 
     381              : /* Verify that autocompletion does not return any match for garbage inputs.  */
     382              : 
     383              : static void
     384            4 : test_completion_garbage (option_proposer &proposer)
     385              : {
     386            4 :   ASSERT_TRUE (empty_completion_p (proposer, NULL));
     387            4 :   ASSERT_TRUE (empty_completion_p (proposer, ""));
     388            4 :   ASSERT_TRUE (empty_completion_p (proposer, "- "));
     389            4 :   ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
     390            4 :   ASSERT_TRUE (empty_completion_p (proposer, "---------"));
     391            4 :   ASSERT_TRUE (empty_completion_p (proposer, "#########"));
     392            4 :   ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
     393            4 :   ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
     394            4 : }
     395              : 
     396              : /* Run all of the selftests within this file.  */
     397              : 
     398              : void
     399            4 : opt_suggestions_cc_tests ()
     400              : {
     401            4 :   option_proposer proposer;
     402              : 
     403            4 :   test_completion_valid_options (proposer);
     404            4 :   test_completion_valid_params (proposer);
     405            4 :   test_completion_partial_match (proposer);
     406            4 :   test_completion_garbage (proposer);
     407            4 : }
     408              : 
     409              : } // namespace selftest
     410              : 
     411              : #endif /* #if CHECKING_P */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.