Factor out final completion match string building
[deliverable/binutils-gdb.git] / gdb / completer.c
index 1e4fe1861978576d44eb869de4131291d552bce9..01951144867fe9c082a849ebe36034b6168cd693 100644 (file)
@@ -45,9 +45,6 @@
 
 #include "completer.h"
 
-static void complete_expression (completion_tracker &tracker,
-                                const char *text, const char *word);
-
 /* Misc state that needs to be tracked across several different
    readline completer entry point calls, all related to a single
    completion invocation.  */
@@ -79,6 +76,9 @@ enum explicit_location_match_type
     /* The name of a function or method.  */
     MATCH_FUNCTION,
 
+    /* The fully-qualified name of a function or method.  */
+    MATCH_QUALIFIED,
+
     /* A line number.  */
     MATCH_LINE,
 
@@ -154,15 +154,13 @@ filename_completer (struct cmd_list_element *ignore,
                    const char *text, const char *word)
 {
   int subsequent_name;
-  VEC (char_ptr) *return_val = NULL;
 
   subsequent_name = 0;
   while (1)
     {
-      char *p, *q;
-
-      p = rl_filename_completion_function (text, subsequent_name);
-      if (p == NULL)
+      gdb::unique_xmalloc_ptr<char> p_rl
+       (rl_filename_completion_function (text, subsequent_name));
+      if (p_rl == NULL)
        break;
       /* We need to set subsequent_name to a non-zero value before the
         continue line below, because otherwise, if the first file
@@ -171,32 +169,12 @@ filename_completer (struct cmd_list_element *ignore,
       subsequent_name = 1;
       /* Like emacs, don't complete on old versions.  Especially
          useful in the "source" command.  */
+      const char *p = p_rl.get ();
       if (p[strlen (p) - 1] == '~')
-       {
-         xfree (p);
-         continue;
-       }
+       continue;
 
-      if (word == text)
-       /* Return exactly p.  */
-       q = p;
-      else if (word > text)
-       {
-         /* Return some portion of p.  */
-         q = (char *) xmalloc (strlen (p) + 5);
-         strcpy (q, p + (word - text));
-         xfree (p);
-       }
-      else
-       {
-         /* Return some of TEXT plus p.  */
-         q = (char *) xmalloc (strlen (p) + (text - word) + 5);
-         strncpy (q, word, text - word);
-         q[text - word] = '\0';
-         strcat (q, p);
-         xfree (p);
-       }
-      tracker.add_completion (gdb::unique_xmalloc_ptr<char> (q));
+      tracker.add_completion
+       (make_completion_match_str (std::move (p_rl), text, word));
     }
 #if 0
   /* There is no way to do this just long enough to affect quote
@@ -429,7 +407,6 @@ static void
 complete_files_symbols (completion_tracker &tracker,
                        const char *text, const char *word)
 {
-  int ix;
   completion_list fn_list;
   const char *p;
   int quote_found = 0;
@@ -502,6 +479,7 @@ complete_files_symbols (completion_tracker &tracker,
     {
       collect_file_symbol_completion_matches (tracker,
                                              complete_symbol_mode::EXPRESSION,
+                                             symbol_name_match_type::EXPRESSION,
                                              symbol_start, word,
                                              file_to_match);
       xfree (file_to_match);
@@ -512,6 +490,7 @@ complete_files_symbols (completion_tracker &tracker,
 
       collect_symbol_completion_matches (tracker,
                                         complete_symbol_mode::EXPRESSION,
+                                        symbol_name_match_type::EXPRESSION,
                                         symbol_start, word);
       /* If text includes characters which cannot appear in a file
         name, they cannot be asking for completion on files.  */
@@ -522,8 +501,6 @@ complete_files_symbols (completion_tracker &tracker,
 
   if (!fn_list.empty () && !tracker.have_completions ())
     {
-      char *fn;
-
       /* If we only have file names as possible completion, we should
         bring them in sync with what rl_complete expects.  The
         problem is that if the user types "break /foo/b TAB", and the
@@ -554,16 +531,57 @@ complete_files_symbols (completion_tracker &tracker,
         on the entire text as a symbol.  */
       collect_symbol_completion_matches (tracker,
                                         complete_symbol_mode::EXPRESSION,
+                                        symbol_name_match_type::EXPRESSION,
                                         orig_text, word);
     }
 }
 
+/* See completer.h.  */
+
+completion_list
+complete_source_filenames (const char *text)
+{
+  size_t text_len = strlen (text);
+
+  /* If text includes characters which cannot appear in a file name,
+     the user cannot be asking for completion on files.  */
+  if (strcspn (text,
+              gdb_completer_file_name_break_characters)
+      == text_len)
+    return make_source_files_completion_list (text, text);
+
+  return {};
+}
+
+/* Complete address and linespec locations.  */
+
+static void
+complete_address_and_linespec_locations (completion_tracker &tracker,
+                                        const char *text,
+                                        symbol_name_match_type match_type)
+{
+  if (*text == '*')
+    {
+      tracker.advance_custom_word_point_by (1);
+      text++;
+      const char *word
+       = advance_to_expression_complete_word_point (tracker, text);
+      complete_expression (tracker, text, word);
+    }
+  else
+    {
+      linespec_complete (tracker, text, match_type);
+    }
+}
+
 /* The explicit location options.  Note that indexes into this array
    must match the explicit_location_match_type enumerators.  */
+
 static const char *const explicit_options[] =
   {
     "-source",
     "-function",
+    "-qualified",
     "-line",
     "-label",
     NULL
@@ -600,6 +618,9 @@ collect_explicit_location_matches (completion_tracker &tracker,
   const struct explicit_location *explicit_loc
     = get_explicit_location (location);
 
+  /* True if the option expects an argument.  */
+  bool needs_arg = true;
+
   /* Note, in the various MATCH_* below, we complete on
      explicit_loc->foo instead of WORD, because only the former will
      have already skipped past any quote char.  */
@@ -618,23 +639,34 @@ collect_explicit_location_matches (completion_tracker &tracker,
       {
        const char *function = string_or_empty (explicit_loc->function_name);
        linespec_complete_function (tracker, function,
+                                   explicit_loc->func_name_match_type,
                                    explicit_loc->source_filename);
       }
       break;
 
+    case MATCH_QUALIFIED:
+      needs_arg = false;
+      break;
     case MATCH_LINE:
       /* Nothing to offer.  */
       break;
 
     case MATCH_LABEL:
-      /* Not supported.  */
+      {
+       const char *label = string_or_empty (explicit_loc->label_name);
+       linespec_complete_label (tracker, language,
+                                explicit_loc->source_filename,
+                                explicit_loc->function_name,
+                                explicit_loc->func_name_match_type,
+                                label);
+      }
       break;
 
     default:
       gdb_assert_not_reached ("unhandled explicit_location_match_type");
     }
 
-  if (tracker.completes_to_completion_word (word))
+  if (!needs_arg || tracker.completes_to_completion_word (word))
     {
       tracker.discard_completions ();
       tracker.advance_custom_word_point_by (strlen (word));
@@ -658,7 +690,7 @@ collect_explicit_location_matches (completion_tracker &tracker,
             keyword.  */
          if (keyword != word)
            {
-             keyword = skip_spaces_const (keyword);
+             keyword = skip_spaces (keyword);
 
              tracker.advance_custom_word_point_by (keyword - word);
              complete_on_enum (tracker, linespec_keywords, keyword, keyword);
@@ -688,7 +720,7 @@ skip_keyword (completion_tracker &tracker,
              const char * const *keywords, const char **text_p)
 {
   const char *text = *text_p;
-  const char *after = skip_to_space_const (text);
+  const char *after = skip_to_space (text);
   size_t len = after - text;
 
   if (text[len] != ' ')
@@ -795,7 +827,7 @@ complete_explicit_location (completion_tracker &tracker,
 void
 location_completer (struct cmd_list_element *ignore,
                    completion_tracker &tracker,
-                   const char *text, const char *word_entry)
+                   const char *text, const char * /* word */)
 {
   int found_probe_option = -1;
 
@@ -823,7 +855,7 @@ location_completer (struct cmd_list_element *ignore,
       tracker.advance_custom_word_point_by (1);
     }
 
-  if (location != NULL)
+  if (completion_info.saw_explicit_location_option)
     {
       if (*copy != '\0')
        {
@@ -863,31 +895,30 @@ location_completer (struct cmd_list_element *ignore,
 
        }
     }
-  else
+  /* This is an address or linespec location.  */
+  else if (location != NULL)
     {
-      /* This is an address or linespec location.  */
-      if (*text == '*')
-       {
-         tracker.advance_custom_word_point_by (1);
-         text++;
-         const char *word
-           = advance_to_expression_complete_word_point (tracker, text);
-         complete_expression (tracker, text, word);
-       }
+      /* Handle non-explicit location options.  */
+
+      int keyword = skip_keyword (tracker, explicit_options, &text);
+      if (keyword == -1)
+       complete_on_enum (tracker, explicit_options, text, text);
       else
        {
-         /* Fall back to the old linespec completer, for now.  */
-
-         if (word_entry == NULL)
-           {
-            /* We're in the handle_brkchars phase.  */
-             tracker.set_use_custom_word_point (false);
-             return;
-           }
+         tracker.advance_custom_word_point_by (copy - text);
+         text = copy;
 
-         complete_files_symbols (tracker, text, word_entry);
+         symbol_name_match_type match_type
+           = get_explicit_location (location.get ())->func_name_match_type;
+         complete_address_and_linespec_locations (tracker, text, match_type);
        }
     }
+  else
+    {
+      /* No options.  */
+      complete_address_and_linespec_locations (tracker, text,
+                                              symbol_name_match_type::WILD);
+    }
 
   /* Add matches for option names, if either:
 
@@ -978,11 +1009,9 @@ add_struct_fields (struct type *type, completion_list &output,
     }
 }
 
-/* Complete on expressions.  Often this means completing on symbol
-   names, but some language parsers also have support for completing
-   field names.  */
+/* See completer.h.  */
 
-static void
+void
 complete_expression (completion_tracker &tracker,
                     const char *text, const char *word)
 {
@@ -1027,7 +1056,6 @@ complete_expression (completion_tracker &tracker,
     }
   else if (fieldname && code != TYPE_CODE_UNDEF)
     {
-      VEC (char_ptr) *result;
       struct cleanup *cleanup = make_cleanup (xfree, fieldname);
 
       collect_symbol_completion_matches_type (tracker, fieldname, fieldname,
@@ -1085,6 +1113,7 @@ symbol_completer (struct cmd_list_element *ignore,
                  const char *text, const char *word)
 {
   collect_symbol_completion_matches (tracker, complete_symbol_mode::EXPRESSION,
+                                    symbol_name_match_type::EXPRESSION,
                                     text, word);
 }
 
@@ -1247,10 +1276,13 @@ complete_line_internal_1 (completion_tracker &tracker,
       word = tmp_command + point - strlen (text);
     }
 
-  if (point == 0)
+  /* Move P up to the start of the command.  */
+  p = skip_spaces (p);
+
+  if (*p == '\0')
     {
-      /* An empty line we want to consider ambiguous; that is, it
-        could be any command.  */
+      /* An empty line is ambiguous; that is, it could be any
+        command.  */
       c = CMD_LIST_AMBIGUOUS;
       result_list = 0;
     }
@@ -1428,6 +1460,7 @@ complete_line_internal (completion_tracker &tracker,
       if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
        throw_exception (except);
     }
+  END_CATCH
 }
 
 /* See completer.h.  */
@@ -1475,7 +1508,9 @@ completion_tracker::~completion_tracker ()
 /* See completer.h.  */
 
 bool
-completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
+completion_tracker::maybe_add_completion
+  (gdb::unique_xmalloc_ptr<char> name,
+   completion_match_for_lcd *match_for_lcd)
 {
   void **slot;
 
@@ -1488,7 +1523,13 @@ completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
   slot = htab_find_slot (m_entries_hash, name.get (), INSERT);
   if (*slot == HTAB_EMPTY_ENTRY)
     {
-      const char *match_for_lcd_str = name.get ();
+      const char *match_for_lcd_str = NULL;
+
+      if (match_for_lcd != NULL)
+       match_for_lcd_str = match_for_lcd->finish ();
+
+      if (match_for_lcd_str == NULL)
+       match_for_lcd_str = name.get ();
 
       recompute_lowest_common_denominator (match_for_lcd_str);
 
@@ -1502,9 +1543,10 @@ completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
 /* See completer.h.  */
 
 void
-completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name)
+completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name,
+                                   completion_match_for_lcd *match_for_lcd)
 {
-  if (!maybe_add_completion (std::move (name)))
+  if (!maybe_add_completion (std::move (name), match_for_lcd))
     throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
 }
 
@@ -1517,6 +1559,63 @@ completion_tracker::add_completions (completion_list &&list)
     add_completion (std::move (candidate));
 }
 
+/* Helper for the make_completion_match_str overloads.  Returns NULL
+   as an indication that we want MATCH_NAME exactly.  It is up to the
+   caller to xstrdup that string if desired.  */
+
+static char *
+make_completion_match_str_1 (const char *match_name,
+                            const char *text, const char *word)
+{
+  char *newobj;
+
+  if (word == text)
+    {
+      /* Return NULL as an indication that we want MATCH_NAME
+        exactly.  */
+      return NULL;
+    }
+  else if (word > text)
+    {
+      /* Return some portion of MATCH_NAME.  */
+      newobj = xstrdup (match_name + (word - text));
+    }
+  else
+    {
+      /* Return some of WORD plus MATCH_NAME.  */
+      size_t len = strlen (match_name);
+      newobj = (char *) xmalloc (text - word + len + 1);
+      memcpy (newobj, word, text - word);
+      memcpy (newobj + (text - word), match_name, len + 1);
+    }
+
+  return newobj;
+}
+
+/* See completer.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+make_completion_match_str (const char *match_name,
+                          const char *text, const char *word)
+{
+  char *newobj = make_completion_match_str_1 (match_name, text, word);
+  if (newobj == NULL)
+    newobj = xstrdup (match_name);
+  return gdb::unique_xmalloc_ptr<char> (newobj);
+}
+
+/* See completer.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+make_completion_match_str (gdb::unique_xmalloc_ptr<char> &&match_name,
+                          const char *text, const char *word)
+{
+  char *newobj = make_completion_match_str_1 (match_name.get (), text, word);
+  if (newobj == NULL)
+    return std::move (match_name);
+  return gdb::unique_xmalloc_ptr<char> (newobj);
+}
+
 /* Generate completions all at once.  Does nothing if max_completions
    is 0.  If max_completions is non-negative, this will collect at
    most max_completions strings.
@@ -1884,7 +1983,7 @@ expand_preserving_ws (const char *orig, size_t orig_len,
        {
          while (p_orig < orig_end && *p_orig == ' ')
            res += *p_orig++;
-         p_lcd = skip_spaces_const (p_lcd);
+         p_lcd = skip_spaces (p_lcd);
        }
       else
        {
@@ -1938,10 +2037,12 @@ completion_tracker::build_completion_result (const char *text,
                                buf, (char *) NULL);
       match_list[1] = NULL;
 
-      /* If we already have a space at the end of the match, tell
-        readline to skip appending another.  */
+      /* If the tracker wants to, or we already have a space at the
+        end of the match, tell readline to skip appending
+        another.  */
       bool completion_suppress_append
-       = (match_list[0][strlen (match_list[0]) - 1] == ' ');
+       = (suppress_append_ws ()
+          || match_list[0][strlen (match_list[0]) - 1] == ' ');
 
       return completion_result (match_list, 1, completion_suppress_append);
     }
@@ -2005,14 +2106,6 @@ completion_result::release_match_list ()
   return ret;
 }
 
-/* Compare C strings for std::sort.  */
-
-static bool
-compare_cstrings (const char *str1, const char *str2)
-{
-  return strcmp (str1, str2) < 0;
-}
-
 /* See completer.h  */
 
 void
@@ -2762,8 +2855,6 @@ gdb_display_match_list (char **matches, int len, int max,
        }
     }
 }
-\f
-extern initialize_file_ftype _initialize_completer; /* -Wmissing-prototypes */
 
 void
 _initialize_completer (void)
This page took 0.029923 seconds and 4 git commands to generate.