Explicit locations -label completer
authorPedro Alves <palves@redhat.com>
Mon, 17 Jul 2017 19:24:41 +0000 (20:24 +0100)
committerPedro Alves <palves@redhat.com>
Mon, 17 Jul 2017 19:24:41 +0000 (20:24 +0100)
We're missing a completer for

  (gdb) break -function func -label [TAB]

This patch adds one.  Tests will be added later in the series.

gdb/ChangeLog:
2017-07-17  Pedro Alves  <palves@redhat.com>

* completer.c (collect_explicit_location_matches): Handle
MATCH_LABEL.
(convert_explicit_location_to_linespec): New, factored out from
...
(convert_explicit_location_to_sals): ... this.
(complete_label): New.
(linespec_complete_label, find_label_symbols_in_block): New.
(find_label_symbols): Add completion_mode parameter and adjust to
call find_label_symbols_in_block.
* linespec.h (linespec_complete_label): Declare.

gdb/ChangeLog
gdb/completer.c
gdb/linespec.c
gdb/linespec.h

index b341eb1..acf0b51 100644 (file)
@@ -1,5 +1,18 @@
 2017-07-17  Pedro Alves  <palves@redhat.com>
 
+       * completer.c (collect_explicit_location_matches): Handle
+       MATCH_LABEL.
+       (convert_explicit_location_to_linespec): New, factored out from
+       ...
+       (convert_explicit_location_to_sals): ... this.
+       (complete_label): New.
+       (linespec_complete_label, find_label_symbols_in_block): New.
+       (find_label_symbols): Add completion_mode parameter and adjust to
+       call find_label_symbols_in_block.
+       * linespec.h (linespec_complete_label): Declare.
+
+2017-07-17  Pedro Alves  <palves@redhat.com>
+
        * ada-lang.c (ada_collect_symbol_completion_matches): Add
        complete_symbol_mode parameter.
        * cli/cli-cmds.c (complete_command): Get the completion result out
index 1e4fe18..c2bb4ee 100644 (file)
@@ -627,7 +627,13 @@ collect_explicit_location_matches (completion_tracker &tracker,
       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,
+                                label);
+      }
       break;
 
     default:
index 20ac71d..0216bf1 100644 (file)
@@ -299,7 +299,8 @@ static VEC (symtab_ptr) *symtabs_from_filename (const char *,
 static VEC (symbolp) *find_label_symbols (struct linespec_state *self,
                                          VEC (symbolp) *function_symbols,
                                          VEC (symbolp) **label_funcs_ret,
-                                         const char *name);
+                                         const char *name,
+                                         bool completion_mode = false);
 
 static void find_linespec_symbols (struct linespec_state *self,
                                   VEC (symtab_ptr) *file_symtabs,
@@ -2053,31 +2054,33 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
   return sals;
 }
 
-/* Convert the explicit location EXPLICIT_LOC into SaLs.  */
+/* Build RESULT from the explicit location components SOURCE_FILENAME,
+   FUNCTION_NAME, LABEL_NAME and LINE_OFFSET.  */
 
