+ VEC (typep) *new_supers = NULL;
+ int ix;
+ struct type *t;
+
+ make_cleanup (VEC_cleanup (typep), &new_supers);
+ for (ix = 0; VEC_iterate (typep, iter_classes, ix, t); ++ix)
+ find_methods (t, name, result_names, &new_supers);
+
+ if (VEC_length (const_char_ptr, *result_names) != old_len
+ || VEC_empty (typep, new_supers))
+ break;
+
+ iter_classes = new_supers;
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* This finds the method COPY in the class whose type is given by one
+ of the symbols in SYM_CLASSES. */
+
+static struct symtabs_and_lines
+find_method (struct linespec_state *self, char *saved_arg,
+ char *copy, const char *class_name, VEC (symbolp) *sym_classes)
+{
+ char *canon;
+ struct symbol *sym;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ int ix;
+ int last_result_len;
+ VEC (typep) *superclass_vec;
+ VEC (const_char_ptr) *result_names;
+ struct collect_info info;
+ char *name_iter;
+
+ /* NAME is typed by the user: it needs to be canonicalized before
+ searching the symbol tables. */
+ canon = cp_canonicalize_string_no_typedefs (copy);
+ if (canon != NULL)
+ {
+ copy = canon;
+ make_cleanup (xfree, copy);
+ }
+
+ /* Sort symbols so that symbols with the same program space are next
+ to each other. */
+ qsort (VEC_address (symbolp, sym_classes),
+ VEC_length (symbolp, sym_classes),
+ sizeof (symbolp),
+ compare_symbols);
+
+ info.state = self;
+ info.result.sals = NULL;
+ info.result.nelts = 0;
+
+ /* Iterate over all the types, looking for the names of existing
+ methods matching COPY. If we cannot find a direct method in a
+ given program space, then we consider inherited methods; this is
+ not ideal (ideal would be to respect C++ hiding rules), but it
+ seems good enough and is what GDB has historically done. We only
+ need to collect the names because later we find all symbols with
+ those names. This loop is written in a somewhat funny way
+ because we collect data across the program space before deciding
+ what to do. */
+ superclass_vec = NULL;
+ make_cleanup (VEC_cleanup (typep), &superclass_vec);
+ result_names = NULL;
+ make_cleanup (VEC_cleanup (const_char_ptr), &result_names);
+ last_result_len = 0;
+ for (ix = 0; VEC_iterate (symbolp, sym_classes, ix, sym); ++ix)
+ {
+ struct type *t;
+ struct program_space *pspace;
+
+ /* Program spaces that are executing startup should have
+ been filtered out earlier. */
+ gdb_assert (!SYMTAB_PSPACE (SYMBOL_SYMTAB (sym))->executing_startup);
+ pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
+ set_current_program_space (pspace);
+ t = check_typedef (SYMBOL_TYPE (sym));
+ find_methods (t, copy, &result_names, &superclass_vec);
+
+ /* Handle all items from a single program space at once; and be
+ sure not to miss the last batch. */
+ if (ix == VEC_length (symbolp, sym_classes) - 1
+ || (pspace
+ != SYMTAB_PSPACE (SYMBOL_SYMTAB (VEC_index (symbolp, sym_classes,
+ ix + 1)))))
+ {
+ /* If we did not find a direct implementation anywhere in
+ this program space, consider superclasses. */
+ if (VEC_length (const_char_ptr, result_names) == last_result_len)
+ find_superclass_methods (superclass_vec, copy, &result_names);
+
+ /* We have a list of candidate symbol names, so now we
+ iterate over the symbol tables looking for all
+ matches in this pspace. */
+ add_all_symbol_names_from_pspace (&info, pspace, result_names);
+
+ VEC_truncate (typep, superclass_vec, 0);
+ last_result_len = VEC_length (const_char_ptr, result_names);
+ }
+ }
+
+ if (info.result.nelts > 0)
+ {
+ if (self->canonical)
+ {
+ self->canonical->pre_expanded = 1;
+ if (self->user_filename)
+ self->canonical->addr_string
+ = xstrprintf ("%s:%s", self->user_filename, saved_arg);
+ else
+ self->canonical->addr_string = xstrdup (saved_arg);
+ }
+
+ do_cleanups (cleanup);
+
+ return info.result;
+ }
+
+ if (copy[0] == '~')
+ cplusplus_error (saved_arg,
+ "the class `%s' does not have destructor defined\n",
+ class_name);
+ else
+ cplusplus_error (saved_arg,
+ "the class %s does not have any method named %s\n",
+ class_name, copy);
+}
+
+\f
+
+/* This object is used when collecting all matching symtabs. */
+
+struct symtab_collector
+{
+ /* The result vector of symtabs. */
+ VEC (symtab_p) *symtabs;
+
+ /* This is used to ensure the symtabs are unique. */
+ htab_t symtab_table;
+};
+
+/* Callback for iterate_over_symtabs. */
+
+static int
+add_symtabs_to_list (struct symtab *symtab, void *d)
+{
+ struct symtab_collector *data = d;
+ void **slot;
+
+ slot = htab_find_slot (data->symtab_table, symtab, INSERT);
+ if (!*slot)
+ {
+ *slot = symtab;
+ VEC_safe_push (symtab_p, data->symtabs, symtab);
+ }
+
+ return 0;
+}
+
+/* Given a file name, return a VEC of all matching symtabs. */
+
+static VEC (symtab_p) *
+collect_symtabs_from_filename (const char *file)
+{
+ struct symtab_collector collector;
+ struct cleanup *cleanups;
+ struct program_space *pspace;
+
+ collector.symtabs = NULL;
+ collector.symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer,
+ NULL);
+ cleanups = make_cleanup_htab_delete (collector.symtab_table);
+
+ /* Find that file's data. */
+ ALL_PSPACES (pspace)
+ {
+ if (pspace->executing_startup)
+ continue;
+
+ set_current_program_space (pspace);
+ iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+ }
+
+ do_cleanups (cleanups);
+ return collector.symtabs;
+}
+
+/* Return all the symtabs associated to the filename given by the
+ substring of *ARGPTR ending at P, and advance ARGPTR past that
+ filename. */
+
+static VEC (symtab_p) *
+symtabs_from_filename (char **argptr, char *p, int is_quote_enclosed,
+ char **user_filename)
+{
+ char *p1;
+ char *copy;
+ struct cleanup *outer;
+ VEC (symtab_p) *result;
+
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ if ((*p == '"') && is_quote_enclosed)
+ --p;
+ copy = xmalloc (p - *argptr + 1);
+ outer = make_cleanup (xfree, copy);
+ memcpy (copy, *argptr, p - *argptr);
+ /* It may have the ending quote right after the file name. */
+ if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
+ || copy[p - *argptr - 1] == '\'')
+ copy[p - *argptr - 1] = 0;
+ else
+ copy[p - *argptr] = 0;
+
+ result = collect_symtabs_from_filename (copy);
+
+ if (VEC_empty (symtab_p, result))
+ {
+ if (!have_full_symbols () && !have_partial_symbols ())
+ throw_error (NOT_FOUND_ERROR,
+ _("No symbol table is loaded. "
+ "Use the \"file\" command."));
+ throw_error (NOT_FOUND_ERROR, _("No source file named %s."), copy);