#include "completer.h"
#include "progspace-and-thread.h"
#include "common/gdb_optional.h"
+#include "filename-seen-cache.h"
/* Forward declarations for local functions. */
}
\f
-/* Cache to watch for file names already seen by filename_seen. */
-
-struct filename_seen_cache
-{
- /* Table of files seen so far. */
- htab_t tab;
- /* Initial size of the table. It automagically grows from here. */
-#define INITIAL_FILENAME_SEEN_CACHE_SIZE 100
-};
-
-/* filename_seen_cache constructor. */
-
-static struct filename_seen_cache *
-create_filename_seen_cache (void)
-{
- struct filename_seen_cache *cache = XNEW (struct filename_seen_cache);
-
- cache->tab = htab_create_alloc (INITIAL_FILENAME_SEEN_CACHE_SIZE,
- filename_hash, filename_eq,
- NULL, xcalloc, xfree);
-
- return cache;
-}
-
-/* Empty the cache, but do not delete it. */
-
-static void
-clear_filename_seen_cache (struct filename_seen_cache *cache)
-{
- htab_empty (cache->tab);
-}
-
-/* filename_seen_cache destructor.
- This takes a void * argument as it is generally used as a cleanup. */
-
-static void
-delete_filename_seen_cache (void *ptr)
-{
- struct filename_seen_cache *cache = (struct filename_seen_cache *) ptr;
-
- htab_delete (cache->tab);
- xfree (cache);
-}
-
-/* If FILE is not already in the table of files in CACHE, return zero;
- otherwise return non-zero. Optionally add FILE to the table if ADD
- is non-zero.
-
- NOTE: We don't manage space for FILE, we assume FILE lives as long
- as the caller needs. */
-
-static int
-filename_seen (struct filename_seen_cache *cache, const char *file, int add)
-{
- void **slot;
-
- /* Is FILE in tab? */
- slot = htab_find_slot (cache->tab, file, add ? INSERT : NO_INSERT);
- if (*slot != NULL)
- return 1;
-
- /* No; maybe add it to tab. */
- if (add)
- *slot = (char *) file;
-
- return 0;
-}
-
/* Data structure to maintain printing state for output_source_filename. */
struct output_source_filename_data
symtabs; it doesn't hurt to check. */
/* Was NAME already seen? */
- if (filename_seen (data->filename_seen_cache, name, 1))
+ if (data->filename_seen_cache->seen (name))
{
/* Yes; don't print it again. */
return;
struct symtab *s;
struct objfile *objfile;
struct output_source_filename_data data;
- struct cleanup *cleanups;
if (!have_full_symbols () && !have_partial_symbols ())
{
error (_("No symbol table is loaded. Use the \"file\" command."));
}
- data.filename_seen_cache = create_filename_seen_cache ();
- cleanups = make_cleanup (delete_filename_seen_cache,
- data.filename_seen_cache);
+ filename_seen_cache filenames_seen;
+
+ data.filename_seen_cache = &filenames_seen;
printf_filtered ("Source files for which symbols have been read in:\n\n");
printf_filtered ("Source files for which symbols "
"will be read in on demand:\n\n");
- clear_filename_seen_cache (data.filename_seen_cache);
+ filenames_seen.clear ();
data.first = 1;
map_symbol_filenames (output_partial_symbol_filename, &data,
1 /*need_fullname*/);
printf_filtered ("\n");
-
- do_cleanups (cleanups);
}
/* Compare FILE against all the NFILES entries of FILES. If BASENAMES is
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)
{
{
char *newobj;
- enum maybe_add_completion_enum add_status;
if (word == sym_text)
{
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);
}
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)
{
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)
{
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)
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);
}
}
}
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)
{
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);
}
}
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)
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
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. */
{
}
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
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. */
[&] (compunit_symtab *symtab) /* expansion notify */
{
add_symtab_completions (symtab,
+ tracker,
sym_text, sym_text_len,
text, word, code);
},
{
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);
}
{
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
macro_source_file *,
int)
{
- completion_list_add_name (macro_name,
+ completion_list_add_name (tracker, macro_name,
sym_text, sym_text_len,
text, word);
};
/* 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 suitable for use as a
- completion function. */
+/* Like collect_symbol_completion_matches, but collects a list of
+ symbols defined in all source files named SRCFILE. */
-VEC (char_ptr) *
-make_symbol_completion_list_fn (struct cmd_list_element *ignore,
- const char *text, const char *word)
-{
- return make_symbol_completion_list (text, word);
-}
-
-/* Like make_symbol_completion_list, but returns a list of symbols
- defined in all source files name 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;
/* A double-quoted string is never a symbol, nor does it make sense
to complete it any other way. */
{
- return NULL;
+ return;
}
else
{
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
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);
newobj[text - word] = '\0';
strcat (newobj, fname);
}
- VEC_safe_push (char_ptr, *list, newobj);
+ list->emplace_back (newobj);
}
static int
const char *text;
const char *word;
int text_len;
- VEC (char_ptr) **list;
+ completion_list *list;
};
/* A callback for map_partial_symbol_filenames. */
if (not_interesting_fname (filename))
return;
- if (!filename_seen (data->filename_seen_cache, filename, 1)
+ if (!data->filename_seen_cache->seen (filename)
&& filename_ncmp (filename, data->text, data->text_len) == 0)
{
/* This file matches for a completion; add it to the
const char *base_name = lbasename (filename);
if (base_name != filename
- && !filename_seen (data->filename_seen_cache, base_name, 1)
+ && !data->filename_seen_cache->seen (base_name)
&& filename_ncmp (base_name, data->text, data->text_len) == 0)
add_filename_to_list (base_name, data->text, data->word, data->list);
}
}
-/* 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 filename_seen_cache *filename_seen_cache;
- struct cleanup *back_to, *cache_cleanup;
+ struct cleanup *back_to;
if (!have_full_symbols () && !have_partial_symbols ())
return list;
- back_to = make_cleanup (do_free_completion_list, &list);
-
- filename_seen_cache = create_filename_seen_cache ();
- cache_cleanup = make_cleanup (delete_filename_seen_cache,
- filename_seen_cache);
+ filename_seen_cache filenames_seen;
ALL_FILETABS (objfile, cu, s)
{
if (not_interesting_fname (s->filename))
continue;
- if (!filename_seen (filename_seen_cache, s->filename, 1)
+ if (!filenames_seen.seen (s->filename)
&& filename_ncmp (s->filename, text, text_len) == 0)
{
/* This file matches for a completion; add it to the current
command do when they parse file names. */
base_name = lbasename (s->filename);
if (base_name != s->filename
- && !filename_seen (filename_seen_cache, base_name, 1)
+ && !filenames_seen.seen (base_name)
&& filename_ncmp (base_name, text, text_len) == 0)
add_filename_to_list (base_name, text, word, &list);
}
}
- datum.filename_seen_cache = filename_seen_cache;
+ datum.filename_seen_cache = &filenames_seen;
datum.text = text;
datum.word = word;
datum.text_len = text_len;
map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
0 /*need_fullname*/);
- do_cleanups (cache_cleanup);
- discard_cleanups (back_to);
-
return list;
}
\f