-static struct symtabs_and_lines
-convert_explicit_location_to_sals (struct linespec_state *self,
-                                  linespec_p result,
-                                  const struct explicit_location *explicit_loc)
+static void
+convert_explicit_location_to_linespec (struct linespec_state *self,
+                                      linespec_p result,
+                                      const char *source_filename,
+                                      const char *function_name,
+                                      const char *label_name,
+                                      struct line_offset line_offset)
 {
   VEC (symbolp) *symbols, *labels;
   VEC (bound_minimal_symbol_d) *minimal_symbols;
 
-  if (explicit_loc->source_filename != NULL)
+  if (source_filename != NULL)
     {
       TRY
        {
          result->file_symtabs
-           = symtabs_from_filename (explicit_loc->source_filename,
-                                    self->search_pspace);
+           = symtabs_from_filename (source_filename, self->search_pspace);
        }
       CATCH (except, RETURN_MASK_ERROR)
        {
-         source_file_not_found_error (explicit_loc->source_filename);
+         source_file_not_found_error (source_filename);
        }
       END_CATCH
-      result->explicit_loc.source_filename
-       = xstrdup (explicit_loc->source_filename);
+      result->explicit_loc.source_filename = xstrdup (source_filename);
     }
   else
     {
@@ -2085,41 +2088,53 @@ convert_explicit_location_to_sals (struct linespec_state *self,
       VEC_safe_push (symtab_ptr, result->file_symtabs, NULL);
     }
 
-  if (explicit_loc->function_name != NULL)
+  if (function_name != NULL)
     {
       find_linespec_symbols (self, result->file_symtabs,
-                            explicit_loc->function_name, &symbols,
+                            function_name, &symbols,
                             &minimal_symbols);
 
       if (symbols == NULL && minimal_symbols == NULL)
-       symbol_not_found_error (explicit_loc->function_name,
+       symbol_not_found_error (function_name,
                                result->explicit_loc.source_filename);
 
-      result->explicit_loc.function_name
-       = xstrdup (explicit_loc->function_name);
+      result->explicit_loc.function_name = xstrdup (function_name);
       result->function_symbols = symbols;
       result->minimal_symbols = minimal_symbols;
     }
 
-  if (explicit_loc->label_name != NULL)
+  if (label_name != NULL)
     {
       symbols = NULL;
       labels = find_label_symbols (self, result->function_symbols,
-                                  &symbols, explicit_loc->label_name);
+                                  &symbols, label_name);
 
       if (labels == NULL)
        undefined_label_error (result->explicit_loc.function_name,
-                              explicit_loc->label_name);
+                              label_name);
 
-      result->explicit_loc.label_name = xstrdup (explicit_loc->label_name);
+      result->explicit_loc.label_name = xstrdup (label_name);
       result->labels.label_symbols = labels;
       result->labels.function_symbols = symbols;
     }
 
-  if (explicit_loc->line_offset.sign != LINE_OFFSET_UNKNOWN)
-    result->explicit_loc.line_offset = explicit_loc->line_offset;
+  if (line_offset.sign != LINE_OFFSET_UNKNOWN)
+    result->explicit_loc.line_offset = line_offset;
+}
 
-   return convert_linespec_to_sals (self, result);
+/* Convert the explicit location EXPLICIT_LOC into SaLs.  */
+
+static struct symtabs_and_lines
+convert_explicit_location_to_sals (struct linespec_state *self,
+                                  linespec_p result,
+                                  const struct explicit_location *explicit_loc)
+{
+  convert_explicit_location_to_linespec (self, result,
+                                        explicit_loc->source_filename,
+                                        explicit_loc->function_name,
+                                        explicit_loc->label_name,
+                                        explicit_loc->line_offset);
+  return convert_linespec_to_sals (self, result);
 }
 
 /* Parse a string that specifies a linespec.
@@ -2470,6 +2485,69 @@ linespec_complete_function (completion_tracker &tracker,
     collect_symbol_completion_matches (tracker, mode, function, function);
 }
 
+/* Helper for linespec_complete_label.  Find labels that match
+   LABEL_NAME in the function symbols listed in the PARSER, and add
+   them to the tracker.  */
+
+static void
+complete_label (completion_tracker &tracker,
+               linespec_parser *parser,
+               const char *label_name)
+{
+  VEC (symbolp) *label_function_symbols = NULL;
+  VEC (symbolp) *labels
+    = find_label_symbols (PARSER_STATE (parser),
+                         PARSER_RESULT (parser)->function_symbols,
+                         &label_function_symbols,
+                         label_name, true);
+
+  symbol *label;
+  for (int ix = 0;
+       VEC_iterate (symbolp, labels, ix, label); ++ix)
+    {
+      char *match = xstrdup (SYMBOL_SEARCH_NAME (label));
+      tracker.add_completion (gdb::unique_xmalloc_ptr<char> (match));
+    }
+  VEC_free (symbolp, labels);
+}
+
+/* See linespec.h.  */
+
+void
+linespec_complete_label (completion_tracker &tracker,
+                        const struct language_defn *language,
+                        const char *source_filename,
+                        const char *function_name,
+                        const char *label_name)
+{
+  linespec_parser parser;
+  struct cleanup *cleanup;
+
+  linespec_parser_new (&parser, 0, language, NULL, NULL, 0, NULL);
+  cleanup = make_cleanup (linespec_parser_delete, &parser);
+
+  line_offset unknown_offset = { 0, LINE_OFFSET_UNKNOWN };
+
+  TRY
+    {
+      convert_explicit_location_to_linespec (PARSER_STATE (&parser),
+                                            PARSER_RESULT (&parser),
+                                            source_filename,
+                                            function_name,
+                                            NULL, unknown_offset);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      do_cleanups (cleanup);
+      return;
+    }
+  END_CATCH
+
+  complete_label (tracker, &parser, label_name);
+
+  do_cleanups (cleanup);
+}
+
 /* A helper function for decode_line_full and decode_line_1 to
    turn LOCATION into symtabs_and_lines.  */
 
