Introduce class completion_tracker & rewrite completion<->readline interaction
authorPedro Alves <palves@redhat.com>
Mon, 17 Jul 2017 13:45:59 +0000 (14:45 +0100)
committerPedro Alves <palves@redhat.com>
Mon, 17 Jul 2017 13:45:59 +0000 (14:45 +0100)
This patch reworks the whole completion machinery, and prepares it
for later enhancements.

Adds a new "completion_tracker" class that is meant to hold everything
about the state of the current completion operation.

This class now has the responsibility of tracking the list of
completion matches, and checking whether the max completions limit has
been reached.  You can look at this as this patch starting out by
C++fying the existing "completion_tracker" in symtab.c (it's just an
htab_t typedef currently), moving it to completer.h/c, and then making
it a class/generalizing/enhancing it.

Unlike with the current tracking, completion_tracker now checks
whether the limit has been reached on each completion match list
insertion.  This both simplifies the max-completions handling code
(maybe_add_completion_enum is gone, for example), and is a
prerequisite for follow up patches.

The current completion_tracker is only used for symbol completions,
and the symbol code gets at the current instance via globals.  This
patch cleans that up by adding a completion_tracker reference to the
signature of the completion functions, and passing the tracker around
everywhere necessary.

Then, the patch changes how the completion match list is handed over
to readline.  Currently, we're using the rl_completion_entry_function
readline entry point, and the patch switches to
rl_attempted_completion_function.  A following patch will want to let
GDB itself decide the common completion prefix between all matches
(what readline calls the "lowest common denominator"), instead of
having readline compute it, and that's not possible with the
rl_completion_entry_function entry point.  Also,
rl_attempted_completion_function lets GDB hand over the match list to
readline as an array in one go instead of passing down matches one by
one, so from that angle it's a nicer entry point anyway.

Lastly, the patch catches exceptions around the readline entry points,
because we can't let C++ exceptions cross readline.  We handle that in
the readline input entry point, but the completion entry point isn't
guarded, so GDB can abort if completion throws.  E.g., in current
master:

 (gdb) b -function "fun<tab>
 terminate called after throwing an instance of 'gdb_exception_RETURN_MASK_ERROR'
 Aborted (core dumped)

This patch fixes that.  This will be exercised in the new tests added
later on in the series.

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

* ada-lang.c (symbol_completion_match): Adjust comments.
(symbol_completion_add): Replace vector parameter with
completion_tracker parameter.  Use it.
(ada_make_symbol_completion_list): Rename to...
(ada_collect_symbol_completion_matches): ... this.  Add
completion_tracker parameter and use it.
(ada_language_defn): Adjust.
* break-catch-syscall.c (catch_syscall_completer): Adjust
prototype and work with completion_tracker instead of VEC.
* breakpoint.c (condition_completer): Adjust prototype and work
with completion_tracker instead of VEC.
* c-lang.c (c_language_defn, cplus_language_defn)
(asm_language_defn, minimal_language_defn): Adjust to renames.
* cli/cli-cmds.c (complete_command): Rework using
completion_tracker.  Catch exceptions when completing.
* cli/cli-decode.c (integer_unlimited_completer)
(complete_on_cmdlist, complete_on_enum): Adjust prototype and work
with completion_tracker instead of VEC.
* command.h (struct completion_tracker): Forward declare.
(completer_ftype, completer_handle_brkchars_ftype): Change
types.
(complete_on_cmdlist, complete_on_enum): Adjust.
* completer.c: Include <algorithm>.
(struct gdb_completer_state): New.
(current_completion): New global.
(readline_line_completion_function): Delete.
(noop_completer, filename_completer)
(filename_completer_handle_brkchars, complete_files_symbols)
(linespec_location_completer): Adjust to work with a
completion_tracker instead of a VEC.
(string_or_empty): New.
(collect_explicit_location_matches): Adjust to work with a
completion_tracker instead of a VEC.
(explicit_location_completer): Rename to ...
(complete_explicit_location): ... this and adjust to work with a
completion_tracker instead of a VEC.
(location_completer): Adjust to work with a completion_tracker
instead of a VEC.
(add_struct_fields): Adjust to work with a completion_list instead
of VEC.
(expression_completer): Rename to ...
(complete_expression): ... this and adjust to work with a
completion_tracker instead of a VEC.  Use complete_files_symbols.
(expression_completer): Reimplement on top of complete_expression.
(symbol_completer): Adjust to work with a completion_tracker
instead of a VEC.
(enum complete_line_internal_reason): Add describing comments.
(complete_line_internal_normal_command): Adjust to work with a
completion_tracker instead of a VEC.
(complete_line_internal): Rename to ...
(complete_line_internal_1): ... this and adjust to work with a
completion_tracker instead of a VEC.  Assert TEXT is NULL in the
handle_brkchars phase.
(new_completion_tracker): Delete.
(complete_line_internal): Reimplement as TRY/CATCH wrapper around
complete_line_internal_1.
(free_completion_tracker): Delete.
(INITIAL_COMPLETION_HTAB_SIZE): New.
(completion_tracker::completion_tracker)
(completion_tracker::~completion_tracker): New.
(maybe_add_completion): Delete.
(completion_tracker::maybe_add_completion)
(completion_tracker::add_completion)
(completion_tracker::add_completions): New.
(throw_max_completions_reached_error): Delete.
(complete_line): Adjust to work with a completion_tracker instead
of a VEC.  Don't create a completion_tracker_t or check for max
completions here.
(command_completer, command_completer_handle_brkchars)
(signal_completer, reg_or_group_completer_1)
(reg_or_group_completer, default_completer_handle_brkchars):
Adjust to work with a completion_tracker.
(gdb_completion_word_break_characters_throw): New.
(gdb_completion_word_break_characters): Reimplement.
(line_completion_function): Delete.
(completion_tracker::recompute_lowest_common_denominator)
(expand_preserving_ws)
(completion_tracker::build_completion_result)
(completion_result::completion_result)
(completion_result::completion_result)
(completion_result::~completion_result)
(completion_result::completion_result)
(completion_result::release_match_list, compare_cstrings)
(completion_result::sort_match_list)
(completion_result::reset_match_list)
(gdb_rl_attempted_completion_function_throw)
(gdb_rl_attempted_completion_function): New.
* completer.h (completion_list, struct completion_result)
(class completion_tracker): New.
(complete_line): Add completion_tracker parameter.
(readline_line_completion_function): Delete.
(gdb_rl_attempted_completion_function): New.
(noop_completer, filename_completer, expression_completer)
(location_completer, symbol_completer, command_completer)
(signal_completer, reg_or_group_completer): Update prototypes.
(completion_tracker_t, new_completion_tracker)
(make_cleanup_free_completion_tracker): Delete.
(enum maybe_add_completion_enum): Delete.
(maybe_add_completion): Delete.
(throw_max_completions_reached_error): Delete.
* corefile.c (complete_set_gnutarget): Adjust to work with a
completion_tracker instead of a VEC.
* cp-abi.c (cp_abi_completer): Adjust to work with a
completion_tracker instead of a VEC.
* d-lang.c (d_language_defn): Adjust.
* disasm.c (disassembler_options_completer): Adjust to work with a
completion_tracker instead of a VEC.
* f-lang.c (f_make_symbol_completion_list): Rename to ...
(f_collect_symbol_completion_matches): ... this.  Adjust to work
with a completion_tracker instead of a VEC.
(f_language_defn): Adjust.
* go-lang.c (go_language_defn): Adjust.
* guile/scm-cmd.c (cmdscm_add_completion, cmdscm_completer):
Adjust to work with a completion_tracker instead of a VEC.
* infrun.c (handle_completer): Likewise.
* interps.c (interpreter_completer): Likewise.
* interps.h (interpreter_completer): Likewise.
* language.c (unknown_language_defn, auto_language_defn)
(local_language_defn): Adjust.
* language.h (language_defn::la_make_symbol_completion_list):
Rename to ...
(language_defn::la_collect_symbol_completion_matches): ... this
and adjust to work with a completion_tracker instead of a VEC.
* m2-lang.c (m2_language_defn): Adjust.
* objc-lang.c (objc_language_defn): Adjust.
* opencl-lang.c (opencl_language_defn): Adjust.
* p-lang.c (pascal_language_defn): Adjust.
* python/py-cmd.c (cmdpy_completer_helper): Handle NULL word.
(cmdpy_completer_handle_brkchars, cmdpy_completer): Adjust to work
with a completion_tracker.
* rust-lang.c (rust_language_defn): Adjust.
* symtab.c (free_completion_list, do_free_completion_list)
(return_val, completion_tracker): Delete.
(completion_list_add_name, completion_list_add_symbol)
(completion_list_add_msymbol, completion_list_objc_symbol)
(completion_list_add_fields, add_symtab_completions): Add
completion_tracker parameter and use it.
(default_make_symbol_completion_list_break_on_1): Rename to...
(default_collect_symbol_completion_matches_break_on): ... this.
Add completion_tracker parameter and use it instead of allocating
a completion tracker here.
(default_make_symbol_completion_list_break_on): Delete old
implementation.
(default_make_symbol_completion_list): Delete.
(default_collect_symbol_completion_matches): New.
(make_symbol_completion_list): Delete.
(collect_symbol_completion_matches): New.
(make_symbol_completion_type): Rename to ...
(collect_symbol_completion_matches_type): ... this.  Add
completion_tracker parameter and use it instead of VEC.
(make_file_symbol_completion_list_1): Rename to...
(collect_file_symbol_completion_matches): ... this.  Add
completion_tracker parameter and use it instead of VEC.
(make_file_symbol_completion_list): Delete.
(add_filename_to_list): Use completion_list instead of a VEC.
(add_partial_filename_data::list): Now a completion_list.
(make_source_files_completion_list): Work with a completion_list
instead of a VEC.
* symtab.h: Include "completer.h".
(default_make_symbol_completion_list_break_on)
(default_make_symbol_completion_list, make_symbol_completion_list)
(make_symbol_completion_type, make_file_symbol_completion_list)
(make_source_files_completion_list): Delete.
(default_collect_symbol_completion_matches_break_on)
(default_collect_symbol_completion_matches)
(collect_symbol_completion_matches)
(collect_symbol_completion_matches_type)
(collect_file_symbol_completion_matches)
(make_source_files_completion_list): New.
* top.c (init_main): Don't install a rl_completion_entry_function
hook.  Install a rl_attempted_completion_function hook instead.
* tui/tui-layout.c (layout_completer): Adjust to work with a
completion_tracker.
* tui/tui-regs.c (tui_reggroup_completer):
* tui/tui-win.c (window_name_completer, focus_completer)
(winheight_completer): Adjust to work with a completion_tracker.
* value.c: Include "completer.h".
(complete_internalvar): Adjust to work with a completion_tracker.
* value.h (complete_internalvar): Likewise.

36 files changed:
gdb/ChangeLog
gdb/ada-lang.c
gdb/break-catch-syscall.c
gdb/breakpoint.c
gdb/c-lang.c
gdb/cli/cli-cmds.c
gdb/cli/cli-decode.c
gdb/command.h
gdb/completer.c
gdb/completer.h
gdb/corefile.c
gdb/cp-abi.c
gdb/d-lang.c
gdb/disasm.c
gdb/f-lang.c
gdb/go-lang.c
gdb/guile/scm-cmd.c
gdb/infrun.c
gdb/interps.c
gdb/interps.h
gdb/language.c
gdb/language.h
gdb/m2-lang.c
gdb/objc-lang.c
gdb/opencl-lang.c
gdb/p-lang.c
gdb/python/py-cmd.c
gdb/rust-lang.c
gdb/symtab.c
gdb/symtab.h
gdb/top.c
gdb/tui/tui-layout.c
gdb/tui/tui-regs.c
gdb/tui/tui-win.c
gdb/value.c
gdb/value.h

index 14391011fe26d181567121c5c5bffc4138946d40..2ab9a4aef163a89e893cc2438bdf61092862b660 100644 (file)
@@ -1,3 +1,185 @@
+2017-07-17  Pedro Alves  <palves@redhat.com>
+
+       * ada-lang.c (symbol_completion_match): Adjust comments.
+       (symbol_completion_add): Replace vector parameter with
+       completion_tracker parameter.  Use it.
+       (ada_make_symbol_completion_list): Rename to...
+       (ada_collect_symbol_completion_matches): ... this.  Add
+       completion_tracker parameter and use it.
+       (ada_language_defn): Adjust.
+       * break-catch-syscall.c (catch_syscall_completer): Adjust
+       prototype and work with completion_tracker instead of VEC.
+       * breakpoint.c (condition_completer): Adjust prototype and work
+       with completion_tracker instead of VEC.
+       * c-lang.c (c_language_defn, cplus_language_defn)
+       (asm_language_defn, minimal_language_defn): Adjust to renames.
+       * cli/cli-cmds.c (complete_command): Rework using
+       completion_tracker.  Catch exceptions when completing.
+       * cli/cli-decode.c (integer_unlimited_completer)
+       (complete_on_cmdlist, complete_on_enum): Adjust prototype and work
+       with completion_tracker instead of VEC.
+       * command.h (struct completion_tracker): Forward declare.
+       (completer_ftype, completer_handle_brkchars_ftype): Change
+       types.
+       (complete_on_cmdlist, complete_on_enum): Adjust.
+       * completer.c: Include <algorithm>.
+       (struct gdb_completer_state): New.
+       (current_completion): New global.
+       (readline_line_completion_function): Delete.
+       (noop_completer, filename_completer)
+       (filename_completer_handle_brkchars, complete_files_symbols)
+       (linespec_location_completer): Adjust to work with a
+       completion_tracker instead of a VEC.
+       (string_or_empty): New.
+       (collect_explicit_location_matches): Adjust to work with a
+       completion_tracker instead of a VEC.
+       (explicit_location_completer): Rename to ...
+       (complete_explicit_location): ... this and adjust to work with a
+       completion_tracker instead of a VEC.
+       (location_completer): Adjust to work with a completion_tracker
+       instead of a VEC.
+       (add_struct_fields): Adjust to work with a completion_list instead
+       of VEC.
+       (expression_completer): Rename to ...
+       (complete_expression): ... this and adjust to work with a
+       completion_tracker instead of a VEC.  Use complete_files_symbols.
+       (expression_completer): Reimplement on top of complete_expression.
+       (symbol_completer): Adjust to work with a completion_tracker
+       instead of a VEC.
+       (enum complete_line_internal_reason): Add describing comments.
+       (complete_line_internal_normal_command): Adjust to work with a
+       completion_tracker instead of a VEC.
+       (complete_line_internal): Rename to ...
+       (complete_line_internal_1): ... this and adjust to work with a
+       completion_tracker instead of a VEC.  Assert TEXT is NULL in the
+       handle_brkchars phase.
+       (new_completion_tracker): Delete.
+       (complete_line_internal): Reimplement as TRY/CATCH wrapper around
+       complete_line_internal_1.
+       (free_completion_tracker): Delete.
+       (INITIAL_COMPLETION_HTAB_SIZE): New.
+       (completion_tracker::completion_tracker)
+       (completion_tracker::~completion_tracker): New.
+       (maybe_add_completion): Delete.
+       (completion_tracker::maybe_add_completion)
+       (completion_tracker::add_completion)
+       (completion_tracker::add_completions): New.
+       (throw_max_completions_reached_error): Delete.
+       (complete_line): Adjust to work with a completion_tracker instead
+       of a VEC.  Don't create a completion_tracker_t or check for max
+       completions here.
+       (command_completer, command_completer_handle_brkchars)
+       (signal_completer, reg_or_group_completer_1)
+       (reg_or_group_completer, default_completer_handle_brkchars):
+       Adjust to work with a completion_tracker.
+       (gdb_completion_word_break_characters_throw): New.
+       (gdb_completion_word_break_characters): Reimplement.
+       (line_completion_function): Delete.
+       (completion_tracker::recompute_lowest_common_denominator)
+       (expand_preserving_ws)
+       (completion_tracker::build_completion_result)
+       (completion_result::completion_result)
+       (completion_result::completion_result)
+       (completion_result::~completion_result)
+       (completion_result::completion_result)
+       (completion_result::release_match_list, compare_cstrings)
+       (completion_result::sort_match_list)
+       (completion_result::reset_match_list)
+       (gdb_rl_attempted_completion_function_throw)
+       (gdb_rl_attempted_completion_function): New.
+       * completer.h (completion_list, struct completion_result)
+       (class completion_tracker): New.
+       (complete_line): Add completion_tracker parameter.
+       (readline_line_completion_function): Delete.
+       (gdb_rl_attempted_completion_function): New.
+       (noop_completer, filename_completer, expression_completer)
+       (location_completer, symbol_completer, command_completer)
+       (signal_completer, reg_or_group_completer): Update prototypes.
+       (completion_tracker_t, new_completion_tracker)
+       (make_cleanup_free_completion_tracker): Delete.
+       (enum maybe_add_completion_enum): Delete.
+       (maybe_add_completion): Delete.
+       (throw_max_completions_reached_error): Delete.
+       * corefile.c (complete_set_gnutarget): Adjust to work with a
+       completion_tracker instead of a VEC.
+       * cp-abi.c (cp_abi_completer): Adjust to work with a
+       completion_tracker instead of a VEC.
+       * d-lang.c (d_language_defn): Adjust.
+       * disasm.c (disassembler_options_completer): Adjust to work with a
+       completion_tracker instead of a VEC.
+       * f-lang.c (f_make_symbol_completion_list): Rename to ...
+       (f_collect_symbol_completion_matches): ... this.  Adjust to work
+       with a completion_tracker instead of a VEC.
+       (f_language_defn): Adjust.
+       * go-lang.c (go_language_defn): Adjust.
+       * guile/scm-cmd.c (cmdscm_add_completion, cmdscm_completer):
+       Adjust to work with a completion_tracker instead of a VEC.
+       * infrun.c (handle_completer): Likewise.
+       * interps.c (interpreter_completer): Likewise.
+       * interps.h (interpreter_completer): Likewise.
+       * language.c (unknown_language_defn, auto_language_defn)
+       (local_language_defn): Adjust.
+       * language.h (language_defn::la_make_symbol_completion_list):
+       Rename to ...
+       (language_defn::la_collect_symbol_completion_matches): ... this
+       and adjust to work with a completion_tracker instead of a VEC.
+       * m2-lang.c (m2_language_defn): Adjust.
+       * objc-lang.c (objc_language_defn): Adjust.
+       * opencl-lang.c (opencl_language_defn): Adjust.
+       * p-lang.c (pascal_language_defn): Adjust.
+       * python/py-cmd.c (cmdpy_completer_helper): Handle NULL word.
+       (cmdpy_completer_handle_brkchars, cmdpy_completer): Adjust to work
+       with a completion_tracker.
+       * rust-lang.c (rust_language_defn): Adjust.
+       * symtab.c (free_completion_list, do_free_completion_list)
+       (return_val, completion_tracker): Delete.
+       (completion_list_add_name, completion_list_add_symbol)
+       (completion_list_add_msymbol, completion_list_objc_symbol)
+       (completion_list_add_fields, add_symtab_completions): Add
+       completion_tracker parameter and use it.
+       (default_make_symbol_completion_list_break_on_1): Rename to...
+       (default_collect_symbol_completion_matches_break_on): ... this.
+       Add completion_tracker parameter and use it instead of allocating
+       a completion tracker here.
+       (default_make_symbol_completion_list_break_on): Delete old
+       implementation.
+       (default_make_symbol_completion_list): Delete.
+       (default_collect_symbol_completion_matches): New.
+       (make_symbol_completion_list): Delete.
+       (collect_symbol_completion_matches): New.
+       (make_symbol_completion_type): Rename to ...
+       (collect_symbol_completion_matches_type): ... this.  Add
+       completion_tracker parameter and use it instead of VEC.
+       (make_file_symbol_completion_list_1): Rename to...
+       (collect_file_symbol_completion_matches): ... this.  Add
+       completion_tracker parameter and use it instead of VEC.
+       (make_file_symbol_completion_list): Delete.
+       (add_filename_to_list): Use completion_list instead of a VEC.
+       (add_partial_filename_data::list): Now a completion_list.
+       (make_source_files_completion_list): Work with a completion_list
+       instead of a VEC.
+       * symtab.h: Include "completer.h".
+       (default_make_symbol_completion_list_break_on)
+       (default_make_symbol_completion_list, make_symbol_completion_list)
+       (make_symbol_completion_type, make_file_symbol_completion_list)
+       (make_source_files_completion_list): Delete.
+       (default_collect_symbol_completion_matches_break_on)
+       (default_collect_symbol_completion_matches)
+       (collect_symbol_completion_matches)
+       (collect_symbol_completion_matches_type)
+       (collect_file_symbol_completion_matches)
+       (make_source_files_completion_list): New.
+       * top.c (init_main): Don't install a rl_completion_entry_function
+       hook.  Install a rl_attempted_completion_function hook instead.
+       * tui/tui-layout.c (layout_completer): Adjust to work with a
+       completion_tracker.
+       * tui/tui-regs.c (tui_reggroup_completer):
+       * tui/tui-win.c (window_name_completer, focus_completer)
+       (winheight_completer): Adjust to work with a completion_tracker.
+       * value.c: Include "completer.h".
+       (complete_internalvar): Adjust to work with a completion_tracker.
+       * value.h (complete_internalvar): Likewise.
+
 2017-07-17  Pedro Alves  <palves@redhat.com>
 
        * cli/cli-decode.c (set_cmd_completer_handle_brkchars): Adjust to
