This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] PR gdb/17960 - Move completion_tracker_t into the completion API.
- From: Keith Seitz <keiths at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Mon, 16 Feb 2015 12:40:53 -0800
- Subject: [PATCH] PR gdb/17960 - Move completion_tracker_t into the completion API.
- Authentication-results: sourceware.org; auth=none
The bug itself is easily demonstrated:
$ gdb -nx -q gdb
(gdb) b gdb.c:ma<TAB>
./../src/gdb/completer.c:837: internal-error: maybe_add_completion:
Assertion `tracker != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
This occurs because the code path in this case is:
complete_line
- complete_line_internal
-- location_completer
--- make_file_symbol_completion_list
(...)
---- completion_list_add_name
----- maybe_add_completion
----> gdb_assert (tracker != NULL);
The tracker in maybe_add_completion is a static global in symtab.c called
completion_tracker. It is initialized by
default_make_symbol_completion_list_break_on_1 (which is a defaulted
language vector method). In this case, this function is never called
and completion_tracker is left NULL/uninitialized.
This patch refactors the completion API, adding a completion_tracker_t
to the list of function arguments for all completion functions, removing
the (file) global completion_tracker in symtab.c that is the cause of this bug.
gdb/ChangeLog
PR gdb/17960
* cli/cli-decode.c (find_cmd): Use maybe_add_completion to
implement completion tracking.
* command.h (completer_ftype, completer_ftype_void,
set_cmd_completer, set_cmd_completer_handle_brkchars,
lookup_cmd, lookup_cmd_1, complete_on_cmdlist,
complete_on_enum): Move to completer.h.
* completer.c (location_completer): Use TRY_CATCH to catch
max completion exception from make_file_symbol_completion_list,
make_symbol_completion_list, and make_source_files_completion_list.
(complete_line_internal): Empty the tracker when a unique
command completion is found.
(complete_line): Instantiate a new tracker earlier and pass this
to complete_line_internal.
If the list of completions is bigger than those tracked,
completion tracking was not implemented for the requested completion;
re-filter the list for maximum completions. Otherwise simply
copy the result.
* completer.h (max_completions, new_completion_tracker,
make_cleanup_free_completion_tracker, enum maybe_add_completion_enum,
maybe_add_completion, throw_max_completions_reached_error): Move
declarations to earlier in file.
(completer_ftype, completer_ftype_void, set_cmd_completer,
set_cmd_completer_handle_brkchars, lookup_cmd, lookup_cmd_1,
complete_on_cmdlist, complete_on_enum): Move declarations here
from command.h.
* symtab.c (COMPLETION_LIST_ADD_SYMBOL,
MCOMPLETION_LIST_ADD_SYMBOL): Add `tracker' as first argument.
All users updated.
(struct add_name_data): Add `tracker' member.
(default_make_symbol_completion_list_break_on_1): Add tracker
to call data.
Do not instantiate a completion tracker here -- use the one
passed instead.
(add_filename_to_list): Implement completion tracking.
(struct add_partial_filename_data): Add `tracker' member.
(make_source_files_completion_list): Add tracker to call data.
* symtab.h: Include completer.h.
* ada-lang.c, breakpoint.c, cli/cli-cmds.c, cli/cli-decode.h,
corefile.c, cp-abi.c, f-lang.c, infrun.c, interps.c, language.h,
python/py-cmd.c, top.c, symtab.c: Updated for completion API change.
gdb/testsuite/ChangeLog
PR gdb/17960
* gdb.base/completion.exp: Add location completer tests.
---
gdb/ada-lang.c | 3 -
gdb/breakpoint.c | 6 +
gdb/cli/cli-cmds.c | 6 +
gdb/cli/cli-decode.c | 58 ++++++++---
gdb/cli/cli-decode.h | 1
gdb/command.h | 31 ------
gdb/completer.c | 177 +++++++++++++++++++++++----------
gdb/completer.h | 168 +++++++++++++++++++------------
gdb/corefile.c | 3 -
gdb/cp-abi.c | 3 -
gdb/f-lang.c | 6 +
gdb/infrun.c | 5 +
gdb/interps.c | 1
gdb/language.h | 3 -
gdb/python/py-cmd.c | 5 +
gdb/symtab.c | 166 ++++++++++++++++++-------------
gdb/symtab.h | 35 +++----
gdb/testsuite/gdb.base/completion.exp | 78 +++++++++++++++
gdb/top.c | 2
19 files changed, 492 insertions(+), 265 deletions(-)
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 562627a..161e3aa 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -6191,7 +6191,8 @@ ada_complete_symbol_matcher (const char *name, void *user_data)
the entire command on which completion is made. */
static VEC (char_ptr) *
-ada_make_symbol_completion_list (const char *text0, const char *word,
+ada_make_symbol_completion_list (completion_tracker_t tracker,
+ const char *text0, const char *word,
enum type_code code)
{
char *text;
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a7cc6cb..2773f53 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1020,6 +1020,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
static VEC (char_ptr) *
condition_completer (struct cmd_list_element *cmd,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
const char *space;
@@ -1058,7 +1059,7 @@ condition_completer (struct cmd_list_element *cmd,
/* We're completing the expression part. */
text = skip_spaces_const (space);
- return expression_completer (cmd, text, word);
+ return expression_completer (cmd, tracker, text, word);
}
/* condition N EXP -- set break condition of breakpoint N to EXP. */
@@ -15393,11 +15394,12 @@ catching_syscall_number (int syscall_number)
/* Complete syscall names. Used by "catch syscall". */
static VEC (char_ptr) *
catch_syscall_completer (struct cmd_list_element *cmd,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
const char **list = get_syscall_names (get_current_arch ());
VEC (char_ptr) *retlist
- = (list == NULL) ? NULL : complete_on_enum (list, word, word);
+ = (list == NULL) ? NULL : complete_on_enum (tracker, list, word, word);
xfree (list);
return retlist;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index e46f036..c2b4604 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1344,7 +1344,7 @@ valid_command_p (const char *command)
{
struct cmd_list_element *c;
- c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
+ c = lookup_cmd_1 (NULL, &command, cmdlist, NULL, 1);
if (c == NULL || c == (struct cmd_list_element *) -1)
return FALSE;
@@ -1467,12 +1467,12 @@ alias_command (char *args, int from_tty)
alias_prefix = dyn_string_buf (alias_prefix_dyn_string);
command_prefix = dyn_string_buf (command_prefix_dyn_string);
- c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
+ c_command = lookup_cmd_1 (NULL, &command_prefix, cmdlist, NULL, 1);
/* We've already tried to look up COMMAND. */
gdb_assert (c_command != NULL
&& c_command != (struct cmd_list_element *) -1);
gdb_assert (c_command->prefixlist != NULL);
- c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
+ c_alias = lookup_cmd_1 (NULL, &alias_prefix, cmdlist, NULL, 1);
if (c_alias != c_command)
error (_("ALIAS and COMMAND prefixes do not match."));
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 4ec6ec0..b31772c 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -35,7 +35,8 @@ static struct cmd_list_element *delete_cmd (const char *name,
struct cmd_list_element **posthook,
struct cmd_list_element **posthookee);
-static struct cmd_list_element *find_cmd (const char *command,
+static struct cmd_list_element *find_cmd (completion_tracker_t tracker,
+ const char *command,
int len,
struct cmd_list_element *clist,
int ignore_help_classes,
@@ -649,6 +650,7 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class class,
static VEC (char_ptr) *
integer_unlimited_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
static const char * const keywords[] =
@@ -657,7 +659,7 @@ integer_unlimited_completer (struct cmd_list_element *ignore,
NULL,
};
- return complete_on_enum (keywords, text, word);
+ return complete_on_enum (tracker, keywords, text, word);
}
/* Add element named NAME to both the set and show command LISTs (the
@@ -1215,22 +1217,43 @@ help_cmd_list (struct cmd_list_element *list, enum command_class class,
found in nfound. */
static struct cmd_list_element *
-find_cmd (const char *command, int len, struct cmd_list_element *clist,
+find_cmd (completion_tracker_t tracker,
+ const char *command, int len, struct cmd_list_element *clist,
int ignore_help_classes, int *nfound)
{
struct cmd_list_element *found, *c;
+ int max_reached;
found = (struct cmd_list_element *) NULL;
*nfound = 0;
- for (c = clist; c; c = c->next)
+ for (c = clist, max_reached = 0; c; c = c->next)
if (!strncmp (command, c->name, len)
&& (!ignore_help_classes || c->func))
{
- found = c;
- (*nfound)++;
- if (c->name[len] == '\0')
+ enum maybe_add_completion_enum add_status;
+
+ add_status = (tracker == NULL
+ ? MAYBE_ADD_COMPLETION_OK
+ : maybe_add_completion (tracker, c->name));
+ switch (add_status)
{
- *nfound = 1;
+ case MAYBE_ADD_COMPLETION_OK:
+ found = c;
+ (*nfound)++;
+ if (c->name[len] == '\0')
+ {
+ *nfound = 1;
+ return found;
+ }
+ break;
+ case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
+ found = c;
+ (*nfound)++;
+ return found;
+ case MAYBE_ADD_COMPLETION_MAX_REACHED:
+ return found;
+ case MAYBE_ADD_COMPLETION_DUPLICATE:
+ continue;
break;
}
}
@@ -1336,7 +1359,8 @@ valid_user_defined_cmd_name_p (const char *name)
the struct cmd_list_element is NULL). */
struct cmd_list_element *
-lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
+lookup_cmd_1 (completion_tracker_t tracker,
+ const char **text, struct cmd_list_element *clist,
struct cmd_list_element **result_list, int ignore_help_classes)
{
char *command;
@@ -1365,7 +1389,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
/* Look it up. */
found = 0;
nfound = 0;
- found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
+ found = find_cmd (tracker, command, len, clist, ignore_help_classes,
+ &nfound);
/* We didn't find the command in the entered case, so lower case it
and search again. */
@@ -1377,7 +1402,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
command[tmp] = isupper (x) ? tolower (x) : x;
}
- found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
+ found = find_cmd (tracker, command, len, clist, ignore_help_classes,
+ &nfound);
}
/* If nothing matches, we have a simple failure. */
@@ -1414,7 +1440,7 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
if (found->prefixlist)
{
- c = lookup_cmd_1 (text, *found->prefixlist, result_list,
+ c = lookup_cmd_1 (tracker, text, *found->prefixlist, result_list,
ignore_help_classes);
if (!c)
{
@@ -1491,7 +1517,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list, char *cmdtype,
if (!*line)
error (_("Lack of needed %scommand"), cmdtype);
- c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
+ c = lookup_cmd_1 (NULL, line, list, &last_list, ignore_help_classes);
if (!c)
{
@@ -1718,7 +1744,7 @@ lookup_cmd_composition (const char *text,
/* Look it up. */
*cmd = 0;
nfound = 0;
- *cmd = find_cmd (command, len, cur_list, 1, &nfound);
+ *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
/* We didn't find the command in the entered case, so lower case
it and search again.
@@ -1731,7 +1757,7 @@ lookup_cmd_composition (const char *text,
command[tmp] = isupper (x) ? tolower (x) : x;
}
- *cmd = find_cmd (command, len, cur_list, 1, &nfound);
+ *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
}
if (*cmd == CMD_LIST_AMBIGUOUS)
@@ -1842,7 +1868,7 @@ complete_on_cmdlist (struct cmd_list_element *list,
"oobar"; if WORD is "baz/foo", return "baz/foobar". */
VEC (char_ptr) *
-complete_on_enum (const char *const *enumlist,
+complete_on_enum (completion_tracker_t ignore, const char *const *enumlist,
const char *text, const char *word)
{
VEC (char_ptr) *matchlist = NULL;
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index ec89325..bbedb52 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -23,6 +23,7 @@
/* Include the public interfaces. */
#include "command.h"
+#include "completer.h"
struct re_pattern_buffer;
diff --git a/gdb/command.h b/gdb/command.h
index 956eeaa..35d61bd 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -156,19 +156,6 @@ typedef void cmd_sfunc_ftype (char *args, int from_tty,
extern void set_cmd_sfunc (struct cmd_list_element *cmd,
cmd_sfunc_ftype *sfunc);
-typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
- const char *, const char *);
-
-typedef void completer_ftype_void (struct cmd_list_element *,
- const char *, const char *);
-
-extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
-
-/* Set the completer_handle_brkchars callback. */
-
-extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
- completer_ftype_void *);
-
/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
around in cmd objects to test the value of the commands sfunc(). */
extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
@@ -189,18 +176,6 @@ extern void execute_cmd_post_hook (struct cmd_list_element *cmd);
/* Return the type of the command. */
extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
-/* Flag for an ambiguous cmd_list result. */
-#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
-
-extern struct cmd_list_element *lookup_cmd (const char **,
- struct cmd_list_element *, char *,
- int, int);
-
-extern struct cmd_list_element *lookup_cmd_1 (const char **,
- struct cmd_list_element *,
- struct cmd_list_element **,
- int);
-
extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,
const char * );
@@ -225,12 +200,6 @@ 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 VEC (char_ptr) *complete_on_enum (const char *const *enumlist,
- const char *, const char *);
-
/* Functions that implement commands about CLI commands. */
extern void help_list (struct cmd_list_element *, const char *,
diff --git a/gdb/completer.c b/gdb/completer.c
index add79cc..67644d1 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -107,7 +107,8 @@ readline_line_completion_function (const char *text, int matches)
/* 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) *
-noop_completer (struct cmd_list_element *ignore,
+noop_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ignore2,
const char *text, const char *prefix)
{
return NULL;
@@ -115,7 +116,8 @@ noop_completer (struct cmd_list_element *ignore,
/* Complete on filenames. */
VEC (char_ptr) *
-filename_completer (struct cmd_list_element *ignore,
+filename_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ignore2,
const char *text, const char *word)
{
int subsequent_name;
@@ -184,7 +186,8 @@ filename_completer (struct cmd_list_element *ignore,
etc. */
VEC (char_ptr) *
-location_completer (struct cmd_list_element *ignore,
+location_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
int n_syms, n_files, ix;
@@ -260,18 +263,41 @@ 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);
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ list = make_file_symbol_completion_list (tracker, symbol_start,
+ word, file_to_match);
+ }
+ if (e.reason < 0)
+ list = NULL;
xfree (file_to_match);
}
else
{
- list = make_symbol_completion_list (symbol_start, word);
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ list = make_symbol_completion_list (tracker, symbol_start, word);
+ }
+ if (e.reason < 0)
+ list = NULL;
+
/* If text includes characters which cannot appear in a file
name, they cannot be asking for completion on files. */
if (strcspn (text,
gdb_completer_file_name_break_characters) == text_len)
- fn_list = make_source_files_completion_list (text, text);
+ {
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ fn_list = make_source_files_completion_list (tracker, text,
+ text);
+ }
+ if (e.reason < 0)
+ fn_list = NULL;
+ }
}
n_syms = VEC_length (char_ptr, list);
@@ -326,7 +352,14 @@ location_completer (struct cmd_list_element *ignore,
{
/* 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);
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ list = make_symbol_completion_list (tracker, orig_text, word);
+ }
+ if (e.reason < 0)
+ list = NULL;
}
return list;
@@ -389,7 +422,8 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
names, but some language parsers also have support for completing
field names. */
VEC (char_ptr) *
-expression_completer (struct cmd_list_element *ignore,
+expression_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
struct type *type = NULL;
@@ -434,7 +468,8 @@ 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);
+ result = make_symbol_completion_type (tracker, fieldname, fieldname,
+ code);
do_cleanups (cleanup);
return result;
}
@@ -448,7 +483,7 @@ expression_completer (struct cmd_list_element *ignore,
;
/* Not ideal but it is what we used to do before... */
- return location_completer (ignore, p, word);
+ return location_completer (ignore, tracker, p, word);
}
/* See definition in completer.h. */
@@ -526,7 +561,7 @@ complete_line_internal_reason;
*/
static VEC (char_ptr) *
-complete_line_internal (const char *text,
+complete_line_internal (completion_tracker_t tracker, const char *text,
const char *line_buffer, int point,
complete_line_internal_reason reason)
{
@@ -572,7 +607,21 @@ complete_line_internal (const char *text,
}
else
{
- c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes);
+ /* There are two possible scenarios:
+ 1) The user is searching for completions to a command
+ 2) The user is attempting to complete the argument of
+ a specific command.
+
+ In either case, lookup_cmd_1 will increment the tracker.
+ However, for case #2, the tracker's results must be cleared,
+ since we don't want the actual command lookup to be counted
+ by that command's completer function. If we didn't do this,
+ we'd end up with an off-by-one error between the tracker
+ and the returned completion list. */
+ c = lookup_cmd_1 (tracker, &p, cmdlist, &result_list,
+ ignore_help_classes);
+ if (c != CMD_LIST_AMBIGUOUS && tracker != NULL)
+ htab_empty (tracker);
}
/* Move p up to the next interesting thing. */
@@ -658,7 +707,7 @@ complete_line_internal (const char *text,
else if (c->enums)
{
if (reason != handle_brkchars)
- list = complete_on_enum (c->enums, p, word);
+ list = complete_on_enum (tracker, c->enums, p, word);
rl_completer_word_break_characters =
gdb_completer_command_word_break_characters;
}
@@ -698,7 +747,7 @@ complete_line_internal (const char *text,
&& c->completer_handle_brkchars != NULL)
(*c->completer_handle_brkchars) (c, p, word);
if (reason != handle_brkchars && c->completer != NULL)
- list = (*c->completer) (c, p, word);
+ list = (*c->completer) (c, tracker, p, word);
}
}
else
@@ -744,7 +793,7 @@ complete_line_internal (const char *text,
else if (c->enums)
{
if (reason != handle_brkchars)
- list = complete_on_enum (c->enums, p, word);
+ list = complete_on_enum (tracker, c->enums, p, word);
}
else
{
@@ -774,7 +823,7 @@ complete_line_internal (const char *text,
&& c->completer_handle_brkchars != NULL)
(*c->completer_handle_brkchars) (c, p, word);
if (reason != handle_brkchars && c->completer != NULL)
- list = (*c->completer) (c, p, word);
+ list = (*c->completer) (c, tracker, p, word);
}
}
}
@@ -825,7 +874,7 @@ make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
/* See completer.h. */
enum maybe_add_completion_enum
-maybe_add_completion (completion_tracker_t tracker, char *name)
+maybe_add_completion (completion_tracker_t tracker, const char *name)
{
void **slot;
@@ -844,7 +893,7 @@ maybe_add_completion (completion_tracker_t tracker, char *name)
if (*slot != HTAB_EMPTY_ENTRY)
return MAYBE_ADD_COMPLETION_DUPLICATE;
- *slot = name;
+ *slot = (void *) name;
return (htab_elements (tracker) < max_completions
? MAYBE_ADD_COMPLETION_OK
@@ -875,52 +924,75 @@ complete_line (const char *text, const char *line_buffer, int point)
{
VEC (char_ptr) *list;
VEC (char_ptr) *result = NULL;
- struct cleanup *cleanups;
+ struct cleanup *tracker_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. */
+ list = complete_line_internal (tracker, text, line_buffer, point,
+ handle_completions);
- for (ix = 0, max_reached = 0;
- !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
- ++ix)
+ if (max_completions < 0)
{
- enum maybe_add_completion_enum add_status;
+ do_cleanups (cleanups);
+ return list;
+ }
+
+ make_cleanup_free_char_ptr_vec (list);
+
+ /* If complete_line_internal returned more completions than were
+ recorded by the completion tracker, then the completer function that
+ was run does not support completion tracking. In this case,
+ do a final test for too many completions.
- add_status = maybe_add_completion (tracker, candidate);
+ 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. */
- switch (add_status)
+ if (VEC_length (char_ptr, list) > htab_elements (tracker))
+ {
+ /* Clear the tracker so that we can re-use it to count the number
+ of returned completions. */
+ htab_empty (tracker);
+
+ for (ix = 0, max_reached = 0;
+ !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
+ ++ix)
{
- 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;
+ 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;
+ }
}
}
+ else
+ {
+ /* There is a valid tracker for the completion -- simply copy
+ the returned list into the return result. */
+ for (ix = 0; VEC_iterate (char_ptr, list, ix, candidate); ++ix)
+ VEC_safe_push (char_ptr, result, xstrdup (candidate));
+ }
do_cleanups (cleanups);
@@ -929,10 +1001,11 @@ complete_line (const char *text, const char *line_buffer, int point)
/* Complete on command names. Used by "help". */
VEC (char_ptr) *
-command_completer (struct cmd_list_element *ignore,
+command_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
- return complete_line_internal (word, text,
+ return complete_line_internal (tracker, word, text,
strlen (text), handle_help);
}
@@ -940,6 +1013,7 @@ command_completer (struct cmd_list_element *ignore,
VEC (char_ptr) *
signal_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ignore2,
const char *text, const char *word)
{
VEC (char_ptr) *return_val = NULL;
@@ -970,6 +1044,7 @@ signal_completer (struct cmd_list_element *ignore,
VEC (char_ptr) *
reg_or_group_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ingore2,
const char *text, const char *word)
{
VEC (char_ptr) *result = NULL;
@@ -1013,7 +1088,7 @@ gdb_completion_word_break_characters (void)
{
VEC (char_ptr) *list;
- list = complete_line_internal (rl_line_buffer, rl_line_buffer, rl_point,
+ list = complete_line_internal (NULL, rl_line_buffer, rl_line_buffer, rl_point,
handle_brkchars);
gdb_assert (list == NULL);
return rl_completer_word_break_characters;
diff --git a/gdb/completer.h b/gdb/completer.h
index 56e1a2b..7bc0543 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -18,7 +18,6 @@
#define COMPLETER_H 1
#include "gdb_vecs.h"
-#include "command.h"
/* Types of functions in struct match_list_displayer. */
@@ -33,6 +32,70 @@ typedef void mld_erase_entire_line_ftype (const struct match_list_displayer *);
typedef void mld_beep_ftype (const struct match_list_displayer *);
typedef int mld_read_key_ftype (const struct match_list_displayer *);
+/* Maximum number of candidates to consider before the completer
+ bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
+ disable limiting. */
+
+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, const char *name);
+
+/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
+
+extern void throw_max_completions_reached_error (void);
+
/* Interface between CLI/TUI and gdb_match_list_displayer. */
struct match_list_displayer
@@ -76,106 +139,83 @@ extern char *readline_line_completion_function (const char *text,
int matches);
extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *reg_or_group_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern char *get_gdb_completer_quote_characters (void);
extern char *gdb_completion_word_break_characters (void);
-/* Set the word break characters array to the corresponding set of
- chars, based on FN. This function is useful for cases when the
- completer doesn't know the type of the completion until some
- calculation is done (e.g., for Python functions). */
-
-extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
-
-/* Exported to linespec.c */
-
-extern const char *skip_quoted_chars (const char *, const char *,
- const char *);
-
-extern const char *skip_quoted (const char *);
-
-/* Maximum number of candidates to consider before the completer
- bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
- disable limiting. */
-
-extern int max_completions;
-
-/* Object to track how many unique completions have been generated.
- Used to limit the size of generated completion lists. */
+typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
+ completion_tracker_t,
+ const char *, const char *);
-typedef htab_t completion_tracker_t;
+typedef void completer_ftype_void (struct cmd_list_element *,
+ const char *, const char *);
-/* 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 void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
-extern completion_tracker_t new_completion_tracker (void);
+/* Set the completer_handle_brkchars callback. */
-/* Make a cleanup to free a completion tracker, and reset its pointer
- to NULL. */
+extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
+ completer_ftype_void *);
-extern struct cleanup *make_cleanup_free_completion_tracker
- (completion_tracker_t *tracker_ptr);
-
-/* Return values for maybe_add_completion. */
+/* Set the word break characters array to the corresponding set of
+ chars, based on FN. This function is useful for cases when the
+ completer doesn't know the type of the completion until some
+ calculation is done (e.g., for Python functions). */
-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,
+extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
- /* NAME has been recorded and max_completions has been reached
- (thus the caller can stop searching). */
- MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
+extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
+ const char *, const char *, int);
- /* max-completions entries has been reached.
- Whether NAME is a duplicate or not is not determined. */
- MAYBE_ADD_COMPLETION_MAX_REACHED,
+extern VEC (char_ptr) *complete_on_enum (completion_tracker_t,
+ const char *const *enumlist,
+ const char *, const char *);
- /* NAME has already been recorded.
- Note that this is never returned if completion tracking is disabled
- (max_completions < 0). */
- MAYBE_ADD_COMPLETION_DUPLICATE
-};
+/* Flag for an ambiguous cmd_list result. */
+#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
-/* 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.
+extern struct cmd_list_element *lookup_cmd (const char **,
+ struct cmd_list_element *, char *,
+ int, int);
- 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 struct cmd_list_element *lookup_cmd_1 (completion_tracker_t,
+ const char **,
+ struct cmd_list_element *,
+ struct cmd_list_element **,
+ int);
-extern enum maybe_add_completion_enum
- maybe_add_completion (completion_tracker_t tracker, char *name);
+/* Exported to linespec.c */
-/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
+extern const char *skip_quoted_chars (const char *, const char *,
+ const char *);
-extern void throw_max_completions_reached_error (void);
+extern const char *skip_quoted (const char *);
#endif /* defined (COMPLETER_H) */
diff --git a/gdb/corefile.c b/gdb/corefile.c
index a042e6d..309a93d 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -469,6 +469,7 @@ set_gnutarget_command (char *ignore, int from_tty,
static VEC (char_ptr) *
complete_set_gnutarget (struct cmd_list_element *cmd,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
static const char **bfd_targets;
@@ -486,7 +487,7 @@ complete_set_gnutarget (struct cmd_list_element *cmd,
bfd_targets[last + 1] = NULL;
}
- return complete_on_enum (bfd_targets, text, word);
+ return complete_on_enum (tracker, bfd_targets, text, word);
}
/* Set the gnutarget. */
diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c
index 9316c4c..4086d0c 100644
--- a/gdb/cp-abi.c
+++ b/gdb/cp-abi.c
@@ -355,6 +355,7 @@ set_cp_abi_cmd (char *args, int from_tty)
static VEC (char_ptr) *
cp_abi_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
static const char **cp_abi_names;
@@ -369,7 +370,7 @@ cp_abi_completer (struct cmd_list_element *ignore,
cp_abi_names[i] = NULL;
}
- return complete_on_enum (cp_abi_names, text, word);
+ return complete_on_enum (tracker, cp_abi_names, text, word);
}
/* Show the currently selected C++ ABI. */
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 8b61028..d772cfa 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -229,10 +229,12 @@ f_word_break_characters (void)
class. */
static VEC (char_ptr) *
-f_make_symbol_completion_list (const char *text, const char *word,
+f_make_symbol_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word,
enum type_code code)
{
- return default_make_symbol_completion_list_break_on (text, word, ":", code);
+ return default_make_symbol_completion_list_break_on (tracker, text, word,
+ ":", code);
}
const struct language_defn f_language_defn =
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 15589b6..75fe2e3 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6934,6 +6934,7 @@ Are you sure you want to change it? "),
static VEC (char_ptr) *
handle_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
@@ -6951,8 +6952,8 @@ handle_completer (struct cmd_list_element *ignore,
NULL,
};
- vec_signals = signal_completer (ignore, text, word);
- vec_keywords = complete_on_enum (keywords, word, word);
+ vec_signals = signal_completer (ignore, tracker, text, word);
+ vec_keywords = complete_on_enum (tracker, keywords, word, word);
return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
VEC_free (char_ptr, vec_signals);
diff --git a/gdb/interps.c b/gdb/interps.c
index 90b5b2d..2215ac1 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -438,6 +438,7 @@ interpreter_exec_cmd (char *args, int from_tty)
/* List the possible interpreters which could complete the given text. */
static VEC (char_ptr) *
interpreter_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ingore2,
const char *text, const char *word)
{
int textlen;
diff --git a/gdb/language.h b/gdb/language.h
index 436fd6e..b095093 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -301,7 +301,8 @@ struct language_defn
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,
+ VEC (char_ptr) *(*la_make_symbol_completion_list) (completion_tracker_t,
+ const char *text,
const char *word,
enum type_code code);
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index a5e96d6..2f95b46 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -347,6 +347,7 @@ cmdpy_completer_handle_brkchars (struct cmd_list_element *command,
static VEC (char_ptr) *
cmdpy_completer (struct cmd_list_element *command,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
PyObject *resultobj = NULL;
@@ -378,7 +379,7 @@ cmdpy_completer (struct cmd_list_element *command,
PyErr_Clear ();
}
else if (value >= 0 && value < (long) N_COMPLETERS)
- result = completers[value].completer (command, text, word);
+ result = completers[value].completer (command, tracker, text, word);
}
else
{
@@ -485,7 +486,7 @@ gdbpy_parse_command_name (const char *name,
prefix_text[i + 1] = '\0';
prefix_text2 = prefix_text;
- elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
+ elt = lookup_cmd_1 (NULL, &prefix_text2, *start_list, NULL, 1);
if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
{
PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5302afa..9f04966 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4994,29 +4994,21 @@ do_free_completion_list (void *list)
static VEC (char_ptr) *return_val;
-#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
- completion_list_add_name \
- (SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
+#define COMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
+ completion_list_add_name \
+ (tracker, SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
-#define MCOMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
- completion_list_add_name \
- (MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
-
-/* 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;
+#define MCOMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
+ completion_list_add_name \
+ ((tracker), MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
/* 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_t tracker,
+ const char *symname,
const char *sym_text, int sym_text_len,
const char *text, const char *word)
{
@@ -5051,7 +5043,7 @@ completion_list_add_name (const char *symname,
strcat (new, symname);
}
- add_status = maybe_add_completion (completion_tracker, new);
+ add_status = maybe_add_completion (tracker, new);
switch (add_status)
{
@@ -5075,7 +5067,8 @@ completion_list_add_name (const char *symname,
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_t tracker,
+ struct minimal_symbol *msymbol,
const char *sym_text, int sym_text_len,
const char *text, const char *word)
{
@@ -5093,7 +5086,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)
{
@@ -5114,9 +5108,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)
@@ -5127,7 +5123,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);
}
}
@@ -5178,9 +5175,9 @@ 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_t tracker, struct symbol *sym,
+ const char *sym_text, int sym_text_len,
+ const char *text, const char *word)
{
if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
{
@@ -5191,7 +5188,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);
}
}
@@ -5206,6 +5203,7 @@ struct add_name_data
int sym_text_len;
const char *text;
const char *word;
+ completion_tracker_t tracker;
/* Extra argument required for add_symtab_completions. */
enum type_code code;
@@ -5221,7 +5219,7 @@ add_macro_name (const char *name, const struct macro_definition *ignore,
{
struct add_name_data *datum = (struct add_name_data *) user_data;
- completion_list_add_name (name,
+ completion_list_add_name (datum->tracker, name,
datum->sym_text, datum->sym_text_len,
datum->text, datum->word);
}
@@ -5240,6 +5238,7 @@ symbol_completion_matcher (const char *name, void *user_data)
static void
add_symtab_completions (struct compunit_symtab *cust,
+ completion_tracker_t tracker,
const char *sym_text, int sym_text_len,
const char *text, const char *word,
enum type_code code)
@@ -5258,7 +5257,7 @@ 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);
}
@@ -5274,14 +5273,15 @@ symtab_expansion_callback (struct compunit_symtab *symtab,
{
struct add_name_data *datum = (struct add_name_data *) user_data;
- add_symtab_completions (symtab,
+ add_symtab_completions (symtab, datum->tracker,
datum->sym_text, datum->sym_text_len,
datum->text, datum->word,
datum->code);
}
static void
-default_make_symbol_completion_list_break_on_1 (const char *text,
+default_make_symbol_completion_list_break_on_1 (completion_tracker_t tracker,
+ const char *text,
const char *word,
const char *break_on,
enum type_code code)
@@ -5302,7 +5302,6 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
/* Length of sym_text. */
int sym_text_len;
struct add_name_data datum;
- struct cleanup *cleanups;
/* Now look for the symbol we are supposed to complete on. */
{
@@ -5373,14 +5372,12 @@ 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);
-
datum.sym_text = sym_text;
datum.sym_text_len = sym_text_len;
datum.text = text;
datum.word = word;
datum.code = code;
+ datum.tracker = tracker;
/* At this point scan through the misc symbol vectors and add each
symbol you find to the list. Eventually we want to ignore
@@ -5392,17 +5389,17 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
ALL_MSYMBOLS (objfile, msymbol)
{
QUIT;
- MCOMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text,
- word);
+ MCOMPLETION_LIST_ADD_SYMBOL (tracker, msymbol, sym_text,
+ sym_text_len, text, word);
- completion_list_objc_symbol (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,
+ add_symtab_completions (cust, tracker, sym_text, sym_text_len, text, word,
code);
/* Look through the partial symtabs for all symbols which begin
@@ -5430,15 +5427,15 @@ 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,
- word);
- completion_list_add_fields (sym, sym_text, sym_text_len, text,
- word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
+ sym_text_len, text, word);
+ 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,
- word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
+ sym_text_len, text, word);
}
/* Stop when we encounter an enclosing function. Do not stop for
@@ -5455,11 +5452,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
@@ -5487,12 +5486,11 @@ 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, &datum);
}
-
- do_cleanups (cleanups);
}
VEC (char_ptr) *
-default_make_symbol_completion_list_break_on (const char *text,
+default_make_symbol_completion_list_break_on (completion_tracker_t tracker,
+ const char *text,
const char *word,
const char *break_on,
enum type_code code)
@@ -5505,7 +5503,7 @@ default_make_symbol_completion_list_break_on (const char *text,
TRY_CATCH (except, RETURN_MASK_ERROR)
{
- default_make_symbol_completion_list_break_on_1 (text, word,
+ default_make_symbol_completion_list_break_on_1 (tracker, text, word,
break_on, code);
}
if (except.reason < 0)
@@ -5519,10 +5517,12 @@ default_make_symbol_completion_list_break_on (const char *text,
}
VEC (char_ptr) *
-default_make_symbol_completion_list (const char *text, const char *word,
+default_make_symbol_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word,
enum type_code code)
{
- return default_make_symbol_completion_list_break_on (text, word, "", code);
+ return default_make_symbol_completion_list_break_on (tracker, text, word,
+ "", code);
}
/* Return a vector of all symbols (regardless of class) which begin by
@@ -5530,9 +5530,10 @@ default_make_symbol_completion_list (const char *text, const char *word,
is NULL. */
VEC (char_ptr) *
-make_symbol_completion_list (const char *text, const char *word)
+make_symbol_completion_list (completion_tracker_t tracker, const char *text,
+ const char *word)
{
- return current_language->la_make_symbol_completion_list (text, word,
+ return current_language->la_make_symbol_completion_list (tracker, text, word,
TYPE_CODE_UNDEF);
}
@@ -5540,13 +5541,14 @@ make_symbol_completion_list (const char *text, const char *word)
symbols whose type code is CODE. */
VEC (char_ptr) *
-make_symbol_completion_type (const char *text, const char *word,
- enum type_code code)
+make_symbol_completion_type (completion_tracker_t 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);
+ return current_language->la_make_symbol_completion_list (tracker, text,
+ word, code);
}
/* Like make_symbol_completion_list, but suitable for use as a
@@ -5554,16 +5556,18 @@ make_symbol_completion_type (const char *text, const char *word,
VEC (char_ptr) *
make_symbol_completion_list_fn (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
- return make_symbol_completion_list (text, word);
+ return make_symbol_completion_list (tracker, text, word);
}
/* Like make_symbol_completion_list, but returns a list of symbols
defined in a source file FILE. */
VEC (char_ptr) *
-make_file_symbol_completion_list (const char *text, const char *word,
+make_file_symbol_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word,
const char *srcfile)
{
struct symbol *sym;
@@ -5645,13 +5649,15 @@ make_file_symbol_completion_list (const char *text, const char *word,
b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), GLOBAL_BLOCK);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
+ word);
}
b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), STATIC_BLOCK);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
+ word);
}
return (return_val);
@@ -5662,11 +5668,13 @@ make_file_symbol_completion_list (const char *text, const char *word,
list as necessary. */
static void
-add_filename_to_list (const char *fname, const char *text, const char *word,
+add_filename_to_list (completion_tracker_t tracker,
+ const char *fname, const char *text, const char *word,
VEC (char_ptr) **list)
{
char *new;
size_t fnlen = strlen (fname);
+ enum maybe_add_completion_enum add_status;
if (word == text)
{
@@ -5688,7 +5696,22 @@ add_filename_to_list (const char *fname, const char *text, const char *word,
new[text - word] = '\0';
strcat (new, fname);
}
- VEC_safe_push (char_ptr, *list, new);
+
+ add_status = maybe_add_completion (tracker, new);
+ switch (add_status)
+ {
+ case MAYBE_ADD_COMPLETION_OK:
+ VEC_safe_push (char_ptr, *list, new);
+ break;
+ case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
+ VEC_safe_push (char_ptr, *list, new);
+ /* fall through */
+ case MAYBE_ADD_COMPLETION_MAX_REACHED:
+ throw_max_completions_reached_error ();
+ break;
+ case MAYBE_ADD_COMPLETION_DUPLICATE:
+ xfree (new);
+ }
}
static int
@@ -5717,6 +5740,7 @@ struct add_partial_filename_data
const char *word;
int text_len;
VEC (char_ptr) **list;
+ completion_tracker_t tracker;
};
/* A callback for map_partial_symbol_filenames. */
@@ -5734,7 +5758,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
{
/* This file matches for a completion; add it to the
current list of matches. */
- add_filename_to_list (filename, data->text, data->word, data->list);
+ add_filename_to_list (data->tracker, filename, data->text, data->word,
+ data->list);
}
else
{
@@ -5743,7 +5768,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
if (base_name != filename
&& !filename_seen (data->filename_seen_cache, base_name, 1)
&& filename_ncmp (base_name, data->text, data->text_len) == 0)
- add_filename_to_list (base_name, data->text, data->word, data->list);
+ add_filename_to_list (data->tracker, base_name, data->text,
+ data->word, data->list);
}
}
@@ -5753,7 +5779,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
NULL. */
VEC (char_ptr) *
-make_source_files_completion_list (const char *text, const char *word)
+make_source_files_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word)
{
struct compunit_symtab *cu;
struct symtab *s;
@@ -5783,7 +5810,7 @@ make_source_files_completion_list (const char *text, const char *word)
{
/* This file matches for a completion; add it to the current
list of matches. */
- add_filename_to_list (s->filename, text, word, &list);
+ add_filename_to_list (tracker, s->filename, text, word, &list);
}
else
{
@@ -5795,7 +5822,7 @@ make_source_files_completion_list (const char *text, const char *word)
if (base_name != s->filename
&& !filename_seen (filename_seen_cache, base_name, 1)
&& filename_ncmp (base_name, text, text_len) == 0)
- add_filename_to_list (base_name, text, word, &list);
+ add_filename_to_list (tracker, base_name, text, word, &list);
}
}
@@ -5804,6 +5831,7 @@ make_source_files_completion_list (const char *text, const char *word)
datum.word = word;
datum.text_len = text_len;
datum.list = &list;
+ datum.tracker = tracker;
map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
0 /*need_fullname*/);
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 0eb3a5b..572738a 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
#include "vec.h"
#include "gdb_vecs.h"
#include "gdbtypes.h"
+#include "completer.h"
/* Opaque declarations. */
struct ui_file;
@@ -1444,24 +1445,22 @@ 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,
- 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 *,
- enum type_code);
-extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *,
- const char *,
- const char *);
-
-extern VEC (char_ptr) *make_file_symbol_completion_list (const char *,
- const char *,
- const char *);
-
-extern VEC (char_ptr) *make_source_files_completion_list (const char *,
- const char *);
+ (completion_tracker_t tracker, const char *text, const char *word,
+ const char *break_on, enum type_code code);
+extern VEC (char_ptr) *default_make_symbol_completion_list
+ (completion_tracker_t tracker, const char *, const char *, enum type_code);
+extern VEC (char_ptr) *make_symbol_completion_list
+ (completion_tracker_t tracker, const char *, const char *);
+extern VEC (char_ptr) *make_symbol_completion_type
+ (completion_tracker_t, const char *, const char *, enum type_code);
+extern VEC (char_ptr) *make_symbol_completion_list_fn
+ (struct cmd_list_element *, completion_tracker_t, const char *, const char *);
+
+extern VEC (char_ptr) *make_file_symbol_completion_list
+ (completion_tracker_t, const char *, const char *, const char *);
+
+extern VEC (char_ptr) *make_source_files_completion_list
+ (completion_tracker_t, const char *, const char *);
/* symtab.c */
diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp
index f77bfe2..5afd851 100644
--- a/gdb/testsuite/gdb.base/completion.exp
+++ b/gdb/testsuite/gdb.base/completion.exp
@@ -777,6 +777,84 @@ gdb_test_multiple "" "$test" {
}
#
+# Tests for the location completer
+#
+
+# Turn off pending breakpoint support so that we don't get queried
+# all the time.
+gdb_test_no_output "set breakpoint pending off"
+
+set subsrc [string range $srcfile 0 [expr {[string length $srcfile] - 3}]]
+set test "tab complete break $subsrc"
+send_gdb "break $subsrc\t\t"
+gdb_test_multiple "" $test {
+ -re "break\.c.*break1\.c.*$gdb_prompt " {
+ send_gdb "1\t\n"
+ gdb_test_multiple "" $test {
+ -re ".*Function \"$srcfile2\" not defined\..*$gdb_prompt " {
+ pass $test
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+ }
+ }
+
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+}
+
+gdb_test "complete break $subsrc" "break\.c.*break1\.c"
+
+# gdb/17960
+set test "tab complete break $srcfile:ma"
+send_gdb "break $srcfile:ma\t"
+gdb_test_multiple "" $test {
+ -re "break $srcfile:main " {
+ send_gdb "\n"
+ gdb_test_multiple "" $test {
+ -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
+ pass $test
+ gdb_test_no_output "delete breakpoint \$bpnum" \
+ "delete breakpoint for $test"
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+ }
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+}
+
+gdb_test "complete break $srcfile:ma" "break\.c:main"
+
+set test "tab complete break need"
+send_gdb "break need\t"
+gdb_test_multiple "" $test {
+ -re "break need_malloc " {
+ send_gdb "\n"
+ gdb_test_multiple "" $test {
+ -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
+ pass $test
+ gdb_test_no_output "delete breakpoint \$bpnum" \
+ "delete breakpoint for $test"
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+ }
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+}
+
+gdb_test "complete break need" "need_malloc"
+
+#
# Completion limiting.
#
diff --git a/gdb/top.c b/gdb/top.c
index 8242e12..af5d923 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1673,7 +1673,7 @@ set_verbose (char *args, int from_tty, struct cmd_list_element *c)
const char *cmdname = "verbose";
struct cmd_list_element *showcmd;
- showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
+ showcmd = lookup_cmd_1 (NULL, &cmdname, showlist, NULL, 1);
gdb_assert (showcmd != NULL && showcmd != CMD_LIST_AMBIGUOUS);
if (info_verbose)