@@ -3385,13 +3463,63 @@ find_linespec_symbols (struct linespec_state *state,
     }
 }
 
-/* Return all labels named NAME in FUNCTION_SYMBOLS.  Return the
-   actual function symbol in which the label was found in LABEL_FUNC_RET.  */
+/* Helper for find_label_symbols.  Find all labels that match name
+   NAME in BLOCK.  Return all labels that match in FUNCTION_SYMBOLS.
+   Return the actual function symbol in which the label was found in
+   LABEL_FUNC_RET.  If COMPLETION_MODE is true, then NAME is
+   interpreted as a label name prefix.  Otherwise, only a label named
+   exactly NAME match.  */
+
+static void
+find_label_symbols_in_block (const struct block *block,
+                            const char *name, struct symbol *fn_sym,
+                            bool completion_mode,
+                            VEC (symbolp) **result,
+                            VEC (symbolp) **label_funcs_ret)
+{
+  if (completion_mode)
+    {
+      struct block_iterator iter;
+      struct symbol *sym;
+      size_t name_len = strlen (name);
+
+      int (*cmp) (const char *, const char *, size_t);
+      cmp = case_sensitivity == case_sensitive_on ? strncmp : strncasecmp;
+
+      ALL_BLOCK_SYMBOLS (block, iter, sym)
+       {
+         if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+                                    SYMBOL_DOMAIN (sym), LABEL_DOMAIN)
+             && cmp (SYMBOL_SEARCH_NAME (sym), name, name_len) == 0)
+           {
+             VEC_safe_push (symbolp, *result, sym);
+             VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
+           }
+       }
+    }
+  else
+    {
+      struct symbol *sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol;
+
+      if (sym != NULL)
+       {
+         VEC_safe_push (symbolp, *result, sym);
+         VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
+       }
+    }
+}
+
+/* Return all labels that match name NAME in FUNCTION_SYMBOLS.  Return
+   the actual function symbol in which the label was found in
+   LABEL_FUNC_RET.  If COMPLETION_MODE is true, then NAME is
+   interpreted as a label name prefix.  Otherwise, only labels named
+   exactly NAME match.  */
 
 static VEC (symbolp) *
 find_label_symbols (struct linespec_state *self,
                    VEC (symbolp) *function_symbols,
-                   VEC (symbolp) **label_funcs_ret, const char *name)
+                   VEC (symbolp) **label_funcs_ret, const char *name,
+                   bool completion_mode)
 {
   int ix;
   const struct block *block;
@@ -3412,13 +3540,8 @@ find_label_symbols (struct linespec_state *self,
        return NULL;
       fn_sym = BLOCK_FUNCTION (block);
 
-      sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol;
-
-      if (sym != NULL)
-       {
-         VEC_safe_push (symbolp, result, sym);
-         VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
-       }
+      find_label_symbols_in_block (block, name, fn_sym, completion_mode,
+                                  &result, label_funcs_ret);
     }
   else
     {
@@ -3427,13 +3550,9 @@ find_label_symbols (struct linespec_state *self,
        {
          set_current_program_space (SYMTAB_PSPACE (symbol_symtab (fn_sym)));
          block = SYMBOL_BLOCK_VALUE (fn_sym);
-         sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol;
 
-         if (sym != NULL)
-           {
-             VEC_safe_push (symbolp, result, sym);
-             VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
-           }
+         find_label_symbols_in_block (block, name, fn_sym, completion_mode,
+                                      &result, label_funcs_ret);
        }
     }
 
index d55ba12..f16bb81 100644 (file)
@@ -194,6 +194,17 @@ extern void linespec_complete_function (completion_tracker &tracker,
                                        const char *function,
                                        const char *source_filename);
 
+/* Complete a label symbol, in linespec mode.  Only labels of
+   functions named FUNCTION_NAME are considered.  If SOURCE_FILENAME
+   is non-NULL, limits completion to labels of functions defined in
+   source files that match SOURCE_FILENAME.  */
+
+extern void linespec_complete_label (completion_tracker &tracker,
+                                    const struct language_defn *language,
+                                    const char *source_filename,
+                                    const char *function_name,
+                                    const char *label_name);
+
 /* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR,
    advancing EXP_PTR past any parsed text.  */