index ea60df20e7cd37b770c0bd311ac4532015b24059..e629902c2edd158bed7a35c97955721970ab987e 100644 (file)
@@ -6440,10 +6440,10 @@ symbol_completion_match (const char *sym_name,
   return sym_name;
 }
 
-/* A companion function to ada_make_symbol_completion_list().
+/* A companion function to ada_collect_symbol_completion_matches().
    Check if SYM_NAME represents a symbol which name would be suitable
-   to complete TEXT (TEXT_LEN is the length of TEXT), in which case
-   it is appended at the end of the given string vector SV.
+   to complete TEXT (TEXT_LEN is the length of TEXT), in which case it
+   is added as a completion match to TRACKER.
 
    ORIG_TEXT is the string original string from the user command
    that needs to be completed.  WORD is the entire command on which
@@ -6456,8 +6456,8 @@ symbol_completion_match (const char *sym_name,
    encoded).  */
 
 static void
-symbol_completion_add (VEC(char_ptr) **sv,
-                       const char *sym_name,
+symbol_completion_add (completion_tracker &tracker,
+                      const char *sym_name,
                        const char *text, int text_len,
                        const char *orig_text, const char *word,
                        int wild_match_p, int encoded_p)
@@ -6492,21 +6492,21 @@ symbol_completion_add (VEC(char_ptr) **sv,
       strcat (completion, match);
     }
 
-  VEC_safe_push (char_ptr, *sv, completion);
+  tracker.add_completion (gdb::unique_xmalloc_ptr<char> (completion));
 }
 
-/* Return a list of possible symbol names completing TEXT0.  WORD is
-   the entire command on which completion is made.  */
+/* Add the list of possible symbol names completing TEXT0 to TRACKER.
+   WORD is the entire command on which completion is made.  */
 
-static VEC (char_ptr) *
-ada_make_symbol_completion_list (const char *text0, const char *word,
-                                enum type_code code)
+static void
+ada_collect_symbol_completion_matches (completion_tracker &tracker,
+                                      const char *text0, const char *word,
+                                      enum type_code code)
 {
   char *text;
   int text_len;
   int wild_match_p;
   int encoded_p;
-  VEC(char_ptr) *completions = VEC_alloc (char_ptr, 128);
   struct symbol *sym;
   struct compunit_symtab *s;
   struct minimal_symbol *msymbol;
@@ -6562,7 +6562,7 @@ ada_make_symbol_completion_list (const char *text0, const char *word,
   ALL_MSYMBOLS (objfile, msymbol)
   {
     QUIT;
-    symbol_completion_add (&completions, MSYMBOL_LINKAGE_NAME (msymbol),
+    symbol_completion_add (tracker, MSYMBOL_LINKAGE_NAME (msymbol),
                           text, text_len, text0, word, wild_match_p,
                           encoded_p);
   }
@@ -6577,7 +6577,7 @@ ada_make_symbol_completion_list (const char *text0, const char *word,
 
       ALL_BLOCK_SYMBOLS (b, iter, sym)
       {
-        symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (sym),
+       symbol_completion_add (tracker, SYMBOL_LINKAGE_NAME (sym),
                                text, text_len, text0, word,
                                wild_match_p, encoded_p);
       }
@@ -6592,7 +6592,7 @@ ada_make_symbol_completion_list (const char *text0, const char *word,
     b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (s), GLOBAL_BLOCK);
     ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
-      symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (sym),
+      symbol_completion_add (tracker, SYMBOL_LINKAGE_NAME (sym),
                              text, text_len, text0, word,
                              wild_match_p, encoded_p);
     }
@@ -6607,14 +6607,13 @@ ada_make_symbol_completion_list (const char *text0, const char *word,
       continue;
     ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
-      symbol_completion_add (&completions, SYMBOL_LINKAGE_NAME (sym),
+      symbol_completion_add (tracker, SYMBOL_LINKAGE_NAME (sym),
                              text, text_len, text0, word,
                              wild_match_p, encoded_p);
     }
   }
 
   do_cleanups (old_chain);
-  return completions;
 }
 
                                 /* Field Access */
@@ -14010,7 +14009,7 @@ const struct language_defn ada_language_defn = {
   0,                            /* c-style arrays */
   1,                            /* String lower bound */
   ada_get_gdb_completer_word_break_characters,
-  ada_make_symbol_completion_list,
+  ada_collect_symbol_completion_matches,
   ada_language_arch_info,
   ada_print_array_index,
   default_pass_by_reference,
index 92ab91b50ce37d9836e8acc86a37d6d52e64e8f1..eb51a6118f1da337a865cadc394c86c063d8a2f2 100644 (file)
@@ -612,15 +612,14 @@ catching_syscall_number (int syscall_number)
 }
 
 /* Complete syscall names.  Used by "catch syscall".  */
-static VEC (char_ptr) *
+
+static void
 catch_syscall_completer (struct cmd_list_element *cmd,
+                        completion_tracker &tracker,
                          const char *text, const char *word)
 {
   struct gdbarch *gdbarch = get_current_arch ();
   struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
-  VEC (char_ptr) *group_retlist = NULL;
-  VEC (char_ptr) *syscall_retlist = NULL;
-  VEC (char_ptr) *retlist = NULL;
   const char **group_list = NULL;
   const char **syscall_list = NULL;
   const char *prefix;
@@ -636,8 +635,8 @@ catch_syscall_completer (struct cmd_list_element *cmd,
     {
       /* Perform completion inside 'group:' namespace only.  */
       group_list = get_syscall_group_names (gdbarch);
-      retlist = (group_list == NULL
-                ? NULL : complete_on_enum (group_list, word, word));
+      if (group_list != NULL)
+       complete_on_enum (tracker, group_list, word, word);
     }
   else
     {
@@ -654,21 +653,15 @@ catch_syscall_completer (struct cmd_list_element *cmd,
          make_cleanup (xfree, prefixed_group);
        }
 
-      syscall_retlist = ((syscall_list == NULL)
-                        ? NULL : complete_on_enum (syscall_list, word, word));
-      group_retlist = ((group_list == NULL)
-                      ? NULL : complete_on_enum (group_list, word, word));
-
-      retlist = VEC_merge (char_ptr, syscall_retlist, group_retlist);
+      if (syscall_list != NULL)
+       complete_on_enum (tracker, syscall_list, word, word);
+      if (group_list != NULL)
+       complete_on_enum (tracker, group_list, word, word);
     }
 
-  VEC_free (char_ptr, syscall_retlist);
-  VEC_free (char_ptr, group_retlist);
   xfree (syscall_list);
   xfree (group_list);
   do_cleanups (cleanups);
-
-  return retlist;
 }
 
 static void
index 053ccef0fa2c081b46beb4fe8d9a5609135ee7eb..a848aea77af6d3d0b88350e9440541827add406b 100644 (file)
@@ -1042,8 +1042,9 @@ set_breakpoint_condition (struct breakpoint *b, const char *exp,
 
 /* Completion for the "condition" command.  */
 
-static VEC (char_ptr) *
+static void
 condition_completer (struct cmd_list_element *cmd,
+                    completion_tracker &tracker,
                     const char *text, const char *word)
 {
   const char *space;
@@ -1059,9 +1060,9 @@ condition_completer (struct cmd_list_element *cmd,
       if (text[0] == '$')
        {
          /* We don't support completion of history indices.  */
-         if (isdigit (text[1]))
-           return NULL;
-         return complete_internalvar (&text[1]);
+         if (!isdigit (text[1]))
+           complete_internalvar (tracker, &text[1]);
+         return;
        }
 
       /* We're completing the breakpoint number.  */
@@ -1074,15 +1075,18 @@ condition_completer (struct cmd_list_element *cmd,
          xsnprintf (number, sizeof (number), "%d", b->number);
 
          if (strncmp (number, text, len) == 0)
-           VEC_safe_push (char_ptr, result, xstrdup (number));
+           {
+             gdb::unique_xmalloc_ptr<char> copy (xstrdup (number));
+             tracker.add_completion (std::move (copy));
+           }
        }
 
-      return result;
+      return;
     }
 
   /* We're completing the expression part.  */
   text = skip_spaces_const (space);
-  return expression_completer (cmd, text, word);
+  expression_completer (cmd, tracker, text, word);
 }
 
 /* condition N EXP -- set break condition of breakpoint N to EXP.  */
index de8868b2e66da96d11a57c77c56145f0712df251..695b2371d046178b3e207700d8ddd92b1002c0ff 100644 (file)
@@ -865,7 +865,7 @@ const struct language_defn c_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
@@ -1009,7 +1009,7 @@ const struct language_defn cplus_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   cplus_language_arch_info,
   default_print_array_index,
   cp_pass_by_reference,
@@ -1062,7 +1062,7 @@ const struct language_defn asm_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   c_language_arch_info,        /* FIXME: la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
@@ -1115,7 +1115,7 @@ const struct language_defn minimal_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index 09303423bf0391a36a1de8b8ae91d74497cddc58..fa5dd4c6478fecdd37fe743b8fb3b45819173610 100644 (file)
@@ -238,6 +238,7 @@ help_command (char *command, int from_tty)
   help_cmd (command, gdb_stdout);
 }
 \f
+
 /* Note: The "complete" command is used by Emacs to implement completion.
    [Is that why this function writes output with *_unfiltered?]  */
 
@@ -246,8 +247,6 @@ complete_command (char *arg_entry, int from_tty)
 {
   const char *arg = arg_entry;
   int argpoint;
-  char *arg_prefix;
-  VEC (char_ptr) *completions;
 
   dont_repeat ();
 
@@ -279,43 +278,46 @@ complete_command (char *arg_entry, int from_tty)
       point--;
     }
 
-  arg_prefix = (char *) alloca (point - arg + 1);
-  memcpy (arg_prefix, arg, point - arg);
-  arg_prefix[point - arg] = 0;
-
-  completions = complete_line (point, arg, argpoint);
+  completion_tracker tracker_handle_completions;
 
-  if (completions)
+  TRY
+    {
+      complete_line (tracker_handle_completions, point, arg, strlen (arg));
+    }
+  CATCH (ex, RETURN_MASK_ALL)
     {
-      int ix, size = VEC_length (char_ptr, completions);
-      char *item, *prev = NULL;
+      return;
+    }
 
-      qsort (VEC_address (char_ptr, completions), size,
-            sizeof (char *), compare_strings);
+  std::string arg_prefix (arg, point - arg);
 
-      /* We do extra processing here since we only want to print each
-        unique item once.  */
-      for (ix = 0; VEC_iterate (char_ptr, completions, ix, item); ++ix)
+  completion_result result
+    = (tracker_handle_completions.build_completion_result
+       (point, point - arg, strlen (arg)));
+
+  if (result.number_matches != 0)
+    {
+      if (result.number_matches == 1)
+       printf_unfiltered ("%s%s\n", arg_prefix.c_str (), result.match_list[0]);
+      else
        {
-         if (prev == NULL || strcmp (item, prev) != 0)
+         result.sort_match_list ();
+
+         for (size_t i = 0; i < result.number_matches; i++)
            {
-             printf_unfiltered ("%s%s\n", arg_prefix, item);
-             xfree (prev);
-             prev = item;
+             printf_unfiltered ("%s%s",
+                                arg_prefix.c_str (),
+                                result.match_list[i + 1]);
+             printf_unfiltered ("\n");
            }
-         else
-           xfree (item);
        }
 
-      xfree (prev);
-      VEC_free (char_ptr, completions);
-
-      if (size == max_completions)
+      if (result.number_matches == max_completions)
        {
          /* ARG_PREFIX and POINT are included in the output so that emacs
             will include the message in the output.  */
          printf_unfiltered (_("%s%s %s\n"),
-                            arg_prefix, point,
+                            arg_prefix.c_str (), point,
                             get_max_completions_reached_message ());
        }
     }
index 064b481f9fda003a8e077d0d052ff9c4a8e0dc36..1bbbe46c3c1a60b1bf3f1c1b83ecdf03e76e38a3 100644 (file)
@@ -657,8 +657,9 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class theclass
 /* Completes on literal "unlimited".  Used by integer commands that
    support a special "unlimited" value.  */
 
-static VEC (char_ptr) *
+static void
 integer_unlimited_completer (struct cmd_list_element *ignore,
+                            completion_tracker &tracker,
                             const char *text, const char *word)
 {
   static const char * const keywords[] =
@@ -667,7 +668,7 @@ integer_unlimited_completer (struct cmd_list_element *ignore,
       NULL,
     };
 
-  return complete_on_enum (keywords, text, word);
+  complete_on_enum (tracker, keywords, text, word);
 }
 
 /* Add element named NAME to both the set and show command LISTs (the
@@ -1771,13 +1772,13 @@ lookup_cmd_composition (const char *text,
    "foo" and we want to complete to "foobar".  If WORD is "oo", return
    "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
 
-VEC (char_ptr) *
+void
 complete_on_cmdlist (struct cmd_list_element *list,
+                    completion_tracker &tracker,
                     const char *text, const char *word,
                     int ignore_help_classes)
 {
   struct cmd_list_element *ptr;
-  VEC (char_ptr) *matchlist = NULL;
   int textlen = strlen (text);
   int pass;
   int saw_deprecated_match = 0;
@@ -1786,8 +1787,10 @@ complete_on_cmdlist (struct cmd_list_element *list,
      commands.  If we see no matching commands in the first pass, and
      if we did happen to see a matching deprecated command, we do
      another loop to collect those.  */
-  for (pass = 0; matchlist == 0 && pass < 2; ++pass)
+  for (pass = 0; pass < 2; ++pass)
     {
+      bool got_matches = false;
+
       for (ptr = list; ptr; ptr = ptr->next)
        if (!strncmp (ptr->name, text, textlen)
            && !ptr->abbrev_flag
@@ -1820,32 +1823,34 @@ complete_on_cmdlist (struct cmd_list_element *list,
                match[text - word] = '\0';
                strcat (match, ptr->name);
              }
-           VEC_safe_push (char_ptr, matchlist, match);
+           tracker.add_completion (gdb::unique_xmalloc_ptr<char> (match));
+           got_matches = true;
          }
+
+      if (got_matches)
+       break;
+
       /* If we saw no matching deprecated commands in the first pass,
         just bail out.  */
       if (!saw_deprecated_match)
        break;
     }
-
-  return matchlist;
 }
 
 /* Helper function for SYMBOL_COMPLETION_FUNCTION.  */
 
-/* Return a vector of char pointers which point to the different
-   possible completions in CMD of TEXT.
+/* Add the different possible completions in ENUMLIST of TEXT.
 
    WORD points in the same buffer as TEXT, and completions should be
    returned relative to this position.  For example, suppose TEXT is "foo"
    and we want to complete to "foobar".  If WORD is "oo", return
    "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
 
-VEC (char_ptr) *
-complete_on_enum (const char *const *enumlist,
+void
+complete_on_enum (completion_tracker &tracker,
+                 const char *const *enumlist,
                  const char *text, const char *word)
 {
-  VEC (char_ptr) *matchlist = NULL;
   int textlen = strlen (text);
   int i;
   const char *name;
@@ -1870,10 +1875,8 @@ complete_on_enum (const char *const *enumlist,
            match[text - word] = '\0';
            strcat (match, name);
          }
-       VEC_safe_push (char_ptr, matchlist, match);
+       tracker.add_completion (gdb::unique_xmalloc_ptr<char> (match));
       }
-
-  return matchlist;
 }
 
 
index 2a190d449d56c11bb51335a5e42026f7f4758118..3a4a449eb01742635d4f58cc2e294de7034b1d46 100644 (file)
@@ -21,6 +21,8 @@
 #include "gdb_vecs.h"
 #include "common/scoped_restore.h"
 
+struct completion_tracker;
+
 /* This file defines the public interface for any code wanting to
    create commands.  */
 
@@ -174,7 +176,7 @@ typedef void cmd_sfunc_ftype (char *args, int from_tty,
 extern void set_cmd_sfunc (struct cmd_list_element *cmd,
                           cmd_sfunc_ftype *sfunc);
 
-/* A completion routine.  Return a list of possible completions.
+/* A completion routine.  Add possible completions to tracker.
 
    TEXT is the text beyond what was matched for the command itself
    (leading whitespace is skipped).  It stops where we are supposed to
@@ -183,11 +185,13 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
    relative to this position.  For example, suppose TEXT is "foo" and
    we want to complete to "foobar".  If WORD is "oo", return "oobar";
    if WORD is "baz/foo", return "baz/foobar".  */
-typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
-                                        const char *text, const char *word);
+typedef void completer_ftype (struct cmd_list_element *,
+                             completion_tracker &tracker,
+                             const char *text, const char *word);
 
 /* Same, but for set_cmd_completer_handle_brkchars.  */
 typedef void completer_handle_brkchars_ftype (struct cmd_list_element *,
+                                             completion_tracker &tracker,
                                              const char *text, const char *word);
 
 extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
@@ -259,11 +263,13 @@ extern struct cmd_list_element *add_info (const char *,
 extern struct cmd_list_element *add_info_alias (const char *, const char *,
                                                int);
 
-extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
-                                           const char *, const char *, int);
+extern void complete_on_cmdlist (struct cmd_list_element *,
+                                completion_tracker &tracker,
+                                const char *, const char *, int);
 
-extern VEC (char_ptr) *complete_on_enum (const char *const *enumlist,
-                                        const char *, const char *);
+extern void complete_on_enum (completion_tracker &tracker,
+                             const char *const *enumlist,
+                             const char *, const char *);
 
 /* Functions that implement commands about CLI commands.  */
 
index 625ff4f561bbb287c9ca846ef8acec68227c9254..85e6d88b7423acecadff89d085fb3b54e5418495 100644 (file)
@@ -28,7 +28,7 @@
 #include "user-regs.h"
 #include "arch-utils.h"
 #include "location.h"
-
+#include <algorithm>
 #include "cli/cli-decode.h"
 
 /* FIXME: This is needed because of lookup_cmd_1 ().  We should be
 
 #include "completer.h"
 
+/* Misc state that needs to be tracked across several different
+   readline completer entry point calls, all related to a single
+   completion invocation.  */
+
+struct gdb_completer_state
+{
+  /* The current completion's completion tracker.  This is a global
+     because a tracker can be shared between the handle_brkchars and
+     handle_completion phases, which involves different readline
+     callbacks.  */
+  completion_tracker *tracker = NULL;
+
+  /* Whether the current completion was aborted.  */
+  bool aborted = false;
+};
+
+/* The current completion state.  */
+static gdb_completer_state current_completion;
+
 /* An enumeration of the various things a user might
    attempt to complete for a location.  */
 
@@ -60,10 +79,6 @@ enum explicit_location_match_type
 };
 
 /* Prototypes for local functions.  */
-static
-char *line_completion_function (const char *text, int matches, 
-                               char *line_buffer,
-                               int point);
 
 /* readline uses the word breaks for two things:
    (1) In figuring out where to point the TEXT parameter to the
@@ -113,28 +128,21 @@ get_gdb_completer_quote_characters (void)
   return gdb_completer_quote_characters;
 }
 
-/* Line completion interface function for readline.  */
-
-char *
-readline_line_completion_function (const char *text, int matches)
-{
-  return line_completion_function (text, matches, 
-                                  rl_line_buffer, rl_point);
-}
-
 /* This can be used for functions which don't want to complete on
    symbols but don't want to complete on anything else either.  */
-VEC (char_ptr) *
+
+void
 noop_completer (struct cmd_list_element *ignore, 
+               completion_tracker &tracker,
                const char *text, const char *prefix)
 {
-  return NULL;
 }
 
 /* Complete on filenames.  */
 
-VEC (char_ptr) *
-filename_completer (struct cmd_list_element *ignore, 
+void
+filename_completer (struct cmd_list_element *ignore,
+                   completion_tracker &tracker,
                    const char *text, const char *word)
 {
   int subsequent_name;
@@ -180,7 +188,7 @@ filename_completer (struct cmd_list_element *ignore,
          strcat (q, p);
          xfree (p);
        }
-      VEC_safe_push (char_ptr, return_val, q);
+      tracker.add_completion (gdb::unique_xmalloc_ptr<char> (q));
     }
 #if 0
   /* There is no way to do this just long enough to affect quote
@@ -190,7 +198,6 @@ filename_completer (struct cmd_list_element *ignore,
      with respect to inserting quotes.  */
   rl_completer_word_break_characters = "";
 #endif
-  return return_val;
 }
 
 /* The corresponding completer_handle_brkchars
@@ -198,6 +205,7 @@ filename_completer (struct cmd_list_element *ignore,
 
 static void
 filename_completer_handle_brkchars (struct cmd_list_element *ignore,
+                                   completion_tracker &tracker,
                                    const char *text, const char *word)
 {
   set_rl_completer_word_break_characters
@@ -213,13 +221,12 @@ filename_completer_handle_brkchars (struct cmd_list_element *ignore,
    This is intended to be used in commands that set breakpoints
    etc.  */
 
-static VEC (char_ptr) *
-linespec_location_completer (struct cmd_list_element *ignore,
-                            const char *text, const char *word)
+static void
+complete_files_symbols (completion_tracker &tracker,
+                       const char *text, const char *word)
 {
-  int n_syms, n_files, ix;
-  VEC (char_ptr) *fn_list = NULL;
-  VEC (char_ptr) *list = NULL;
+  int ix;
+  completion_list fn_list;
   const char *p;
   int quote_found = 0;
   int quoted = *text == '\'' || *text == '"';
@@ -228,7 +235,6 @@ linespec_location_completer (struct cmd_list_element *ignore,
   char *file_to_match = NULL;
   const char *symbol_start = text;
   const char *orig_text = text;
-  size_t text_len;
 
   /* Do we have an unquoted colon, as in "break foo.c:bar"?  */
   for (p = text; *p != '\0'; ++p)
@@ -269,7 +275,6 @@ linespec_location_completer (struct cmd_list_element *ignore,
 
   if (quoted)
     text++;
-  text_len = strlen (text);
 
   /* Where is the file name?  */
   if (colon)
@@ -291,44 +296,23 @@ linespec_location_completer (struct cmd_list_element *ignore,
      symbols as well as on files.  */
   if (colon)
     {
-      list = make_file_symbol_completion_list (symbol_start, word,
-                                              file_to_match);
+      collect_file_symbol_completion_matches (tracker, symbol_start, word,
+                                             file_to_match);
       xfree (file_to_match);
     }
   else
     {
-      list = make_symbol_completion_list (symbol_start, word);
+      size_t text_len = strlen (text);
+
+      collect_symbol_completion_matches (tracker, symbol_start, word);
       /* If text includes characters which cannot appear in a file
         name, they cannot be asking for completion on files.  */
-      if (strcspn (text, 
+      if (strcspn (text,
                   gdb_completer_file_name_break_characters) == text_len)
        fn_list = make_source_files_completion_list (text, text);
     }
 
-  n_syms = VEC_length (char_ptr, list);
-  n_files = VEC_length (char_ptr, fn_list);
-
-  /* Catenate fn_list[] onto the end of list[].  */
-  if (!n_syms)
-    {
-      VEC_free (char_ptr, list); /* Paranoia.  */
-      list = fn_list;
-      fn_list = NULL;
-    }
-  else
-    {
-      char *fn;
-
-      for (ix = 0; VEC_iterate (char_ptr, fn_list, ix, fn); ++ix)
-       VEC_safe_push (char_ptr, list, fn);
-      VEC_free (char_ptr, fn_list);
-    }
-
-  if (n_syms && n_files)
-    {
-      /* Nothing.  */
-    }
-  else if (n_files)
+  if (!fn_list.empty () && !tracker.have_completions ())
     {
       char *fn;
 
@@ -347,31 +331,41 @@ linespec_location_completer (struct cmd_list_element *ignore,
         completion, because rl_complete will prepend "/foo/" to each
         candidate completion.  The loop below removes that leading
         part.  */
-      for (ix = 0; VEC_iterate (char_ptr, list, ix, fn); ++ix)
+      for (const auto &fn_up: fn_list)
        {
-         memmove (fn, fn + (word - text),
-                  strlen (fn) + 1 - (word - text));
+         char *fn = fn_up.get ();
+         memmove (fn, fn + (word - text), strlen (fn) + 1 - (word - text));
        }
     }
-  else if (!n_syms)
+
+  tracker.add_completions (std::move (fn_list));
+
+  if (!tracker.have_completions ())
     {
       /* No completions at all.  As the final resort, try completing
         on the entire text as a symbol.  */
-      list = make_symbol_completion_list (orig_text, word);
+      collect_symbol_completion_matches (tracker,
+                                        orig_text, word);
     }
+}
 
-  return list;
+/* Returns STRING if not NULL, the empty string otherwise.  */
+
+static const char *
+string_or_empty (const char *string)
+{
+  return string != NULL ? string : "";
 }
 
 /* A helper function to collect explicit location matches for the given
    LOCATION, which is attempting to match on WORD.  */
 
-static VEC (char_ptr) *
-collect_explicit_location_matches (struct event_location *location,
+static void
+collect_explicit_location_matches (completion_tracker &tracker,
+                                  struct event_location *location,
                                   enum explicit_location_match_type what,
                                   const char *word)
 {
-  VEC (char_ptr) *matches = NULL;
   const struct explicit_location *explicit_loc
     = get_explicit_location (location);
 
@@ -379,26 +373,25 @@ collect_explicit_location_matches (struct event_location *location,
     {
     case MATCH_SOURCE:
       {
-       const char *text = (explicit_loc->source_filename == NULL
-                           ? "" : explicit_loc->source_filename);
-
-       matches = make_source_files_completion_list (text, word);
+       const char *source = string_or_empty (explicit_loc->source_filename);
+       completion_list matches
+         = make_source_files_completion_list (source, word);
+       tracker.add_completions (std::move (matches));
       }
       break;
 
     case MATCH_FUNCTION:
       {
-       const char *text = (explicit_loc->function_name == NULL
-                           ? "" : explicit_loc->function_name);
-
+       const char *function = string_or_empty (explicit_loc->function_name);
        if (explicit_loc->source_filename != NULL)
          {
            const char *filename = explicit_loc->source_filename;
 
-           matches = make_file_symbol_completion_list (text, word, filename);
+           collect_file_symbol_completion_matches (tracker,
+                                                   function, word, filename);
          }
-       else
-         matches = make_symbol_completion_list (text, word);
+       else
+        collect_symbol_completion_matches (tracker, function, word);
       }
       break;
 
@@ -409,8 +402,6 @@ collect_explicit_location_matches (struct event_location *location,
     default:
       gdb_assert_not_reached ("unhandled explicit_location_match_type");
     }
-
-  return matches;
 }
 
 /* A convenience macro to (safely) back up P to the previous word.  */
@@ -429,13 +420,12 @@ backup_text_ptr (const char *p, const char *text)
 /* A completer function for explicit locations.  This function
    completes both options ("-source", "-line", etc) and values.  */
 
-static VEC (char_ptr) *
-explicit_location_completer (struct cmd_list_element *ignore,
-                            struct event_location *location,
-                            const char *text, const char *word)
+static void
+complete_explicit_location (completion_tracker &tracker,
+                           struct event_location *location,
+                           const char *text, const char *word)
 {
   const char *p;
-  VEC (char_ptr) *matches = NULL;
 
   /* Find the beginning of the word.  This is necessary because
      we need to know if we are completing an option name or value.  We
@@ -457,7 +447,8 @@ explicit_location_completer (struct cmd_list_element *ignore,
       /* Skip over the '-'.  */
       ++p;
 
-      return complete_on_enum (keywords, p, p);
+      complete_on_enum (tracker, keywords, p, p);
+      return;
     }
   else
     {
@@ -495,7 +486,7 @@ explicit_location_completer (struct cmd_list_element *ignore,
        {
          /* The user isn't completing on any valid option name,
             e.g., "break -source foo.c [tab]".  */
-         return NULL;
+         return;
        }
 
       /* If the user hasn't entered a search expression, e.g.,
@@ -505,43 +496,40 @@ explicit_location_completer (struct cmd_list_element *ignore,
        new_word = "";
 
       /* Now gather matches  */
-      matches = collect_explicit_location_matches (location, what, new_word);
+      collect_explicit_location_matches (tracker, location, what, new_word);
     }
-
-  return matches;
 }
 
 /* A completer for locations.  */
 
-VEC (char_ptr) *
+void
 location_completer (struct cmd_list_element *ignore,
+                   completion_tracker &tracker,
                    const char *text, const char *word)
 {
-  VEC (char_ptr) *matches = NULL;
   const char *copy = text;
 
   event_location_up location = string_to_explicit_location (&copy,
                                                            current_language,
                                                            1);
   if (location != NULL)
-    matches = explicit_location_completer (ignore, location.get (),
-                                          text, word);
+    complete_explicit_location (tracker, location.get (),
+                               text, word);
   else
     {
       /* This is an address or linespec location.
         Right now both of these are handled by the (old) linespec
         completer.  */
-      matches = linespec_location_completer (ignore, text, word);
+      complete_files_symbols (tracker, text, word);
     }
-
-  return matches;
 }
 
 /* Helper for expression_completer which recursively adds field and
-   method names from TYPE, a struct or union type, to the array
-   OUTPUT.  */
+   method names from TYPE, a struct or union type, to the OUTPUT
+   list.  */
+
 static void
-add_struct_fields (struct type *type, VEC (char_ptr) **output,
+add_struct_fields (struct type *type, completion_list &output,
                   char *fieldname, int namelen)
 {
   int i;
@@ -560,8 +548,7 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
            {
              if (! strncmp (TYPE_FIELD_NAME (type, i), 
                             fieldname, namelen))
-               VEC_safe_push (char_ptr, *output,
-                              xstrdup (TYPE_FIELD_NAME (type, i)));
+               output.emplace_back (xstrdup (TYPE_FIELD_NAME (type, i)));
            }
          else if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_UNION)
            {
@@ -585,7 +572,7 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
            }
          /* Omit constructors from the completion list.  */
          if (!type_name || strcmp (type_name, name))
-           VEC_safe_push (char_ptr, *output, xstrdup (name));
+           output.emplace_back (xstrdup (name));
        }
     }
 }
@@ -593,9 +580,10 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
 /* Complete on expressions.  Often this means completing on symbol
    names, but some language parsers also have support for completing
    field names.  */
-VEC (char_ptr) *
-expression_completer (struct cmd_list_element *ignore, 
-                     const char *text, const char *word)
+
+static void
+complete_expression (completion_tracker &tracker,
+                    const char *text, const char *word)
 {
   struct type *type = NULL;
   char *fieldname;
@@ -610,7 +598,7 @@ expression_completer (struct cmd_list_element *ignore,
     }
   CATCH (except, RETURN_MASK_ERROR)
     {
-      return NULL;
+      return;
     }
   END_CATCH
 
@@ -628,11 +616,12 @@ expression_completer (struct cmd_list_element *ignore,
          || TYPE_CODE (type) == TYPE_CODE_STRUCT)
        {
          int flen = strlen (fieldname);
-         VEC (char_ptr) *result = NULL;
+         completion_list result;
 
-         add_struct_fields (type, &result, fieldname, flen);
+         add_struct_fields (type, result, fieldname, flen);
          xfree (fieldname);
-         return result;
+         tracker.add_completions (std::move (result));
+         return;
        }
     }
   else if (fieldname && code != TYPE_CODE_UNDEF)
@@ -640,14 +629,26 @@ expression_completer (struct cmd_list_element *ignore,
       VEC (char_ptr) *result;
       struct cleanup *cleanup = make_cleanup (xfree, fieldname);
 
-      result = make_symbol_completion_type (fieldname, fieldname, code);
+      collect_symbol_completion_matches_type (tracker, fieldname, fieldname,
+                                             code);
       do_cleanups (cleanup);
-      return result;
+      return;
     }
   xfree (fieldname);
 
-  /* Not ideal but it is what we used to do before...  */
-  return linespec_location_completer (ignore, text, word);
+  complete_files_symbols (tracker, text, word);
+}
+
+/* Complete on expressions.  Often this means completing on symbol
+   names, but some language parsers also have support for completing
+   field names.  */
+
+void
+expression_completer (struct cmd_list_element *ignore,
+                     completion_tracker &tracker,
+                     const char *text, const char *word)
+{
+  complete_expression (tracker, text, word);
 }
 
 /* See definition in completer.h.  */
@@ -677,11 +678,12 @@ set_gdb_completion_word_break_characters (completer_ftype *fn)
 
 /* Complete on symbols.  */
 
-VEC (char_ptr) *
+void
 symbol_completer (struct cmd_list_element *ignore,
+                 completion_tracker &tracker,
                  const char *text, const char *word)
 {
-  return make_symbol_completion_list (text, word);
+  collect_symbol_completion_matches (tracker, text, word);
 }
 
 /* Here are some useful test cases for completion.  FIXME: These
@@ -707,18 +709,30 @@ symbol_completer (struct cmd_list_element *ignore,
    "file ../gdb.stabs/we" "ird" (needs to not break word at slash)
  */
 
-typedef enum
+enum complete_line_internal_reason
 {
+  /* Preliminary phase, called by gdb_completion_word_break_characters
+     function, is used to determine the correct set of chars that are
+     word delimiters depending on the current command in line_buffer.
+     No completion list should be generated; the return value should
+     be NULL.  This is checked by an assertion.  */
   handle_brkchars,
+
+  /* Main phase, called by complete_line function, is used to get the
+     list of possible completions.  */
   handle_completions,
-  handle_help
-}
-complete_line_internal_reason;
+
+  /* Special case when completing a 'help' command.  In this case,
+     once sub-command completions are exhausted, we simply return
+     NULL.  */
+  handle_help,
+};
 
 /* Helper for complete_line_internal to simplify it.  */
 
-static VEC (char_ptr) *
-complete_line_internal_normal_command (const char *command, const char *word,
+static void
+complete_line_internal_normal_command (completion_tracker &tracker,
+                                      const char *command, const char *word,
                                       const char *cmd_args,
                                       complete_line_internal_reason reason,
                                       struct cmd_list_element *c)
@@ -753,12 +767,11 @@ complete_line_internal_normal_command (const char *command, const char *word,
               (c->completer));
        }
 
-      brkchars_fn (c, p, word);
+      brkchars_fn (c, tracker, p, word);
     }
 
   if (reason != handle_brkchars && c->completer != NULL)
-    return (*c->completer) (c, p, word);
-  return NULL;
+    (*c->completer) (c, tracker, p, word);
 }
 
 /* Internal function used to handle completions.
@@ -770,35 +783,19 @@ complete_line_internal_normal_command (const char *command, const char *word,
    text of the line.  POINT is the offset in that line of the cursor.
    You should pretend that the line ends at POINT.
 
-   REASON is of type complete_line_internal_reason.
-
-   If REASON is handle_brkchars:
-   Preliminary phase, called by gdb_completion_word_break_characters
-   function, is used to determine the correct set of chars that are
-   word delimiters depending on the current command in line_buffer.
-   No completion list should be generated; the return value should be
-   NULL.  This is checked by an assertion in that function.
-
-   If REASON is handle_completions:
-   Main phase, called by complete_line function, is used to get the list
-   of posible completions.
+   See complete_line_internal_reason for description of REASON.  */
 
-   If REASON is handle_help:
-   Special case when completing a 'help' command.  In this case,
-   once sub-command completions are exhausted, we simply return NULL.
- */
-
-static VEC (char_ptr) *
-complete_line_internal (const char *text, 
-                       const char *line_buffer, int point,
-                       complete_line_internal_reason reason)
+static void
+complete_line_internal_1 (completion_tracker &tracker,
+                         const char *text,
+                         const char *line_buffer, int point,
+                         complete_line_internal_reason reason)
 {
-  VEC (char_ptr) *list = NULL;
   char *tmp_command;
   const char *p;
   int ignore_help_classes;
   /* Pointer within tmp_command which corresponds to text.  */
-  char *word;
+  const char *word;
   struct cmd_list_element *c, *result_list;
 
   /* Choose the default set of word break characters to break
@@ -821,10 +818,18 @@ complete_line_internal (const char *text,
 
   strncpy (tmp_command, line_buffer, point);
   tmp_command[point] = '\0';
-  /* Since text always contains some number of characters leading up
-     to point, we can find the equivalent position in tmp_command
-     by subtracting that many characters from the end of tmp_command.  */
-  word = tmp_command + point - strlen (text);
+  if (reason == handle_brkchars)
+    {
+      gdb_assert (text == NULL);
+      word = NULL;
+    }
+  else
+    {
+      /* Since text always contains some number of characters leading up
+        to point, we can find the equivalent position in tmp_command
+        by subtracting that many characters from the end of tmp_command.  */
+      word = tmp_command + point - strlen (text);
+    }
 
   if (point == 0)
     {
@@ -848,7 +853,6 @@ complete_line_internal (const char *text,
     {
       /* It is an unrecognized command.  So there are no
         possible completions.  */
-      list = NULL;
     }
   else if (c == CMD_LIST_AMBIGUOUS)
     {
@@ -866,7 +870,6 @@ complete_line_internal (const char *text,
             example, "info t " or "info t foo" does not complete
             to anything, because "info t" can be "info target" or
             "info terminal".  */
-         list = NULL;
        }
       else
        {
@@ -875,14 +878,14 @@ complete_line_internal (const char *text,
          if (result_list)
            {
              if (reason != handle_brkchars)
-               list = complete_on_cmdlist (*result_list->prefixlist, p,
-                                           word, ignore_help_classes);
+               complete_on_cmdlist (*result_list->prefixlist, tracker, p,
+                                    word, ignore_help_classes);
            }
          else
            {
              if (reason != handle_brkchars)
-               list = complete_on_cmdlist (cmdlist, p, word,
-                                           ignore_help_classes);
+               complete_on_cmdlist (cmdlist, tracker, p, word,
+                                    ignore_help_classes);
            }
          /* Ensure that readline does the right thing with respect to
             inserting quotes.  */
@@ -908,8 +911,8 @@ complete_line_internal (const char *text,
                  /* It is a prefix command; what comes after it is
                     a subcommand (e.g. "info ").  */
                  if (reason != handle_brkchars)
-                   list = complete_on_cmdlist (*c->prefixlist, p, word,
-                                               ignore_help_classes);
+                   complete_on_cmdlist (*c->prefixlist, tracker, p, word,
+                                        ignore_help_classes);
 
                  /* Ensure that readline does the right thing
                     with respect to inserting quotes.  */
@@ -917,11 +920,11 @@ complete_line_internal (const char *text,
                    (gdb_completer_command_word_break_characters);
                }
              else if (reason == handle_help)
-               list = NULL;
+               ;
              else if (c->enums)
                {
                  if (reason != handle_brkchars)
-                   list = complete_on_enum (c->enums, p, word);
+                   complete_on_enum (tracker, c->enums, p, word);
                  set_rl_completer_word_break_characters
                    (gdb_completer_command_word_break_characters);
                }
@@ -929,9 +932,9 @@ complete_line_internal (const char *text,
                {
                  /* It is a normal command; what comes after it is
                     completed by the command's completer function.  */
-                 list = complete_line_internal_normal_command (tmp_command,
-                                                               word, p,
-                                                               reason, c);
+                 complete_line_internal_normal_command (tracker,
+                                                        tmp_command, word, p,
+                                                        reason, c);
                }
            }
          else
@@ -953,8 +956,8 @@ complete_line_internal (const char *text,
                }
 
              if (reason != handle_brkchars)
-               list = complete_on_cmdlist (result_list, q, word,
-                                           ignore_help_classes);
+               complete_on_cmdlist (result_list, tracker, q, word,
+                                    ignore_help_classes);
 
              /* Ensure that readline does the right thing
                 with respect to inserting quotes.  */
@@ -963,7 +966,7 @@ complete_line_internal (const char *text,
            }
        }
       else if (reason == handle_help)
-       list = NULL;
+       ;
       else
        {
          /* There is non-whitespace beyond the command.  */
@@ -972,105 +975,115 @@ complete_line_internal (const char *text,
            {
              /* It is an unrecognized subcommand of a prefix command,
                 e.g. "info adsfkdj".  */
-             list = NULL;
            }
          else if (c->enums)
            {
              if (reason != handle_brkchars)
-               list = complete_on_enum (c->enums, p, word);
+               complete_on_enum (tracker, c->enums, p, word);
            }
          else
            {
              /* It is a normal command.  */
-             list = complete_line_internal_normal_command (tmp_command,
-                                                           word, p,
-                                                           reason, c);
+             complete_line_internal_normal_command (tracker,
+                                                    tmp_command, word, p,
+                                                    reason, c);
            }
        }
     }
-
-  return list;
 }
 
-/* See completer.h.  */
+/* Wrapper around complete_line_internal_1 to handle
+   MAX_COMPLETIONS_REACHED_ERROR.  */
 
-int max_completions = 200;
+static void
+complete_line_internal (completion_tracker &tracker,
+                       const char *text,
+                       const char *line_buffer, int point,
+                       complete_line_internal_reason reason)
+{
+  TRY
+    {
+      complete_line_internal_1 (tracker, text, line_buffer, point, reason);
+    }
+  CATCH (except, RETURN_MASK_ERROR)
+    {
+      if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
+       throw_exception (except);
+    }
+}
 
 /* See completer.h.  */
 
-completion_tracker_t
-new_completion_tracker (void)
-{
-  if (max_completions <= 0)
-    return NULL;
+int max_completions = 200;
 
-  return htab_create_alloc (max_completions,
-                           htab_hash_string, (htab_eq) streq,
-                           NULL, xcalloc, xfree);
-}
+/* Initial size of the table.  It automagically grows from here.  */
+#define INITIAL_COMPLETION_HTAB_SIZE 200
 
-/* Cleanup routine to free a completion tracker and reset the pointer
-   to NULL.  */
+/* See completer.h.  */
 
-static void
-free_completion_tracker (void *p)
+completion_tracker::completion_tracker ()
 {
-  completion_tracker_t *tracker_ptr = (completion_tracker_t *) p;
-
-  htab_delete (*tracker_ptr);
-  *tracker_ptr = NULL;
+  m_entries_hash = htab_create_alloc (INITIAL_COMPLETION_HTAB_SIZE,
+                                     htab_hash_string, (htab_eq) streq,
+                                     NULL, xcalloc, xfree);
 }
 
 /* See completer.h.  */
 
-struct cleanup *
-make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
+completion_tracker::~completion_tracker ()
 {
-  if (*tracker_ptr == NULL)
-    return make_cleanup (null_cleanup, NULL);
-
-  return make_cleanup (free_completion_tracker, tracker_ptr);
+  xfree (m_lowest_common_denominator);
+  htab_delete (m_entries_hash);
 }
 
 /* See completer.h.  */
 
-enum maybe_add_completion_enum
-maybe_add_completion (completion_tracker_t tracker, char *name)
+bool
+completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
 {
   void **slot;
 
-  if (max_completions < 0)
-    return MAYBE_ADD_COMPLETION_OK;
   if (max_completions == 0)
-    return MAYBE_ADD_COMPLETION_MAX_REACHED;
+    return false;
 
-  gdb_assert (tracker != NULL);
+  if (htab_elements (m_entries_hash) >= max_completions)
+    return false;
 
-  if (htab_elements (tracker) >= max_completions)
-    return MAYBE_ADD_COMPLETION_MAX_REACHED;
+  slot = htab_find_slot (m_entries_hash, name.get (), INSERT);
+  if (*slot == HTAB_EMPTY_ENTRY)
+    {
+      const char *match_for_lcd_str = name.get ();
 
-  slot = htab_find_slot (tracker, name, INSERT);
+      recompute_lowest_common_denominator (match_for_lcd_str);
 
-  if (*slot != HTAB_EMPTY_ENTRY)
-    return MAYBE_ADD_COMPLETION_DUPLICATE;
+      *slot = name.get ();
+      m_entries_vec.push_back (std::move (name));
+    }
 
-  *slot = name;
+  return true;
+}
 
-  return (htab_elements (tracker) < max_completions
-         ? MAYBE_ADD_COMPLETION_OK
-         : MAYBE_ADD_COMPLETION_OK_MAX_REACHED);
+/* See completer.h.  */
+
+void
+completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name)
+{
+  if (!maybe_add_completion (std::move (name)))
+    throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
 }
 
+/* See completer.h.  */
+
 void
-throw_max_completions_reached_error (void)
+completion_tracker::add_completions (completion_list &&list)
 {
-  throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
+  for (auto &candidate : list)
+    add_completion (std::move (candidate));
 }
 
-/* Generate completions all at once.  Returns a vector of unique strings
-   allocated with xmalloc.  Returns NULL if there are no completions
-   or if max_completions is 0.  If max_completions is non-negative, this will
-   return at most max_completions strings.
+/* 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.
 
    TEXT is the caller's idea of the "word" we are looking at.
 
@@ -1080,77 +1093,32 @@ throw_max_completions_reached_error (void)
    POINT is the offset in that line of the cursor.  You
    should pretend that the line ends at POINT.  */
 
-VEC (char_ptr) *
-complete_line (const char *text, const char *line_buffer, int point)
+void
+complete_line (completion_tracker &tracker,
+              const char *text, const char *line_buffer, int point)
 {
-  VEC (char_ptr) *list;
-  VEC (char_ptr) *result = NULL;
-  struct cleanup *cleanups;
-  completion_tracker_t tracker;
-  char *candidate;
-  int ix, max_reached;
-
   if (max_completions == 0)
-    return NULL;
-  list = complete_line_internal (text, line_buffer, point,
-                                handle_completions);
-  if (max_completions < 0)
-    return list;
-
-  tracker = new_completion_tracker ();
-  cleanups = make_cleanup_free_completion_tracker (&tracker);
-  make_cleanup_free_char_ptr_vec (list);
-
-  /* Do a final test for too many completions.  Individual completers may
-     do some of this, but are not required to.  Duplicates are also removed
-     here.  Otherwise the user is left scratching his/her head: readline and
-     complete_command will remove duplicates, and if removal of duplicates
-     there brings the total under max_completions the user may think gdb quit
-     searching too early.  */
-
-  for (ix = 0, max_reached = 0;
-       !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
-       ++ix)
-    {
-      enum maybe_add_completion_enum add_status;
-
-      add_status = maybe_add_completion (tracker, candidate);
-
-      switch (add_status)
-       {
-         case MAYBE_ADD_COMPLETION_OK:
-           VEC_safe_push (char_ptr, result, xstrdup (candidate));
-           break;
-         case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
-           VEC_safe_push (char_ptr, result, xstrdup (candidate));
-           max_reached = 1;
-           break;
-         case MAYBE_ADD_COMPLETION_MAX_REACHED:
-           gdb_assert_not_reached ("more than max completions reached");
-         case MAYBE_ADD_COMPLETION_DUPLICATE:
-           break;
-       }
-    }
-
-  do_cleanups (cleanups);
-
-  return result;
+    return;
+  complete_line_internal (tracker, text, line_buffer, point,
+                         handle_completions);
 }
 
 /* Complete on command names.  Used by "help".  */
 
-VEC (char_ptr) *
+void
 command_completer (struct cmd_list_element *ignore, 
+                  completion_tracker &tracker,
                   const char *text, const char *word)
 {
-  return complete_line_internal (word, text, 
-                                strlen (text), handle_help);
+  complete_line_internal (tracker, word, text,
+                         strlen (text), handle_help);
 }
 
 /* The corresponding completer_handle_brkchars implementation.  */
 
 static void
 command_completer_handle_brkchars (struct cmd_list_element *ignore,
+                                  completion_tracker &tracker,
                                   const char *text, const char *word)
 {
   set_rl_completer_word_break_characters
@@ -1159,11 +1127,11 @@ command_completer_handle_brkchars (struct cmd_list_element *ignore,
 
 /* Complete on signals.  */
 
-VEC (char_ptr) *
+void
 signal_completer (struct cmd_list_element *ignore,
+                 completion_tracker &tracker,
                  const char *text, const char *word)
 {
-  VEC (char_ptr) *return_val = NULL;
   size_t len = strlen (word);
   int signum;
   const char *signame;
@@ -1181,10 +1149,11 @@ signal_completer (struct cmd_list_element *ignore,
        continue;
 
       if (strncasecmp (signame, word, len) == 0)
-       VEC_safe_push (char_ptr, return_val, xstrdup (signame));
+       {
+         gdb::unique_xmalloc_ptr<char> copy (xstrdup (signame));
+         tracker.add_completion (std::move (copy));
+       }
     }
-
-  return return_val;
 }
 
 /* Bit-flags for selecting what the register and/or register-group
@@ -1200,12 +1169,11 @@ DEF_ENUM_FLAGS_TYPE (enum reg_completer_target, reg_completer_targets);
 /* Complete register names and/or reggroup names based on the value passed
    in TARGETS.  At least one bit in TARGETS must be set.  */
 
-static VEC (char_ptr) *
-reg_or_group_completer_1 (struct cmd_list_element *ignore,
+static void
+reg_or_group_completer_1 (completion_tracker &tracker,
                          const char *text, const char *word,
                          reg_completer_targets targets)
 {
-  VEC (char_ptr) *result = NULL;
   size_t len = strlen (word);
   struct gdbarch *gdbarch;
   const char *name;
@@ -1223,7 +1191,10 @@ reg_or_group_completer_1 (struct cmd_list_element *ignore,
           i++)
        {
          if (*name != '\0' && strncmp (word, name, len) == 0)
-           VEC_safe_push (char_ptr, result, xstrdup (name));
+           {
+             gdb::unique_xmalloc_ptr<char> copy (xstrdup (name));
+             tracker.add_completion (std::move (copy));
+           }
        }
     }
 
@@ -1237,38 +1208,42 @@ reg_or_group_completer_1 (struct cmd_list_element *ignore,
        {
          name = reggroup_name (group);
          if (strncmp (word, name, len) == 0)
-           VEC_safe_push (char_ptr, result, xstrdup (name));
+           {
+             gdb::unique_xmalloc_ptr<char> copy (xstrdup (name));
+             tracker.add_completion (std::move (copy));
+           }
        }
     }
-
-  return result;
 }
 
 /* Perform completion on register and reggroup names.  */
 
-VEC (char_ptr) *
+void
 reg_or_group_completer (struct cmd_list_element *ignore,
+                       completion_tracker &tracker,
                        const char *text, const char *word)
 {
-  return reg_or_group_completer_1 (ignore, text, word,
-                                  (complete_register_names
-                                   | complete_reggroup_names));
+  reg_or_group_completer_1 (tracker, text, word,
+                           (complete_register_names
+                            | complete_reggroup_names));
 }
 
 /* Perform completion on reggroup names.  */
 
-VEC (char_ptr) *
+void
 reggroup_completer (struct cmd_list_element *ignore,
+                   completion_tracker &tracker,
                    const char *text, const char *word)
 {
-  return reg_or_group_completer_1 (ignore, text, word,
-                                  complete_reggroup_names);
+  reg_or_group_completer_1 (tracker, text, word,
+                           complete_reggroup_names);
 }
 
 /* The default completer_handle_brkchars implementation.  */
 
 static void
 default_completer_handle_brkchars (struct cmd_list_element *ignore,
+                                  completion_tracker &tracker,
                                   const char *text, const char *word)
 {
   set_rl_completer_word_break_characters
@@ -1292,89 +1267,339 @@ completer_handle_brkchars_func_for_completer (completer_ftype *fn)
 /* Get the list of chars that are considered as word breaks
    for the current command.  */
 
-char *
-gdb_completion_word_break_characters (void)
+static char *
+gdb_completion_word_break_characters_throw ()
 {
-  VEC (char_ptr) *list;
+  /* New completion starting.  Get rid of the previous tracker and
+     start afresh.  */
+  delete current_completion.tracker;
+  current_completion.tracker = new completion_tracker ();
+
+  completion_tracker &tracker = *current_completion.tracker;
+
+  complete_line_internal (tracker, NULL, rl_line_buffer,
+                         rl_point, handle_brkchars);
 
-  list = complete_line_internal (rl_line_buffer, rl_line_buffer, rl_point,
-                                handle_brkchars);
-  gdb_assert (list == NULL);
   return rl_completer_word_break_characters;
 }
 
-/* Generate completions one by one for the completer.  Each time we
-   are called return another potential completion to the caller.
-   line_completion just completes on commands or passes the buck to
-   the command's completer function, the stuff specific to symbol
-   completion is in make_symbol_completion_list.
-
-   TEXT is the caller's idea of the "word" we are looking at.
+char *
+gdb_completion_word_break_characters ()
+{
+  /* New completion starting.  */
+  current_completion.aborted = false;
 
-   MATCHES is the number of matches that have currently been collected
-   from calling this completion function.  When zero, then we need to
-   initialize, otherwise the initialization has already taken place
-   and we can just return the next potential completion string.
+  TRY
+    {
+      return gdb_completion_word_break_characters_throw ();
+    }
+  CATCH (ex, RETURN_MASK_ALL)
+    {
+      /* Set this to that gdb_rl_attempted_completion_function knows
+        to abort early.  */
+      current_completion.aborted = true;
+    }
+  END_CATCH
 
-   LINE_BUFFER is available to be looked at; it contains the entire
-   text of the line.  POINT is the offset in that line of the cursor.
-   You should pretend that the line ends at POINT.
+  return NULL;
+}
 
-   Returns NULL if there are no more completions, else a pointer to a
-   string which is a possible completion, it is the caller's
-   responsibility to free the string.  */
+/* See completer.h.  */
 
-static char *
-line_completion_function (const char *text, int matches, 
-                         char *line_buffer, int point)
+void
+completion_tracker::recompute_lowest_common_denominator (const char *new_match)
 {
-  static VEC (char_ptr) *list = NULL;  /* Cache of completions.  */
-  static int index;                    /* Next cached completion.  */
-  char *output = NULL;
-
-  if (matches == 0)
+  if (m_lowest_common_denominator == NULL)
+    {
+      /* We don't have a lowest common denominator yet, so simply take
+        the whole NEW_MATCH as being it.  */
+      m_lowest_common_denominator = xstrdup (new_match);
+      m_lowest_common_denominator_unique = true;
+    }
+  else
     {
-      /* The caller is beginning to accumulate a new set of
-         completions, so we need to find all of them now, and cache
-         them for returning one at a time on future calls.  */
+      /* Find the common denominator between the currently-known
+        lowest common denominator and NEW_MATCH.  That becomes the
+        new lowest common denominator.  */
+      size_t i;
 
-      if (list)
+      for (i = 0;
+          (new_match[i] != '\0'
+           && new_match[i] == m_lowest_common_denominator[i]);
+          i++)
+       ;
+      if (m_lowest_common_denominator[i] != new_match[i])
        {
-         /* Free the storage used by LIST, but not by the strings
-            inside.  This is because rl_complete_internal () frees
-            the strings.  As complete_line may abort by calling
-            `error' clear LIST now.  */
-         VEC_free (char_ptr, list);
+         m_lowest_common_denominator[i] = '\0';
+         m_lowest_common_denominator_unique = false;
        }
-      index = 0;
-      list = complete_line (text, line_buffer, point);
     }
+}
+
+/* Build a new C string that is a copy of LCD with the whitespace of
+   ORIG/ORIG_LEN preserved.
+
+   Say the user is completing a symbol name, with spaces, like:
+
+     "foo ( i"
+
+   and the resulting completion match is:
+
+     "foo(int)"
+
+   we want to end up with an input line like:
+
+     "foo ( int)"
+      ^^^^^^^      => text from LCD [1], whitespace from ORIG preserved.
+            ^^    => new text from LCD
+
+   [1] - We must take characters from the LCD instead of the original
+   text, since some completions want to change upper/lowercase.  E.g.:
 
-  /* If we found a list of potential completions during initialization
-     then dole them out one at a time.  After returning the last one,
-     return NULL (and continue to do so) each time we are called after
-     that, until a new list is available.  */
+     "handle sig<>"
 
-  if (list)
+   completes to:
+
+     "handle SIG[QUIT|etc.]"
+*/
+
+static char *
+expand_preserving_ws (const char *orig, size_t orig_len,
+                     const char *lcd)
+{
+  const char *p_orig = orig;
+  const char *orig_end = orig + orig_len;
+  const char *p_lcd = lcd;
+  std::string res;
+
+  while (p_orig < orig_end)
     {
-      if (index < VEC_length (char_ptr, list))
+      if (*p_orig == ' ')
+       {
+         while (p_orig < orig_end && *p_orig == ' ')
+           res += *p_orig++;
+         p_lcd = skip_spaces_const (p_lcd);
+       }
+      else
        {
-         output = VEC_index (char_ptr, list, index);
-         index++;
+         /* Take characters from the LCD instead of the original
+            text, since some completions change upper/lowercase.
+            E.g.:
+              "handle sig<>"
+            completes to:
+              "handle SIG[QUIT|etc.]"
+         */
+         res += *p_lcd;
+         p_orig++;
+         p_lcd++;
        }
     }
 
-#if 0
-  /* Can't do this because readline hasn't yet checked the word breaks
-     for figuring out whether to insert a quote.  */
-  if (output == NULL)
-    /* Make sure the word break characters are set back to normal for
-       the next time that readline tries to complete something.  */
-    rl_completer_word_break_characters =
-      current_language->la_word_break_characters();
-#endif
+  while (*p_lcd != '\0')
+    res += *p_lcd++;
+
+  return xstrdup (res.c_str ());
+}
+
+/* See completer.h.  */
+
+completion_result
+completion_tracker::build_completion_result (const char *text,
+                                            int start, int end)
+{
+  completion_list &list = m_entries_vec;       /* The completions.  */
 
-  return (output);
+  if (list.empty ())
+    return {};
+
+  /* +1 for the LCD, and +1 for NULL termination.  */
+  char **match_list = XNEWVEC (char *, 1 + list.size () + 1);
+
+  /* Build replacement word, based on the LCD.  */
+
+  match_list[0]
+    = expand_preserving_ws (text, end - start,
+                           m_lowest_common_denominator);
+
+  if (m_lowest_common_denominator_unique)
+    {
+      match_list[1] = NULL;
+
+      /* If 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] == ' ');
+
+      return completion_result (match_list, 1, completion_suppress_append);
+    }
+  else
+    {
+      int ix;
+
+      for (ix = 0; ix < list.size (); ++ix)
+       match_list[ix + 1] = list[ix].release ();
+      match_list[ix + 1] = NULL;
+
+      return completion_result (match_list, list.size (), false);
+    }
+}
+
+/* See completer.h  */
+
+completion_result::completion_result ()
+  : match_list (NULL), number_matches (0),
+    completion_suppress_append (false)
+{}
+
+/* See completer.h  */
+
+completion_result::completion_result (char **match_list_,
+                                     size_t number_matches_,
+                                     bool completion_suppress_append_)
+  : match_list (match_list_),
+    number_matches (number_matches_),
+    completion_suppress_append (completion_suppress_append_)
+{}
+
+/* See completer.h  */
+
+completion_result::~completion_result ()
+{
+  reset_match_list ();
+}
+
+/* See completer.h  */
+
+completion_result::completion_result (completion_result &&rhs)
+{
+  if (this == &rhs)
+    return;
+
+  reset_match_list ();
+  match_list = rhs.match_list;
+  rhs.match_list = NULL;
+  number_matches = rhs.number_matches;
+  rhs.number_matches = 0;
+}
+
+/* See completer.h  */
+
+char **
+completion_result::release_match_list ()
+{
+  char **ret = match_list;
+  match_list = NULL;
+  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
+completion_result::sort_match_list ()
+{
+  if (number_matches > 1)
+    {
+      /* Element 0 is special (it's the common prefix), leave it
+        be.  */
+      std::sort (&match_list[1],
+                &match_list[number_matches + 1],
+                compare_cstrings);
+    }
+}
+
+/* See completer.h  */
+
+void
+completion_result::reset_match_list ()
+{
+  if (match_list != NULL)
+    {
+      for (char **p = match_list; *p != NULL; p++)
+       xfree (*p);
+      xfree (match_list);
+      match_list = NULL;
+    }
+}
+
+/* Helper for gdb_rl_attempted_completion_function, which does most of
+   the work.  This is called by readline to build the match list array
+   and to determine the lowest common denominator.  The real matches
+   list starts at match[1], while match[0] is the slot holding
+   readline's idea of the lowest common denominator of all matches,
+   which is what readline replaces the completion "word" with.
+
+   TEXT is the caller's idea of the "word" we are looking at, as
+   computed in the handle_brkchars phase.
+
+   START is the offset from RL_LINE_BUFFER where TEXT starts.  END is
+   the offset from RL_LINE_BUFFER where TEXT ends (i.e., where
+   rl_point is).
+
+   You should thus pretend that the line ends at END (relative to
+   RL_LINE_BUFFER).
+
+   RL_LINE_BUFFER contains the entire text of the line.  RL_POINT is
+   the offset in that line of the cursor.  You should pretend that the
+   line ends at POINT.
+
+   Returns NULL if there are no completions.  */
+
+static char **
+gdb_rl_attempted_completion_function_throw (const char *text, int start, int end)
+{
+  /* Completers must be called twice.  If rl_point (i.e., END) is at
+     column 0, then readline skips the the handle_brkchars phase, and
+     so we create a tracker now in that case too.  */
+  delete current_completion.tracker;
+  current_completion.tracker = new completion_tracker ();
+
+  complete_line (*current_completion.tracker, text,
+                rl_line_buffer, rl_point);
+
+  completion_tracker &tracker = *current_completion.tracker;
+
+  completion_result result
+    = tracker.build_completion_result (text, start, end);
+
+  rl_completion_suppress_append = result.completion_suppress_append;
+  return result.release_match_list ();
+}
+
+/* Function installed as "rl_attempted_completion_function" readline
+   hook.  Wrapper around gdb_rl_attempted_completion_function_throw
+   that catches C++ exceptions, which can't cross readline.  */
+
+char **
+gdb_rl_attempted_completion_function (const char *text, int start, int end)
+{
+  /* If we end up returning NULL, either on error, or simple because
+     there are no matches, inhibit readline's default filename
+     completer.  */
+  rl_attempted_completion_over = 1;
+
+  /* If the handle_brkchars phase was aborted, don't try
+     completing.  */
+  if (current_completion.aborted)
+    return NULL;
+
+  TRY
+    {
+      return gdb_rl_attempted_completion_function_throw (text, start, end);
+    }
+  CATCH (ex, RETURN_MASK_ALL)
+    {
+    }
+  END_CATCH
+
+  return NULL;
 }
 
 /* Skip over the possibly quoted word STR (as defined by the quote
index 463a53d4ad2032e8fd37c455b30d820e3fd27719..4b3b1882101cd33bbab40f88235c20fc630bda8a 100644 (file)
@@ -63,44 +63,184 @@ struct match_list_displayer
   mld_read_key_ftype *read_key;
 };
 
+/* A list of completion candidates.  Each element is a malloc string,
+   because ownership of the strings is transferred to readline, which
+   calls free on each element.  */
+typedef std::vector<gdb::unique_xmalloc_ptr<char>> completion_list;
+
+/* The final result of a completion that is handed over to either
+   readline or the "completion" command (which pretends to be
+   readline).  Mainly a wrapper for a readline-style match list array,
+   though other bits of info are included too.  */
+
+struct completion_result
+{
+  /* Create an empty result.  */
+  completion_result ();
+
+  /* Create a result.  */
+  completion_result (char **match_list, size_t number_matches,
+                    bool completion_suppress_append);
+
+  /* Destroy a result.  */
+  ~completion_result ();
+
+  /* Disable copying, since we don't need it.  */
+  completion_result (const completion_result &rhs) = delete;
+  void operator= (const completion_result &rhs) = delete;
+
+  /* Move a result.  */
+  completion_result (completion_result &&rhs);
+
+  /* Release ownership of the match list array.  */
+  char **release_match_list ();
+
+  /* Sort the match list.  */
+  void sort_match_list ();
+
+private:
+  /* Destroy the match list array and its contents.  */
+  void reset_match_list ();
+
+public:
+  /* (There's no point in making these fields private, since the whole
+     point of this wrapper is to build data in the layout expected by
+     readline.  Making them private would require adding getters for
+     the "complete" command, which would expose the same
+     implementation details anyway.)  */
+
+  /* The match list array, in the format that readline expects.
+     match_list[0] contains the common prefix.  The real match list
+     starts at index 1.  The list is NULL terminated.  If there's only
+     one match, then match_list[1] is NULL.  If there are no matches,
+     then this is NULL.  */
+  char **match_list;
+  /* The number of matched completions in MATCH_LIST.  Does not
+     include the NULL terminator or the common prefix.  */
+  size_t number_matches;
+
+  /* Whether readline should suppress appending a whitespace, when
+     there's only one possible completion.  */
+  bool completion_suppress_append;
+};
+
+/* Object used by completers to build a completion match list to hand
+   over to readline.  It tracks:
+
+   - How many unique completions have been generated, to terminate
+     completion list generation early if the list has grown to a size
+     so large as to be useless.  This helps avoid GDB seeming to lock
+     up in the event the user requests to complete on something vague
+     that necessitates the time consuming expansion of many symbol
+     tables.
+*/
+class completion_tracker
+{
+public:
+  completion_tracker ();
+  ~completion_tracker ();
+
+  /* Disable copy.  */
+  completion_tracker (const completion_tracker &rhs) = delete;
+  void operator= (const completion_tracker &rhs) = delete;
+
+  /* Add the completion NAME to the list of generated completions if
+     it is not there already.  If too many completions were already
+     found, this throws an error.  */
+  void add_completion (gdb::unique_xmalloc_ptr<char> name);
+
+  /* Add all completions matches in LIST.  Elements are moved out of
+     LIST.  */
+  void add_completions (completion_list &&list);
+
+  /* True if we have any completion match recorded.  */
+  bool have_completions () const
+  { return !m_entries_vec.empty (); }
+
+  /* Build a completion_result containing the list of completion
+     matches to hand over to readline.  The parameters are as in
+     rl_attempted_completion_function.  */
+  completion_result build_completion_result (const char *text,
+                                            int start, int end);
+
+private:
+
+  /* Add the completion NAME to the list of generated completions if
+     it is not there already.  If false is returned, too many
+     completions were found.  */
+  bool maybe_add_completion (gdb::unique_xmalloc_ptr<char> name);
+
+  /* Given a new match, recompute the lowest common denominator (LCD)
+     to hand over to readline.  */
+  void recompute_lowest_common_denominator (const char *new_match);
+
+  /* The completion matches found so far, in a vector.  */
+  completion_list m_entries_vec;
+
+  /* The completion matches found so far, in a hash table, for
+     duplicate elimination as entries are added.  Otherwise the user
+     is left scratching his/her head: readline and complete_command
+     will remove duplicates, and if removal of duplicates there brings
+     the total under max_completions the user may think gdb quit
+     searching too early.  */
+  htab_t m_entries_hash;
+
+  /* Our idea of lowest common denominator to hand over to readline.  */
+  char *m_lowest_common_denominator = NULL;
+
+  /* If true, the LCD is unique.  I.e., all completion candidates had
+     the same string.  */
+  bool m_lowest_common_denominator_unique = false;
+};
+
 extern void gdb_display_match_list (char **matches, int len, int max,
                                    const struct match_list_displayer *);
 
 extern const char *get_max_completions_reached_message (void);
 
-extern VEC (char_ptr) *complete_line (const char *text,
-                                     const char *line_buffer,
-                                     int point);
+extern void complete_line (completion_tracker &tracker,
+                          const char *text,
+                          const char *line_buffer,
+                          int point);
 
-extern char *readline_line_completion_function (const char *text,
-                                               int matches);
+extern char **gdb_rl_attempted_completion_function (const char *text,
+                                                   int start, int end);
 
-extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
-                                      const char *, const char *);
+extern void noop_completer (struct cmd_list_element *,
+                           completion_tracker &tracker,
+                           const char *, const char *);
 
-extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
-                                          const char *, const char *);
+extern void filename_completer (struct cmd_list_element *,
+                               completion_tracker &tracker,
+                               const char *, const char *);
 
-extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
-                                            const char *, const char *);
+extern void expression_completer (struct cmd_list_element *,
+                                 completion_tracker &tracker,
+                                 const char *, const char *);
 
-extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
-                                          const char *, const char *);
+extern void location_completer (struct cmd_list_element *,
+                               completion_tracker &tracker,
+                               const char *, const char *);
 
-extern VEC (char_ptr) *symbol_completer (struct cmd_list_element *,
-                                        const char *, const char *);
+extern void symbol_completer (struct cmd_list_element *,
+                             completion_tracker &tracker,
+                             const char *, const char *);
 
-extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
-                                         const char *, const char *);
+extern void command_completer (struct cmd_list_element *,
+                              completion_tracker &tracker,
+                              const char *, const char *);
 
-extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
-                                        const char *, const char *);
+extern void signal_completer (struct cmd_list_element *,
+                             completion_tracker &tracker,
+                             const char *, const char *);
 
-extern VEC (char_ptr) *reg_or_group_completer (struct cmd_list_element *,
-                                              const char *, const char *);
+extern void reg_or_group_completer (struct cmd_list_element *,
+                                   completion_tracker &tracker,
+                                   const char *, const char *);
 
-extern VEC (char_ptr) *reggroup_completer (struct cmd_list_element *,
-                                          const char *, const char *);
+extern void reggroup_completer (struct cmd_list_element *,
+                               completion_tracker &tracker,
+                               const char *, const char *);
 
 extern const char *get_gdb_completer_quote_characters (void);
 
@@ -134,62 +274,4 @@ extern const char *skip_quoted (const char *);
 
 extern int max_completions;
 
-/* Object to track how many unique completions have been generated.
-   Used to limit the size of generated completion lists.  */
-
-typedef htab_t completion_tracker_t;
-
-/* Create a new completion tracker.
-   The result is a hash table to track added completions, or NULL
-   if max_completions <= 0.  If max_completions < 0, tracking is disabled.
-   If max_completions == 0, the max is indeed zero.  */
-
-extern completion_tracker_t new_completion_tracker (void);
-
-/* Make a cleanup to free a completion tracker, and reset its pointer
-   to NULL.  */
-
-extern struct cleanup *make_cleanup_free_completion_tracker
-                     (completion_tracker_t *tracker_ptr);
-
-/* Return values for maybe_add_completion.  */
-
-enum maybe_add_completion_enum
-{
-  /* NAME has been recorded and max_completions has not been reached,
-     or completion tracking is disabled (max_completions < 0).  */
-  MAYBE_ADD_COMPLETION_OK,
-
-  /* NAME has been recorded and max_completions has been reached
-     (thus the caller can stop searching).  */
-  MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
-
-  /* max-completions entries has been reached.
-     Whether NAME is a duplicate or not is not determined.  */
-  MAYBE_ADD_COMPLETION_MAX_REACHED,
-
-  /* NAME has already been recorded.
-     Note that this is never returned if completion tracking is disabled
-     (max_completions < 0).  */
-  MAYBE_ADD_COMPLETION_DUPLICATE
-};
-
-/* Add the completion NAME to the list of generated completions if
-   it is not there already.
-   If max_completions is negative, nothing is done, not even watching
-   for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned.
-
-   If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to
-   record at least one more completion.  The final list will be pruned to
-   max_completions, but recording at least one more than max_completions is
-   the signal to the completion machinery that too many completions were
-   found.  */
-
-extern enum maybe_add_completion_enum
-  maybe_add_completion (completion_tracker_t tracker, char *name);
-
-/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR.  */ 
-
-extern void throw_max_completions_reached_error (void);
-
 #endif /* defined (COMPLETER_H) */
index 33eb4d1c46fa135d4a64e5ec22972ffab21f0f77..d9773cf80068a4b38b456b4d1e38955f4820d7cb 100644 (file)
@@ -483,8 +483,9 @@ set_gnutarget_command (char *ignore, int from_tty,
 
 /* A completion function for "set gnutarget".  */
 
-static VEC (char_ptr) *
+static void
 complete_set_gnutarget (struct cmd_list_element *cmd,
+                       completion_tracker &tracker,
                        const char *text, const char *word)
 {
   static const char **bfd_targets;
@@ -502,7 +503,7 @@ complete_set_gnutarget (struct cmd_list_element *cmd,
       bfd_targets[last + 1] = NULL;
     }
 
-  return complete_on_enum (bfd_targets, text, word);
+  complete_on_enum (tracker, bfd_targets, text, word);
 }
 
 /* Set the gnutarget.  */
index b72f2272a2fd4b13b711c18b77d1ecef6900aa71..f4cf9448d353640d603c2709e3f21fbbb83dedfb 100644 (file)
@@ -355,8 +355,9 @@ set_cp_abi_cmd (char *args, int from_tty)
 
 /* A completion function for "set cp-abi".  */
 
-static VEC (char_ptr) *
+static void
 cp_abi_completer (struct cmd_list_element *ignore,
+                 completion_tracker &tracker,
                  const char *text, const char *word)
 {
   static const char **cp_abi_names;
@@ -371,7 +372,7 @@ cp_abi_completer (struct cmd_list_element *ignore,
       cp_abi_names[i] = NULL;
     }
 
-  return complete_on_enum (cp_abi_names, text, word);
+  complete_on_enum (tracker, cp_abi_names, text, word);
 }
 
 /* Show the currently selected C++ ABI.  */
index 434b2e6ba5f3b4399ccc327c1b4e7926fc544f59..74cceaaefb1ee92431ddbaa065c35e4c6c438693 100644 (file)
@@ -239,7 +239,7 @@ static const struct language_defn d_language_defn =
   1,                           /* C-style arrays.  */
   0,                           /* String lower bound.  */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   d_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index 83f9871628ebd5446487602e211adce44fed1974..76c4ff31a6ee7861dc60ef292421693b98462644 100644 (file)
@@ -1030,8 +1030,9 @@ The following disassembler options are supported for use with the\n\
 
 /* A completion function for "set disassembler".  */
 
-static VEC (char_ptr) *
+static void
 disassembler_options_completer (struct cmd_list_element *ignore,
+                               completion_tracker &tracker,
                                const char *text, const char *word)
 {
   struct gdbarch *gdbarch = get_current_arch ();
@@ -1044,9 +1045,8 @@ disassembler_options_completer (struct cmd_list_element *ignore,
       if (separator != NULL)
        text = separator + 1;
       text = skip_spaces_const (text);
-      return complete_on_enum (opts->name, text, word);
+      complete_on_enum (tracker, opts->name, text, word);
     }
-  return NULL;
 }
 
 
index a9663d415bcac1e0f247f4274bfff462ecc34e86..e1184ee86022b81d754927a691d1381fab88e899 100644 (file)
@@ -228,11 +228,13 @@ f_word_break_characters (void)
 /* Consider the modules separator :: as a valid symbol name character
    class.  */
 
-static VEC (char_ptr) *
-f_make_symbol_completion_list (const char *text, const char *word,
-                              enum type_code code)
+static void
+f_collect_symbol_completion_matches (completion_tracker &tracker,
+                                    const char *text, const char *word,
+                                    enum type_code code)
 {
-  return default_make_symbol_completion_list_break_on (text, word, ":", code);
+  default_collect_symbol_completion_matches_break_on (tracker,
+                                                     text, word, ":", code);
 }
 
 static const char *f_extensions[] =
@@ -282,7 +284,7 @@ const struct language_defn f_language_defn =
   0,                           /* arrays are first-class (not c-style) */
   1,                           /* String lower bound */
   f_word_break_characters,
-  f_make_symbol_completion_list,
+  f_collect_symbol_completion_matches,
   f_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index 3b80cec4452baa1bb1d235ad05e9378d6456289b..f3b4f5cf1cf3c36e40b088b718eaa8da6a20d40d 100644 (file)
@@ -600,13 +600,13 @@ static const struct language_defn go_language_defn =
   1,                           /* C-style arrays.  */
   0,                           /* String lower bound.  */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   go_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
   c_get_string,
   c_watch_location_expression,
-  NULL,
+  NULL,                                /* la_get_symbol_name_cmp */
   iterate_over_symbols,
   &default_varobj_ops,
   NULL,
index 0c6419d9d04768a5f0b0c1870127ad8127af33f7..5501d31063447c68ccb7262d3e6e798eb0e0a692 100644 (file)
@@ -350,9 +350,8 @@ cmdscm_bad_completion_result (const char *msg, SCM completion)
    The result is a boolean indicating success.  */
 
 static int
-cmdscm_add_completion (SCM completion, VEC (char_ptr) **result)
+cmdscm_add_completion (SCM completion, completion_tracker &tracker)
 {
-  char *item;
   SCM except_scm;
 
   if (!scm_is_string (completion))
@@ -363,8 +362,9 @@ cmdscm_add_completion (SCM completion, VEC (char_ptr) **result)
       return 0;
     }
 
-  item = gdbscm_scm_to_string (completion, NULL, host_charset (), 1,
-                              &except_scm);
+  gdb::unique_xmalloc_ptr<char> item
+    (gdbscm_scm_to_string (completion, NULL, host_charset (), 1,
+                          &except_scm));
   if (item == NULL)
     {
       /* Inform the user, but otherwise ignore the entire result.  */
@@ -372,21 +372,21 @@ cmdscm_add_completion (SCM completion, VEC (char_ptr) **result)
       return 0;
     }
 
-  VEC_safe_push (char_ptr, *result, item);
+  tracker.add_completion (std::move (item));
 
   return 1;
 }
 
 /* Called by gdb for command completion.  */
 
-static VEC (char_ptr) *
+static void
 cmdscm_completer (struct cmd_list_element *command,
+                 completion_tracker &tracker,
                  const char *text, const char *word)
 {
   command_smob *c_smob/*obj*/ = (command_smob *) get_cmd_context (command);
   SCM completer_result_scm;
   SCM text_scm, word_scm, result_scm;
-  VEC (char_ptr) *result = NULL;
 
   gdb_assert (c_smob != NULL);
   gdb_assert (gdbscm_is_procedure (c_smob->complete));
@@ -408,7 +408,7 @@ cmdscm_completer (struct cmd_list_element *command,
     {
       /* Inform the user, but otherwise ignore.  */
       gdbscm_print_gdb_exception (SCM_BOOL_F, completer_result_scm);
-      goto done;
+      return;
     }
 
   if (gdbscm_is_true (scm_list_p (completer_result_scm)))
@@ -419,11 +419,8 @@ cmdscm_completer (struct cmd_list_element *command,
        {
          SCM next = scm_car (list);
 
-         if (!cmdscm_add_completion (next, &result))
-           {
-             VEC_free (char_ptr, result);
-             goto done;
-           }
+         if (!cmdscm_add_completion (next, tracker))
+           break;
 
          list = scm_cdr (list);
        }
@@ -437,17 +434,13 @@ cmdscm_completer (struct cmd_list_element *command,
        {
          if (gdbscm_is_exception (next))
            {
-             /* Inform the user, but otherwise ignore the entire result.  */
+             /* Inform the user.  */
              gdbscm_print_gdb_exception (SCM_BOOL_F, completer_result_scm);
-             VEC_free (char_ptr, result);
-             goto done;
+             break;
            }
 
-         if (!cmdscm_add_completion (next, &result))
-           {
-             VEC_free (char_ptr, result);
-             goto done;
-           }
+         if (cmdscm_add_completion (next, tracker))
+           break;
 
          next = itscm_safe_call_next_x (iter, NULL);
        }
@@ -458,9 +451,6 @@ cmdscm_completer (struct cmd_list_element *command,
       cmdscm_bad_completion_result (_("Bad completer result: "),
                                    completer_result_scm);
     }
-
- done:
-  return result;
 }
 
 /* Helper for gdbscm_make_command which locates the command list to use and
index 5e4cd51facf328720d3adb2882c590c025d4e01b..a68da6a0b3fc9f263c40ed82ec756af20faea060 100644 (file)
@@ -8691,11 +8691,11 @@ Are you sure you want to change it? "),
 
 /* Complete the "handle" command.  */
 
-static VEC (char_ptr) *
+static void
 handle_completer (struct cmd_list_element *ignore,
+                 completion_tracker &tracker,
                  const char *text, const char *word)
 {
-  VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
   static const char * const keywords[] =
     {
       "all",
@@ -8710,13 +8710,8 @@ handle_completer (struct cmd_list_element *ignore,
       NULL,
     };
 
-  vec_signals = signal_completer (ignore, text, word);
-  vec_keywords = complete_on_enum (keywords, word, word);
-
-  return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
-  VEC_free (char_ptr, vec_signals);
-  VEC_free (char_ptr, vec_keywords);
-  return return_val;
+  signal_completer (ignore, tracker, text, word);
+  complete_on_enum (tracker, keywords, word, word);
 }
 
 enum gdb_signal
index af86390b3decab6bb95d7f5f1217f85fef4787ca..4de7c4e8be6c48d4b266943e06f4ba90c3babaf5 100644 (file)
@@ -452,13 +452,13 @@ interpreter_exec_cmd (char *args, int from_tty)
 
 /* See interps.h.  */
 
-VEC (char_ptr) *
+void
 interpreter_completer (struct cmd_list_element *ignore,
+                      completion_tracker &tracker,
                       const char *text, const char *word)
 {
   struct interp_factory *interp;
   int textlen;
-  VEC (char_ptr) *matches = NULL;
   int ix;
 
   textlen = strlen (text);
@@ -485,11 +485,9 @@ interpreter_completer (struct cmd_list_element *ignore,
              match[text - word] = '\0';
              strcat (match, interp->name);
            }
-         VEC_safe_push (char_ptr, matches, match);
+         tracker.add_completion (gdb::unique_xmalloc_ptr<char> (match));
        }
     }
-
-  return matches;
 }
 
 struct interp *
index 1b9580c1183c90a4992fc59f6c9238cef8ef8ac6..b20cf5cc9be454d81b98a9e378c2e144f1006089 100644 (file)
@@ -138,9 +138,10 @@ extern void interp_pre_command_loop (struct interp *interp);
 
 /* List the possible interpreters which could complete the given
    text.  */
-extern VEC (char_ptr) *interpreter_completer (struct cmd_list_element *ignore,
-                                             const char *text,
-                                             const char *word);
+extern void interpreter_completer (struct cmd_list_element *ignore,
+                                  completion_tracker &tracker,
+                                  const char *text,
+                                  const char *word);
 
 /* well-known interpreters */
 #define INTERP_CONSOLE         "console"
index e9d9803aeee7401efc4a9ae1655785fe6f83bafa..d30f4f0b53872f2eedc9314545c40f78d22a96a4 100644 (file)
@@ -855,7 +855,7 @@ const struct language_defn unknown_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   unknown_language_arch_info,  /* la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
@@ -905,7 +905,7 @@ const struct language_defn auto_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   unknown_language_arch_info,  /* la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
@@ -953,7 +953,7 @@ const struct language_defn local_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   unknown_language_arch_info,  /* la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
index cc0df8c5ce2747840f98c983843e91309f28c21f..7ce4f7f13ba0784ef3c3bba158015cc44aa5b912 100644 (file)
@@ -134,7 +134,7 @@ struct language_arch_info
    transformed for lookup.  */
 
 typedef int (*symbol_name_cmp_ftype) (const char *symbol_search_name,
-                                         const char *lookup_name);
+                                     const char *lookup_name);
 
 /* Structure tying together assorted information about a language.  */
 
@@ -323,14 +323,16 @@ struct language_defn
     /* The list of characters forming word boundaries.  */
     const char *(*la_word_break_characters) (void);
 
-    /* Should return a vector of all symbols which are possible
+    /* Add to the completion tracker all symbols which are possible
        completions for TEXT.  WORD is the entire command on which the
        completion is being made.  If CODE is TYPE_CODE_UNDEF, then all
        symbols should be examined; otherwise, only STRUCT_DOMAIN
        symbols whose type has a code of CODE should be matched.  */
-    VEC (char_ptr) *(*la_make_symbol_completion_list) (const char *text,
-                                                      const char *word,
-                                                      enum type_code code);
+    void (*la_collect_symbol_completion_matches)
+      (completion_tracker &tracker,
+       const char *text,
+       const char *word,
+       enum type_code code);
 
     /* The per-architecture (OS/ABI) language information.  */
     void (*la_language_arch_info) (struct gdbarch *,
index 35840bf56f91b7bf0a5cc6f8de29a2743d8aaf87..0035a52e20d4c25cbf821f95e9066f0a1b2c2107 100644 (file)
@@ -388,7 +388,7 @@ const struct language_defn m2_language_defn =
   0,                           /* arrays are first-class (not c-style) */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   m2_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index 934d9c6d168fa5f797767b62f56143851326012c..af272681dde59b02a115c4a902a0c0a6083b56bd 100644 (file)
@@ -397,7 +397,7 @@ const struct language_defn objc_language_defn = {
   1,                           /* C-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index df57b61529981acee4b2bd231427d01e42735bbf..116d107aca158bd338b8dfadb37f7bd14ef0f823 100644 (file)
@@ -1077,7 +1077,7 @@ const struct language_defn opencl_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   opencl_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index c4fe2f6c2a02e99ed1ac61c488833e23571490db..77913fc290614f2970c01ecff124eef8e01bb371 100644 (file)
@@ -451,7 +451,7 @@ const struct language_defn pascal_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   pascal_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index b9a866e6f488d56032021a2bd947fd983c74ee0f..b9f60377bd60218547968f30ae737b6d8322d11e 100644 (file)
@@ -242,10 +242,21 @@ cmdpy_completer_helper (struct cmd_list_element *command,
                                         NULL));
   if (textobj == NULL)
     error (_("Could not convert argument to Python string."));
-  gdbpy_ref<> wordobj (PyUnicode_Decode (word, strlen (word), host_charset (),
-                                        NULL));
-  if (wordobj == NULL)
-    error (_("Could not convert argument to Python string."));
+
+  gdbpy_ref<> wordobj;
+  if (word == NULL)
+    {
+      /* "brkchars" phase.  */
+      wordobj.reset (Py_None);
+      Py_INCREF (Py_None);
+    }
+  else
+    {
+      wordobj.reset (PyUnicode_Decode (word, strlen (word), host_charset (),
+                                      NULL));
+      if (wordobj == NULL)
+       error (_("Could not convert argument to Python string."));
+    }
 
   gdbpy_ref<> resultobj (PyObject_CallMethodObjArgs ((PyObject *) obj,
                                                     complete_cst,
@@ -267,6 +278,7 @@ cmdpy_completer_helper (struct cmd_list_element *command,
 
 static void
 cmdpy_completer_handle_brkchars (struct cmd_list_element *command,
+                                completion_tracker &tracker,
                                 const char *text, const char *word)
 {
   gdbpy_enter enter_py (get_current_arch (), current_language);
@@ -300,19 +312,18 @@ cmdpy_completer_handle_brkchars (struct cmd_list_element *command,
             adjust the break characters accordingly.  */
          brkchars_fn = (completer_handle_brkchars_func_for_completer
                         (completers[value].completer));
-         brkchars_fn (command, text, word);
+         brkchars_fn (command, tracker, text, word);
        }
     }
 }
 
 /* Called by gdb for command completion.  */
 
-static VEC (char_ptr) *
+static void
 cmdpy_completer (struct cmd_list_element *command,
+                completion_tracker &tracker,
                 const char *text, const char *word)
 {
-  VEC (char_ptr) *result = NULL;
-
   gdbpy_enter enter_py (get_current_arch (), current_language);
 
   /* Calling our helper to obtain the PyObject of the Python
@@ -320,12 +331,10 @@ cmdpy_completer (struct cmd_list_element *command,
   gdbpy_ref<> resultobj (cmdpy_completer_helper (command, text, word));
 
   /* If the result object of calling the Python function is NULL, it
-     means that there was an error.  In this case, just give up and
-     return NULL.  */
+     means that there was an error.  In this case, just give up.  */
   if (resultobj == NULL)
-    return NULL;
+    return;
 
-  result = NULL;
   if (PyInt_Check (resultobj.get ()))
     {
       /* User code may also return one of the completion constants,
@@ -338,15 +347,16 @@ cmdpy_completer (struct cmd_list_element *command,
          PyErr_Clear ();
        }
       else if (value >= 0 && value < (long) N_COMPLETERS)
-       result = completers[value].completer (command, text, word);
+       completers[value].completer (command, tracker, text, word);
     }
   else
     {
       gdbpy_ref<> iter (PyObject_GetIter (resultobj.get ()));
 
       if (iter == NULL)
-       return NULL;
+       return;
 
+      bool got_matches = false;
       while (true)
        {
          gdbpy_ref<> elt (PyIter_Next (iter.get ()));
@@ -366,16 +376,15 @@ cmdpy_completer (struct cmd_list_element *command,
              PyErr_Clear ();
              continue;
            }
-         VEC_safe_push (char_ptr, result, item.release ());
+         tracker.add_completion (std::move (item));
+         got_matches = true;
        }
 
       /* If we got some results, ignore problems.  Otherwise, report
         the problem.  */
-      if (result != NULL && PyErr_Occurred ())
+      if (got_matches && PyErr_Occurred ())
        PyErr_Clear ();
     }
-
-  return result;
 }
 
 /* Helper for cmdpy_init which locates the command list to use and
index d4cda1fc257f270789f0124408a6375d16bfbbff..ef41f56b4d8ddee78c7cec3c06b07abd2e4d74ee 100644 (file)
@@ -2184,7 +2184,7 @@ static const struct language_defn rust_language_defn =
   1,                           /* c-style arrays */
   0,                           /* String lower bound */
   default_word_break_characters,
-  default_make_symbol_completion_list,
+  default_collect_symbol_completion_matches,
   rust_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
index e5cd397f6ca434ee842c75b644c1a0a4fda250d4..57fb355328f16fa82cc906ac9184516bdb681998 100644 (file)
@@ -4747,44 +4747,13 @@ compare_symbol_name (const char *name, const char *sym_text, int sym_text_len)
   return 1;
 }
 
-/* Free any memory associated with a completion list.  */
-
-static void
-free_completion_list (VEC (char_ptr) **list_ptr)
-{
-  int i;
-  char *p;
-
-  for (i = 0; VEC_iterate (char_ptr, *list_ptr, i, p); ++i)
-    xfree (p);
-  VEC_free (char_ptr, *list_ptr);
-}
-
-/* Callback for make_cleanup.  */
-
-static void
-do_free_completion_list (void *list)
-{
-  free_completion_list ((VEC (char_ptr) **) list);
-}
-
-static VEC (char_ptr) *return_val;
-
-/* Tracker for how many unique completions have been generated.  Used
-   to terminate completion list generation early if the list has grown
-   to a size so large as to be useless.  This helps avoid GDB seeming
-   to lock up in the event the user requests to complete on something
-   vague that necessitates the time consuming expansion of many symbol
-   tables.  */
-
-static completion_tracker_t completion_tracker;
-
 /*  Test to see if the symbol specified by SYMNAME (which is already
    demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN
    characters.  If so, add it to the current completion list.  */
 
 static void
-completion_list_add_name (const char *symname,
+completion_list_add_name (completion_tracker &tracker,
+                         const char *symname,
                          const char *sym_text, int sym_text_len,
                          const char *text, const char *word)
 {
@@ -4797,7 +4766,6 @@ completion_list_add_name (const char *symname,
 
   {
     char *newobj;
-    enum maybe_add_completion_enum add_status;
 
     if (word == sym_text)
       {
@@ -4819,45 +4787,33 @@ completion_list_add_name (const char *symname,
        strcat (newobj, symname);
       }
 
-    add_status = maybe_add_completion (completion_tracker, newobj);
+    gdb::unique_xmalloc_ptr<char> completion (newobj);
 
-    switch (add_status)
-      {
-      case MAYBE_ADD_COMPLETION_OK:
-       VEC_safe_push (char_ptr, return_val, newobj);
-       break;
-      case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
-       VEC_safe_push (char_ptr, return_val, newobj);
-       throw_max_completions_reached_error ();
-      case MAYBE_ADD_COMPLETION_MAX_REACHED:
-       xfree (newobj);
-       throw_max_completions_reached_error ();
-      case MAYBE_ADD_COMPLETION_DUPLICATE:
-       xfree (newobj);
-       break;
-      }
+    tracker.add_completion (std::move (completion));
   }
 }
 
 /* completion_list_add_name wrapper for struct symbol.  */
 
 static void
-completion_list_add_symbol (symbol *sym,
+completion_list_add_symbol (completion_tracker &tracker,
+                           symbol *sym,
                            const char *sym_text, int sym_text_len,
                            const char *text, const char *word)
 {
-  completion_list_add_name (SYMBOL_NATURAL_NAME (sym),
+  completion_list_add_name (tracker, SYMBOL_NATURAL_NAME (sym),
                            sym_text, sym_text_len, text, word);
 }
 
 /* completion_list_add_name wrapper for struct minimal_symbol.  */
 
 static void
-completion_list_add_msymbol (minimal_symbol *sym,
+completion_list_add_msymbol (completion_tracker &tracker,
+                            minimal_symbol *sym,
                             const char *sym_text, int sym_text_len,
                             const char *text, const char *word)
 {
-  completion_list_add_name (MSYMBOL_NATURAL_NAME (sym),
+  completion_list_add_name (tracker, MSYMBOL_NATURAL_NAME (sym),
                            sym_text, sym_text_len, text, word);
 }
 
@@ -4865,7 +4821,8 @@ completion_list_add_msymbol (minimal_symbol *sym,
    again and feed all the selectors into the mill.  */
 
 static void
-completion_list_objc_symbol (struct minimal_symbol *msymbol,
+completion_list_objc_symbol (completion_tracker &tracker,
+                            struct minimal_symbol *msymbol,
                             const char *sym_text, int sym_text_len,
                             const char *text, const char *word)
 {
@@ -4883,7 +4840,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
 
   if (sym_text[0] == '[')
     /* Complete on shortened method method.  */
-    completion_list_add_name (method + 1, sym_text, sym_text_len, text, word);
+    completion_list_add_name (tracker, method + 1,
+                             sym_text, sym_text_len, text, word);
 
   while ((strlen (method) + 1) >= tmplen)
     {
@@ -4904,9 +4862,11 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
       memcpy (tmp, method, (category - method));
       tmp[category - method] = ' ';
       memcpy (tmp + (category - method) + 1, selector, strlen (selector) + 1);
-      completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
+      completion_list_add_name (tracker, tmp,
+                               sym_text, sym_text_len, text, word);
       if (sym_text[0] == '[')
-       completion_list_add_name (tmp + 1, sym_text, sym_text_len, text, word);
+       completion_list_add_name (tracker, tmp + 1,
+                                 sym_text, sym_text_len, text, word);
     }
 
   if (selector != NULL)
@@ -4917,7 +4877,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
       if (tmp2 != NULL)
        *tmp2 = '\0';
 
-      completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
+      completion_list_add_name (tracker, tmp,
+                               sym_text, sym_text_len, text, word);
     }
 }
 
@@ -4968,9 +4929,10 @@ language_search_unquoted_string (const char *text, const char *p)
 }
 
 static void
-completion_list_add_fields (struct symbol *sym, const char *sym_text,
-                           int sym_text_len, const char *text,
-                           const char *word)
+completion_list_add_fields (completion_tracker &tracker,
+                           struct symbol *sym,
+                           const char *sym_text, int sym_text_len,
+                           const char *text, const char *word)
 {
   if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
     {
@@ -4981,7 +4943,7 @@ completion_list_add_fields (struct symbol *sym, const char *sym_text,
       if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
        for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
          if (TYPE_FIELD_NAME (t, j))
-           completion_list_add_name (TYPE_FIELD_NAME (t, j),
+           completion_list_add_name (tracker, TYPE_FIELD_NAME (t, j),
                                      sym_text, sym_text_len, text, word);
     }
 }
@@ -4990,6 +4952,7 @@ completion_list_add_fields (struct symbol *sym, const char *sym_text,
 
 static void
 add_symtab_completions (struct compunit_symtab *cust,
+                       completion_tracker &tracker,
                        const char *sym_text, int sym_text_len,
                        const char *text, const char *word,
                        enum type_code code)
@@ -5011,18 +4974,18 @@ add_symtab_completions (struct compunit_symtab *cust,
          if (code == TYPE_CODE_UNDEF
              || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
                  && TYPE_CODE (SYMBOL_TYPE (sym)) == code))
-           completion_list_add_symbol (sym,
+           completion_list_add_symbol (tracker, sym,
                                        sym_text, sym_text_len,
                                        text, word);
        }
     }
 }
 
-static void
-default_make_symbol_completion_list_break_on_1 (const char *text,
-                                               const char *word,
-                                               const char *break_on,
-                                               enum type_code code)
+void
+default_collect_symbol_completion_matches_break_on
+  (completion_tracker &tracker,
+   const char *text, const char *word,
+   const char *break_on, enum type_code code)
 {
   /* Problem: All of the symbols have to be copied because readline
      frees them.  I'm not going to worry about this; hopefully there
@@ -5039,7 +5002,6 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
   const char *sym_text;
   /* Length of sym_text.  */
   int sym_text_len;
-  struct cleanup *cleanups;
 
   /* Now look for the symbol we are supposed to complete on.  */
   {
@@ -5109,9 +5071,6 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
     }
   gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '(');
 
-  completion_tracker = new_completion_tracker ();
-  cleanups = make_cleanup_free_completion_tracker (&completion_tracker);
-
   /* At this point scan through the misc symbol vectors and add each
      symbol you find to the list.  Eventually we want to ignore
      anything that isn't a text symbol (everything else will be
@@ -5122,18 +5081,21 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
       ALL_MSYMBOLS (objfile, msymbol)
        {
          QUIT;
-         completion_list_add_msymbol (msymbol, sym_text, sym_text_len, text,
-                                      word);
 
-         completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text,
-                                      word);
+         completion_list_add_msymbol (tracker,
+                                      msymbol, sym_text, sym_text_len,
+                                      text, word);
+
+         completion_list_objc_symbol (tracker,
+                                      msymbol, sym_text, sym_text_len,
+                                      text, word);
        }
     }
 
   /* Add completions for all currently loaded symbol tables.  */
   ALL_COMPUNITS (objfile, cust)
-    add_symtab_completions (cust, sym_text, sym_text_len, text, word,
-                           code);
+    add_symtab_completions (cust, tracker,
+                           sym_text, sym_text_len, text, word, code);
 
   /* Look through the partial symtabs for all symbols which begin by
      matching SYM_TEXT.  Expand all CUs that you find to the list.  */
@@ -5147,6 +5109,7 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
                           [&] (compunit_symtab *symtab) /* expansion notify */
                             {
                               add_symtab_completions (symtab,
+                                                      tracker,
                                                       sym_text, sym_text_len,
                                                       text, word, code);
                             },
@@ -5169,14 +5132,17 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
          {
            if (code == TYPE_CODE_UNDEF)
              {
-               completion_list_add_symbol (sym, sym_text, sym_text_len, text,
+               completion_list_add_symbol (tracker, sym,
+                                           sym_text, sym_text_len, text,
                                            word);
-               completion_list_add_fields (sym, sym_text, sym_text_len, text,
+               completion_list_add_fields (tracker, sym,
+                                           sym_text, sym_text_len, text,
                                            word);
              }
            else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
                     && TYPE_CODE (SYMBOL_TYPE (sym)) == code)
-             completion_list_add_symbol (sym, sym_text, sym_text_len, text,
+             completion_list_add_symbol (tracker, sym,
+                                         sym_text, sym_text_len, text,
                                          word);
          }
 
@@ -5194,11 +5160,13 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
     {
       if (surrounding_static_block != NULL)
        ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
-         completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
+         completion_list_add_fields (tracker, sym,
+                                     sym_text, sym_text_len, text, word);
 
       if (surrounding_global_block != NULL)
        ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
-         completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
+         completion_list_add_fields (tracker, sym,
+                                     sym_text, sym_text_len, text, word);
     }
 
   /* Skip macros if we are completing a struct tag -- arguable but
@@ -5214,7 +5182,7 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
                                 macro_source_file *,
                                 int)
        {
-         completion_list_add_name (macro_name,
+         completion_list_add_name (tracker, macro_name,
                                    sym_text, sym_text_len,
                                    text, word);
        };
@@ -5237,74 +5205,52 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
       /* User-defined macros are always visible.  */
       macro_for_each (macro_user_macros, add_macro_name);
     }
-
-  do_cleanups (cleanups);
 }
 
-VEC (char_ptr) *
-default_make_symbol_completion_list_break_on (const char *text,
-                                             const char *word,
-                                             const char *break_on,
-                                             enum type_code code)
-{
-  struct cleanup *back_to;
-
-  return_val = NULL;
-  back_to = make_cleanup (do_free_completion_list, &return_val);
-
-  TRY
-    {
-      default_make_symbol_completion_list_break_on_1 (text, word,
-                                                     break_on, code);
-    }
-  CATCH (except, RETURN_MASK_ERROR)
-    {
-      if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
-       throw_exception (except);
-    }
-  END_CATCH
-
-  discard_cleanups (back_to);
-  return return_val;
-}
-
-VEC (char_ptr) *
-default_make_symbol_completion_list (const char *text, const char *word,
-                                    enum type_code code)
+void
+default_collect_symbol_completion_matches (completion_tracker &tracker,
+                                          const char *text, const char *word,
+                                          enum type_code code)
 {
-  return default_make_symbol_completion_list_break_on (text, word, "", code);
+  return default_collect_symbol_completion_matches_break_on (tracker,
+                                                            text, word, "",
+                                                            code);
 }
 
-/* Return a vector of all symbols (regardless of class) which begin by
-   matching TEXT.  If the answer is no symbols, then the return value
-   is NULL.  */
+/* Collect all symbols (regardless of class) which begin by matching
+   TEXT.  */
 
-VEC (char_ptr) *
-make_symbol_completion_list (const char *text, const char *word)
+void
+collect_symbol_completion_matches (completion_tracker &tracker,
+                                  const char *text, const char *word)
 {
-  return current_language->la_make_symbol_completion_list (text, word,
-                                                          TYPE_CODE_UNDEF);
+  current_language->la_collect_symbol_completion_matches (tracker,
+                                                         text, word,
+                                                         TYPE_CODE_UNDEF);
 }
 
-/* Like make_symbol_completion_list, but only return STRUCT_DOMAIN
-   symbols whose type code is CODE.  */
+/* Like collect_symbol_completion_matches, but only collect
+   STRUCT_DOMAIN symbols whose type code is CODE.  */
 
-VEC (char_ptr) *
-make_symbol_completion_type (const char *text, const char *word,
-                            enum type_code code)
+void
+collect_symbol_completion_matches_type (completion_tracker &tracker,
+                                       const char *text, const char *word,
+                                       enum type_code code)
 {
   gdb_assert (code == TYPE_CODE_UNION
              || code == TYPE_CODE_STRUCT
              || code == TYPE_CODE_ENUM);
-  return current_language->la_make_symbol_completion_list (text, word, code);
+  current_language->la_collect_symbol_completion_matches (tracker,
+                                                         text, word, code);
 }
 
-/* Like make_symbol_completion_list, but returns a list of symbols
-   defined in all source files name SRCFILE.  */
+/* Like collect_symbol_completion_matches, but collects a list of
+   symbols defined in all source files named SRCFILE.  */
 
-static VEC (char_ptr) *
-make_file_symbol_completion_list_1 (const char *text, const char *word,
-                                   const char *srcfile)
+void
+collect_file_symbol_completion_matches (completion_tracker &tracker,
+                                       const char *text, const char *word,
+                                       const char *srcfile)
 {
   /* The symbol we are completing on.  Points in same buffer as text.  */
   const char *sym_text;
@@ -5345,7 +5291,7 @@ make_file_symbol_completion_list_1 (const char *text, const char *word,
       /* A double-quoted string is never a symbol, nor does it make sense
          to complete it any other way.  */
       {
-       return NULL;
+       return;
       }
     else
       {
@@ -5361,42 +5307,11 @@ make_file_symbol_completion_list_1 (const char *text, const char *word,
   iterate_over_symtabs (srcfile, [&] (symtab *s)
     {
       add_symtab_completions (SYMTAB_COMPUNIT (s),
+                             tracker,
                              sym_text, sym_text_len,
                              text, word, TYPE_CODE_UNDEF);
       return false;
     });
-
-  return (return_val);
-}
-
-/* Wrapper around make_file_symbol_completion_list_1
-   to handle MAX_COMPLETIONS_REACHED_ERROR.  */
-
-VEC (char_ptr) *
-make_file_symbol_completion_list (const char *text, const char *word,
-                                 const char *srcfile)
-{
-  struct cleanup *back_to, *cleanups;
-
-  completion_tracker = new_completion_tracker ();
-  cleanups = make_cleanup_free_completion_tracker (&completion_tracker);
-  return_val = NULL;
-  back_to = make_cleanup (do_free_completion_list, &return_val);
-
-  TRY
-    {
-      make_file_symbol_completion_list_1 (text, word, srcfile);
-    }
-  CATCH (except, RETURN_MASK_ERROR)
-    {
-      if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
-       throw_exception (except);
-    }
-  END_CATCH
-
-  discard_cleanups (back_to);
-  do_cleanups (cleanups);
-  return return_val;
 }
 
 /* A helper function for make_source_files_completion_list.  It adds
@@ -5405,7 +5320,7 @@ make_file_symbol_completion_list (const char *text, const char *word,
 
 static void
 add_filename_to_list (const char *fname, const char *text, const char *word,
-                     VEC (char_ptr) **list)
+                     completion_list *list)
 {
   char *newobj;
   size_t fnlen = strlen (fname);
@@ -5430,7 +5345,7 @@ add_filename_to_list (const char *fname, const char *text, const char *word,
       newobj[text - word] = '\0';
       strcat (newobj, fname);
     }
-  VEC_safe_push (char_ptr, *list, newobj);
+  list->emplace_back (newobj);
 }
 
 static int
@@ -5458,7 +5373,7 @@ struct add_partial_filename_data
   const char *text;
   const char *word;
   int text_len;
-  VEC (char_ptr) **list;
+  completion_list *list;
 };
 
 /* A callback for map_partial_symbol_filenames.  */
@@ -5490,19 +5405,18 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
     }
 }
 
-/* Return a vector of all source files whose names begin with matching
+/* Return a list of all source files whose names begin with matching
    TEXT.  The file names are looked up in the symbol tables of this
-   program.  If the answer is no matchess, then the return value is
-   NULL.  */
+   program.  */
 
-VEC (char_ptr) *
+completion_list
 make_source_files_completion_list (const char *text, const char *word)
 {
   struct compunit_symtab *cu;
   struct symtab *s;
   struct objfile *objfile;
   size_t text_len = strlen (text);
-  VEC (char_ptr) *list = NULL;
+  completion_list list;
   const char *base_name;
   struct add_partial_filename_data datum;
   struct cleanup *back_to;
@@ -5510,8 +5424,6 @@ make_source_files_completion_list (const char *text, const char *word)
   if (!have_full_symbols () && !have_partial_symbols ())
     return list;
 
-  back_to = make_cleanup (do_free_completion_list, &list);
-
   filename_seen_cache filenames_seen;
 
   ALL_FILETABS (objfile, cu, s)
@@ -5547,8 +5459,6 @@ make_source_files_completion_list (const char *text, const char *word)
   map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
                        0 /*need_fullname*/);
 
-  discard_cleanups (back_to);
-
   return list;
 }
 \f
index 5261a6940c955f2d3ceaef0f7c131c519e13eea2..8b975ad44f03540799086b533f84e5b1f295bb8c 100644 (file)
@@ -25,6 +25,7 @@
 #include "gdbtypes.h"
 #include "common/enum-flags.h"
 #include "common/function-view.h"
+#include "completer.h"
 
 /* Opaque declarations.  */
 struct ui_file;
@@ -1498,22 +1499,28 @@ extern void forget_cached_source_info (void);
 
 extern void select_source_symtab (struct symtab *);
 
-extern VEC (char_ptr) *default_make_symbol_completion_list_break_on
-  (const char *text, const char *word, const char *break_on,
+extern void default_collect_symbol_completion_matches_break_on
+  (completion_tracker &tracker,
+   const char *text, const char *word, const char *break_on,
    enum type_code code);
-extern VEC (char_ptr) *default_make_symbol_completion_list (const char *,
-                                                           const char *,
-                                                           enum type_code);
-extern VEC (char_ptr) *make_symbol_completion_list (const char *, const char *);
-extern VEC (char_ptr) *make_symbol_completion_type (const char *, const char *,
+extern void default_collect_symbol_completion_matches
+  (completion_tracker &tracker,
+   const char *,
+   const char *,
+   enum type_code);
+extern void collect_symbol_completion_matches (completion_tracker &tracker,
+                                              const char *, const char *);
+extern void collect_symbol_completion_matches_type (completion_tracker &tracker,
+                                                   const char *, const char *,
                                                    enum type_code);
 
-extern VEC (char_ptr) *make_file_symbol_completion_list (const char *,
-                                                        const char *,
-                                                        const char *);
+extern void collect_file_symbol_completion_matches (completion_tracker &tracker,
+                                                   const char *,
+                                                   const char *,
+                                                   const char *);
 
-extern VEC (char_ptr) *make_source_files_completion_list (const char *,
-                                                         const char *);
+extern completion_list
+  make_source_files_completion_list (const char *, const char *);
 
 /* symtab.c */
 
index 17261cc77263ba980206cc7bb52c0b25119e4888..4c53efdd61cbf05a204e7d501cd4c2e266574e6d 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -2023,7 +2023,7 @@ init_main (void)
 
   /* Setup important stuff for command line editing.  */
   rl_completion_word_break_hook = gdb_completion_word_break_characters;
-  rl_completion_entry_function = readline_line_completion_function;
+  rl_attempted_completion_function = gdb_rl_attempted_completion_function;
   set_rl_completer_word_break_characters (default_word_break_characters ());
   rl_completer_quote_characters = get_gdb_completer_quote_characters ();
   rl_completion_display_matches_hook = cli_display_match_list;
index e52f7894109c6392b00908cce0b2c58e0e0c1eaf..7ecfaec5efbea5c6864816f7a73055c4264e089d 100644 (file)
@@ -353,14 +353,15 @@ tui_default_win_viewport_height (enum tui_win_type type,
 /* Complete possible layout names.  TEXT is the complete text entered so
    far, WORD is the word currently being completed.  */
 
-static VEC (char_ptr) *
+static void
 layout_completer (struct cmd_list_element *ignore,
+                 completion_tracker &tracker,
                  const char *text, const char *word)
 {
   static const char *layout_names [] =
     { "src", "asm", "split", "regs", "next", "prev", NULL };
 
-  return complete_on_enum (layout_names, text, word);
+  complete_on_enum (tracker, layout_names, text, word);
 }
 
 /* Function to initialize gdb commands, for tui window layout
index 3f9a007b19ffcba40fef0710b50fad099564cfe2..c41820335b2d47971ad8f6403b6c904aefbcb400 100644 (file)
@@ -668,24 +668,23 @@ tui_reg_command (char *args, int from_tty)
 /* Complete names of register groups, and add the special "prev" and "next"
    names.  */
 
-static VEC (char_ptr) *
+static void
 tui_reggroup_completer (struct cmd_list_element *ignore,
+                       completion_tracker &tracker,
                        const char *text, const char *word)
 {
-  VEC (char_ptr) *result = NULL;
   static const char *extra[] = { "next", "prev", NULL };
   size_t len = strlen (word);
   const char **tmp;
 
-  result = reggroup_completer (ignore, text, word);
+  reggroup_completer (ignore, tracker, text, word);
 
+  /* XXXX use complete_on_enum instead?  */
   for (tmp = extra; *tmp != NULL; ++tmp)
     {
       if (strncmp (word, *tmp, len) == 0)
-       VEC_safe_push (char_ptr, result, xstrdup (*tmp));
+       tracker.add_completion (gdb::unique_xmalloc_ptr<char> (xstrdup (*tmp)));
     }
-
-  return result;
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
index f49d7d5b87e0d090be54ce42bbf4622b19da8a76..e0df667b291e9e988211eebd73ca3dd3ef69e4d9 100644 (file)
@@ -359,12 +359,12 @@ tui_set_var_cmd (char *null_args, int from_tty, struct cmd_list_element *c)
    window names 'next' and 'prev' will also be considered as possible
    completions of the window name.  */
 
-static VEC (char_ptr) *
-window_name_completer (int include_next_prev_p,
+static void
+window_name_completer (completion_tracker &tracker,
+                      int include_next_prev_p,
                       const char *text, const char *word)
 {
   VEC (const_char_ptr) *completion_name_vec = NULL;
-  VEC (char_ptr) *matches_vec;
   int win_type;
 
   for (win_type = SRC_WIN; win_type < MAX_MAJOR_WINDOWS; win_type++)
@@ -398,39 +398,39 @@ window_name_completer (int include_next_prev_p,
     }
 
   VEC_safe_push (const_char_ptr, completion_name_vec, NULL);
-  matches_vec
-    = complete_on_enum (VEC_address (const_char_ptr, completion_name_vec),
-                       text, word);
+  complete_on_enum (tracker,
+                   VEC_address (const_char_ptr, completion_name_vec),
+                   text, word);
 
   VEC_free (const_char_ptr, completion_name_vec);
-
-  return matches_vec;
 }
 
 /* Complete possible window names to focus on.  TEXT is the complete text
    entered so far, WORD is the word currently being completed.  */
 
-static VEC (char_ptr) *
+static void
 focus_completer (struct cmd_list_element *ignore,
-                 const char *text, const char *word)
+                completion_tracker &tracker,
+                const char *text, const char *word)
 {
-  return window_name_completer (1, text, word);
+  window_name_completer (tracker, 1, text, word);
 }
 
 /* Complete possible window names for winheight command.  TEXT is the
    complete text entered so far, WORD is the word currently being
    completed.  */
 
-static VEC (char_ptr) *
+static void
 winheight_completer (struct cmd_list_element *ignore,
+                    completion_tracker &tracker,
                     const char *text, const char *word)
 {
   /* The first word is the window name.  That we can complete.  Subsequent
      words can't be completed.  */
   if (word != text)
-    return NULL;
+    return;
 
-  return window_name_completer (0, text, word);
+  window_name_completer (tracker, 0, text, word);
 }
 
 /* Function to initialize gdb commands, for tui window
index be01f0fe34cf4a4fcfbea6bc08844f74ad368e95..ec615b36630d7a7e79a05e1d262c27a3003d732c 100644 (file)
@@ -41,6 +41,7 @@
 #include "cp-abi.h"
 #include "user-regs.h"
 #include <algorithm>
+#include "completer.h"
 
 /* Prototypes for exported functions.  */
 
@@ -2144,14 +2145,12 @@ lookup_only_internalvar (const char *name)
   return NULL;
 }
 
-/* Complete NAME by comparing it to the names of internal variables.
-   Returns a vector of newly allocated strings, or NULL if no matches
-   were found.  */
+/* Complete NAME by comparing it to the names of internal
+   variables.  */
 
-VEC (char_ptr) *
-complete_internalvar (const char *name)
+void
+complete_internalvar (completion_tracker &tracker, const char *name)
 {
-  VEC (char_ptr) *result = NULL;
   struct internalvar *var;
   int len;
 
@@ -2160,12 +2159,10 @@ complete_internalvar (const char *name)
   for (var = internalvars; var; var = var->next)
     if (strncmp (var->name, name, len) == 0)
       {
-       char *r = xstrdup (var->name);
+       gdb::unique_xmalloc_ptr<char> copy (xstrdup (var->name));
 
-       VEC_safe_push (char_ptr, result, r);
+       tracker.add_completion (std::move (copy));
       }
-
-  return result;
 }
 
 /* Create an internal variable with name NAME and with a void value.
index fb7f13d29423093560723d47b238987613bdc3c3..6dee80af339b1abd1e7a65fe35172d64ec41f892 100644 (file)
@@ -927,7 +927,8 @@ extern struct internalvar *lookup_only_internalvar (const char *name);
 
 extern struct internalvar *create_internalvar (const char *name);
 
-extern VEC (char_ptr) *complete_internalvar (const char *name);
+extern void complete_internalvar (completion_tracker &tracker,
+                                 const char *name);
 
 /* An internalvar can be dynamically computed by supplying a vector of
    function pointers to perform various operations.  */
This page took 0.081001 seconds and 4 git commands to generate.