Update copyright year range in all GDB files
[deliverable/binutils-gdb.git] / gdb / cp-support.c
index c46c7fc15696743397747bedfbbd135c99508bb8..2efc38557acb3590a780ab0c87aa1d185a57569a 100644 (file)
@@ -1,5 +1,5 @@
 /* Helper routines for C++ support in GDB.
-   Copyright (C) 2002-2017 Free Software Foundation, Inc.
+   Copyright (C) 2002-2018 Free Software Foundation, Inc.
 
    Contributed by MontaVista Software.
 
@@ -36,6 +36,7 @@
 #include <signal.h>
 #include "gdb_setjmp.h"
 #include "safe-ctype.h"
+#include "selftest.h"
 
 #define d_left(dc) (dc)->u.s_binary.left
 #define d_right(dc) (dc)->u.s_binary.right
@@ -65,11 +66,6 @@ static void make_symbol_overload_list_qualified (const char *func_name);
 
 struct cmd_list_element *maint_cplus_cmd_list = NULL;
 
-/* The actual commands.  */
-
-static void maint_cplus_command (char *arg, int from_tty);
-static void first_component_command (char *arg, int from_tty);
-
 /* A list of typedefs which should not be substituted by replace_typedefs.  */
 static const char * const ignore_typedefs[] =
   {
@@ -95,24 +91,6 @@ copy_string_to_obstack (struct obstack *obstack, const char *string,
   return (char *) obstack_copy (obstack, string, *len);
 }
 
-/* A cleanup wrapper for cp_demangled_name_parse_free.  */
-
-static void
-do_demangled_name_parse_free_cleanup (void *data)
-{
-  struct demangle_parse_info *info = (struct demangle_parse_info *) data;
-
-  cp_demangled_name_parse_free (info);
-}
-
-/* Create a cleanup for C++ name parsing.  */
-
-struct cleanup *
-make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *info)
-{
-  return make_cleanup (do_demangled_name_parse_free_cleanup, info);
-}
-
 /* Return 1 if STRING is clearly already in canonical form.  This
    function is conservative; things which it does not recognize are
    assumed to be non-canonical, and the parser will sort them out
@@ -209,8 +187,7 @@ inspect_type (struct demangle_parse_info *info,
          long len;
          int is_anon;
          struct type *type;
-         struct demangle_parse_info *i;
-         struct ui_file *buf;
+         std::unique_ptr<demangle_parse_info> i;
 
          /* Get the real type of the typedef.  */
          type = check_typedef (otype);
@@ -246,23 +223,21 @@ inspect_type (struct demangle_parse_info *info,
                type = last;
            }
 
-         buf = mem_fileopen ();
+         string_file buf;
          TRY
-         {
-           type_print (type, "", buf, -1);
-         }
-
+           {
+             type_print (type, "", &buf, -1);
+           }
          /* If type_print threw an exception, there is little point
             in continuing, so just bow out gracefully.  */
          CATCH (except, RETURN_MASK_ERROR)
            {
-             ui_file_delete (buf);
              return 0;
            }
          END_CATCH
 
-         name = ui_file_obsavestring (buf, &info->obstack, &len);
-         ui_file_delete (buf);
+         len = buf.size ();
+         name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
 
          /* Turn the result into a new tree.  Note that this
             tree will contain pointers into NAME, so NAME cannot
@@ -272,7 +247,7 @@ inspect_type (struct demangle_parse_info *info,
          if (i != NULL)
            {
              /* Merge the two trees.  */
-             cp_merge_demangle_parse_infos (info, ret_comp, i);
+             cp_merge_demangle_parse_infos (info, ret_comp, i.get ());
 
              /* Replace any newly introduced typedefs -- but not
                 if the type is anonymous (that would lead to infinite
@@ -317,9 +292,7 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
                                 canonicalization_ftype *finder,
                                 void *data)
 {
-  long len;
-  char *name;
-  struct ui_file *buf = mem_fileopen ();
+  string_file buf;
   struct demangle_component *comp = ret_comp;
 
   /* Walk each node of the qualified name, reconstructing the name of
@@ -333,32 +306,31 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
        {
          struct demangle_component newobj;
 
-         ui_file_write (buf, d_left (comp)->u.s_name.s,
-                        d_left (comp)->u.s_name.len);
-         name = ui_file_obsavestring (buf, &info->obstack, &len);
+         buf.write (d_left (comp)->u.s_name.s, d_left (comp)->u.s_name.len);
          newobj.type = DEMANGLE_COMPONENT_NAME;
-         newobj.u.s_name.s = name;
-         newobj.u.s_name.len = len;
+         newobj.u.s_name.s
+           = (char *) obstack_copy0 (&info->obstack,
+                                     buf.c_str (), buf.size ());
+         newobj.u.s_name.len = buf.size ();
          if (inspect_type (info, &newobj, finder, data))
            {
-             char *n, *s;
+             char *s;
              long slen;
 
              /* A typedef was substituted in NEW.  Convert it to a
                 string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
                 node.  */
 
-             ui_file_rewind (buf);
-             n = cp_comp_to_string (&newobj, 100);
+             buf.clear ();
+             gdb::unique_xmalloc_ptr<char> n
+               = cp_comp_to_string (&newobj, 100);
              if (n == NULL)
                {
                  /* If something went astray, abort typedef substitutions.  */
-                 ui_file_delete (buf);
                  return;
                }
 
-             s = copy_string_to_obstack (&info->obstack, n, &slen);
-             xfree (n);
+             s = copy_string_to_obstack (&info->obstack, n.get (), &slen);
 
              d_left (ret_comp)->type = DEMANGLE_COMPONENT_NAME;
              d_left (ret_comp)->u.s_name.s = s;
@@ -374,18 +346,17 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
             typedefs in it.  Then print it to the stream to continue
             checking for more typedefs in the tree.  */
          replace_typedefs (info, d_left (comp), finder, data);
-         name = cp_comp_to_string (d_left (comp), 100);
+         gdb::unique_xmalloc_ptr<char> name
+           = cp_comp_to_string (d_left (comp), 100);
          if (name == NULL)
            {
              /* If something went astray, abort typedef substitutions.  */
-             ui_file_delete (buf);
              return;
            }
-         fputs_unfiltered (name, buf);
-         xfree (name);
+         buf.puts (name.get ());
        }
 
-      ui_file_write (buf, "::", 2);
+      buf.write ("::", 2);
       comp = d_right (comp);
     }
 
@@ -395,21 +366,20 @@ replace_typedefs_qualified_name (struct demangle_parse_info *info,
 
   if (comp->type == DEMANGLE_COMPONENT_NAME)
     {
-      ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
-      name = ui_file_obsavestring (buf, &info->obstack, &len);
+      buf.write (comp->u.s_name.s, comp->u.s_name.len);
 
       /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node
         with a DEMANGLE_COMPONENT_NAME node containing the whole
         name.  */
       ret_comp->type = DEMANGLE_COMPONENT_NAME;
-      ret_comp->u.s_name.s = name;
-      ret_comp->u.s_name.len = len;
+      ret_comp->u.s_name.s
+       = (char *) obstack_copy0 (&info->obstack,
+                                 buf.c_str (), buf.size ());
+      ret_comp->u.s_name.len = buf.size ();
       inspect_type (info, ret_comp, finder, data);
     }
   else
     replace_typedefs (info, comp, finder, data);
-
-  ui_file_delete (buf);
 }
 
 
@@ -447,7 +417,8 @@ replace_typedefs (struct demangle_parse_info *info,
              || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE
              || ret_comp->type == DEMANGLE_COMPONENT_BUILTIN_TYPE))
        {
-         char *local_name = cp_comp_to_string (ret_comp, 10);
+         gdb::unique_xmalloc_ptr<char> local_name
+           = cp_comp_to_string (ret_comp, 10);
 
          if (local_name != NULL)
            {
@@ -456,15 +427,14 @@ replace_typedefs (struct demangle_parse_info *info,
              sym = NULL;
              TRY
                {
-                 sym = lookup_symbol (local_name, 0, VAR_DOMAIN, 0).symbol;
+                 sym = lookup_symbol (local_name.get (), 0,
+                                      VAR_DOMAIN, 0).symbol;
                }
              CATCH (except, RETURN_MASK_ALL)
                {
                }
              END_CATCH
 
-             xfree (local_name);
-
              if (sym != NULL)
                {
                  struct type *otype = SYMBOL_TYPE (sym);
@@ -518,6 +488,7 @@ replace_typedefs (struct demangle_parse_info *info,
        case DEMANGLE_COMPONENT_RESTRICT_THIS:
        case DEMANGLE_COMPONENT_POINTER:
        case DEMANGLE_COMPONENT_REFERENCE:
+       case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
          replace_typedefs (info, d_left (ret_comp), finder, data);
          break;
 
@@ -540,22 +511,21 @@ cp_canonicalize_string_full (const char *string,
 {
   std::string ret;
   unsigned int estimated_len;
-  struct demangle_parse_info *info;
+  std::unique_ptr<demangle_parse_info> info;
 
   estimated_len = strlen (string) * 2;
   info = cp_demangled_name_to_comp (string, NULL);
   if (info != NULL)
     {
       /* Replace all the typedefs in the tree.  */
-      replace_typedefs (info, info->tree, finder, data);
+      replace_typedefs (info.get (), info->tree, finder, data);
 
       /* Convert the tree back into a string.  */
-      ret = cp_comp_to_string (info->tree, estimated_len);
-      gdb_assert (!ret.empty ());
-
-      /* Free the parse information.  */
-      cp_demangled_name_parse_free (info);
+      gdb::unique_xmalloc_ptr<char> us = cp_comp_to_string (info->tree,
+                                                           estimated_len);
+      gdb_assert (us);
 
+      ret = us.get ();
       /* Finally, compare the original string with the computed
         name, returning NULL if they are the same.  */
       if (ret == string)
@@ -581,7 +551,7 @@ cp_canonicalize_string_no_typedefs (const char *string)
 std::string
 cp_canonicalize_string (const char *string)
 {
-  struct demangle_parse_info *info;
+  std::unique_ptr<demangle_parse_info> info;
   unsigned int estimated_len;
 
   if (cp_already_canonical (string))
@@ -592,16 +562,18 @@ cp_canonicalize_string (const char *string)
     return std::string ();
 
   estimated_len = strlen (string) * 2;
-  std::string ret = cp_comp_to_string (info->tree, estimated_len);
-  cp_demangled_name_parse_free (info);
+  gdb::unique_xmalloc_ptr<char> us (cp_comp_to_string (info->tree,
+                                                      estimated_len));
 
-  if (ret.empty ())
+  if (!us)
     {
       warning (_("internal error: string \"%s\" failed to be canonicalized"),
               string);
       return std::string ();
     }
 
+  std::string ret (us.get ());
+
   if (ret == string)
     return std::string ();
 
@@ -614,12 +586,11 @@ cp_canonicalize_string (const char *string)
    freed when finished with the tree, or NULL if none was needed.
    OPTIONS will be passed to the demangler.  */
 
-static struct demangle_parse_info *
+static std::unique_ptr<demangle_parse_info>
 mangled_name_to_comp (const char *mangled_name, int options,
                      void **memory, char **demangled_p)
 {
   char *demangled_name;
-  struct demangle_parse_info *info;
 
   /* If it looks like a v3 mangled name, then try to go directly
      to trees.  */
@@ -631,7 +602,7 @@ mangled_name_to_comp (const char *mangled_name, int options,
                                          options, memory);
       if (ret)
        {
-         info = cp_new_demangle_parse_info ();
+         std::unique_ptr<demangle_parse_info> info (new demangle_parse_info);
          info->tree = ret;
          *demangled_p = NULL;
          return info;
@@ -646,7 +617,8 @@ mangled_name_to_comp (const char *mangled_name, int options,
   
   /* If we could demangle the name, parse it to build the component
      tree.  */
-  info = cp_demangled_name_to_comp (demangled_name, NULL);
+  std::unique_ptr<demangle_parse_info> info
+    = cp_demangled_name_to_comp (demangled_name, NULL);
 
   if (info == NULL)
     {
@@ -664,9 +636,10 @@ char *
 cp_class_name_from_physname (const char *physname)
 {
   void *storage = NULL;
-  char *demangled_name = NULL, *ret;
+  char *demangled_name = NULL;
+  gdb::unique_xmalloc_ptr<char> ret;
   struct demangle_component *ret_comp, *prev_comp, *cur_comp;
-  struct demangle_parse_info *info;
+  std::unique_ptr<demangle_parse_info> info;
   int done;
 
   info = mangled_name_to_comp (physname, DMGL_ANSI,
@@ -733,7 +706,6 @@ cp_class_name_from_physname (const char *physname)
        break;
       }
 
-  ret = NULL;
   if (cur_comp != NULL && prev_comp != NULL)
     {
       /* We want to discard the rightmost child of PREV_COMP.  */
@@ -745,8 +717,7 @@ cp_class_name_from_physname (const char *physname)
 
   xfree (storage);
   xfree (demangled_name);
-  cp_demangled_name_parse_free (info);
-  return ret;
+  return ret.release ();
 }
 
 /* Return the child of COMP which is the basename of a method,
@@ -813,9 +784,10 @@ char *
 method_name_from_physname (const char *physname)
 {
   void *storage = NULL;
-  char *demangled_name = NULL, *ret;
+  char *demangled_name = NULL;
+  gdb::unique_xmalloc_ptr<char> ret;
   struct demangle_component *ret_comp;
-  struct demangle_parse_info *info;
+  std::unique_ptr<demangle_parse_info> info;
 
   info = mangled_name_to_comp (physname, DMGL_ANSI,
                               &storage, &demangled_name);
@@ -824,7 +796,6 @@ method_name_from_physname (const char *physname)
 
   ret_comp = unqualified_name_from_comp (info->tree);
 
-  ret = NULL;
   if (ret_comp != NULL)
     /* The ten is completely arbitrary; we don't have a good
        estimate.  */
@@ -832,8 +803,7 @@ method_name_from_physname (const char *physname)
 
   xfree (storage);
   xfree (demangled_name);
-  cp_demangled_name_parse_free (info);
-  return ret;
+  return ret.release ();
 }
 
 /* If FULL_NAME is the demangled name of a C++ function (including an
@@ -845,9 +815,9 @@ method_name_from_physname (const char *physname)
 char *
 cp_func_name (const char *full_name)
 {
-  char *ret;
+  gdb::unique_xmalloc_ptr<char> ret;
   struct demangle_component *ret_comp;
-  struct demangle_parse_info *info;
+  std::unique_ptr<demangle_parse_info> info;
 
   info = cp_demangled_name_to_comp (full_name, NULL);
   if (!info)
@@ -855,25 +825,25 @@ cp_func_name (const char *full_name)
 
   ret_comp = unqualified_name_from_comp (info->tree);
 
-  ret = NULL;
   if (ret_comp != NULL)
     ret = cp_comp_to_string (ret_comp, 10);
 
-  cp_demangled_name_parse_free (info);
-  return ret;
+  return ret.release ();
 }
 
-/* DEMANGLED_NAME is the name of a function, including parameters and
-   (optionally) a return type.  Return the name of the function without
-   parameters or return type, or NULL if we can not parse the name.  */
+/* Helper for cp_remove_params.  DEMANGLED_NAME is the name of a
+   function, including parameters and (optionally) a return type.
+   Return the name of the function without parameters or return type,
+   or NULL if we can not parse the name.  If REQUIRE_PARAMS is false,
+   then tolerate a non-existing or unbalanced parameter list.  */
 
-char *
-cp_remove_params (const char *demangled_name)
+static gdb::unique_xmalloc_ptr<char>
+cp_remove_params_1 (const char *demangled_name, bool require_params)
 {
-  int done = 0;
+  bool done = false;
   struct demangle_component *ret_comp;
-  struct demangle_parse_info *info;
-  char *ret = NULL;
+  std::unique_ptr<demangle_parse_info> info;
+  gdb::unique_xmalloc_ptr<char> ret;
 
   if (demangled_name == NULL)
     return NULL;
@@ -897,18 +867,63 @@ cp_remove_params (const char *demangled_name)
         ret_comp = d_left (ret_comp);
         break;
       default:
-       done = 1;
+       done = true;
        break;
       }
 
   /* What we have now should be a function.  Return its name.  */
   if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
     ret = cp_comp_to_string (d_left (ret_comp), 10);
+  else if (!require_params
+          && (ret_comp->type == DEMANGLE_COMPONENT_NAME
+              || ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME
+              || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE))
+    ret = cp_comp_to_string (ret_comp, 10);
 
-  cp_demangled_name_parse_free (info);
   return ret;
 }
 
+/* DEMANGLED_NAME is the name of a function, including parameters and
+   (optionally) a return type.  Return the name of the function
+   without parameters or return type, or NULL if we can not parse the
+   name.  */
+
+gdb::unique_xmalloc_ptr<char>
+cp_remove_params (const char *demangled_name)
+{
+  return cp_remove_params_1 (demangled_name, true);
+}
+
+/* See cp-support.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+cp_remove_params_if_any (const char *demangled_name, bool completion_mode)
+{
+  /* Trying to remove parameters from the empty string fails.  If
+     we're completing / matching everything, avoid returning NULL
+     which would make callers interpret the result as an error.  */
+  if (demangled_name[0] == '\0' && completion_mode)
+    return gdb::unique_xmalloc_ptr<char> (xstrdup (""));
+
+  gdb::unique_xmalloc_ptr<char> without_params
+    = cp_remove_params_1 (demangled_name, false);
+
+  if (without_params == NULL && completion_mode)
+    {
+      std::string copy = demangled_name;
+
+      while (!copy.empty ())
+       {
+         copy.pop_back ();
+         without_params = cp_remove_params_1 (copy.c_str (), false);
+         if (without_params != NULL)
+           break;
+       }
+    }
+
+  return without_params;
+}
+
 /* Here are some random pieces of trivia to keep in mind while trying
    to take apart demangled names:
 
@@ -962,10 +977,6 @@ cp_find_first_component (const char *name)
    the recursion easier, it also stops if it reaches an unexpected ')'
    or '>' if the value of PERMISSIVE is nonzero.  */
 
-/* Let's optimize away calls to strlen("operator").  */
-
-#define LENGTH_OF_OPERATOR 8
-
 static unsigned int
 cp_find_first_component_aux (const char *name, int permissive)
 {
@@ -1037,14 +1048,15 @@ cp_find_first_component_aux (const char *name, int permissive)
        case 'o':
          /* Operator names can screw up the recursion.  */
          if (operator_possible
-             && strncmp (name + index, "operator",
-                         LENGTH_OF_OPERATOR) == 0)
+             && startswith (name + index, CP_OPERATOR_STR))
            {
-             index += LENGTH_OF_OPERATOR;
+             index += CP_OPERATOR_LEN;
              while (ISSPACE(name[index]))
                ++index;
              switch (name[index])
                {
+               case '\0':
+                 return index;
                  /* Skip over one less than the appropriate number of
                     characters: the for loop will skip over the last
                     one.  */
@@ -1136,7 +1148,7 @@ overload_list_add_symbol (struct symbol *sym,
 {
   int newsize;
   int i;
-  char *sym_name;
+  gdb::unique_xmalloc_ptr<char> sym_name;
 
   /* If there is no type information, we can't do anything, so
      skip.  */
@@ -1155,13 +1167,8 @@ overload_list_add_symbol (struct symbol *sym,
     return;
 
   /* skip symbols that cannot match */
-  if (strcmp (sym_name, oload_name) != 0)
-    {
-      xfree (sym_name);
-      return;
-    }
-
-  xfree (sym_name);
+  if (strcmp (sym_name.get (), oload_name) != 0)
+    return;
 
   /* We have a match for an overload instance, so add SYM to the
      current list of overload instances */
@@ -1223,7 +1230,9 @@ make_symbol_overload_list_block (const char *name,
   struct block_iterator iter;
   struct symbol *sym;
 
-  ALL_BLOCK_SYMBOLS_WITH_NAME (block, name, iter, sym)
+  lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
+
+  ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
     overload_list_add_symbol (sym, name);
 }
 
@@ -1273,7 +1282,7 @@ make_symbol_overload_list_adl_namespace (struct type *type,
   int i, prefix_len;
 
   while (TYPE_CODE (type) == TYPE_CODE_PTR
-        || TYPE_CODE (type) == TYPE_CODE_REF
+        || TYPE_IS_REFERENCE (type)
          || TYPE_CODE (type) == TYPE_CODE_ARRAY
          || TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
     {
@@ -1328,16 +1337,6 @@ make_symbol_overload_list_adl (struct type **arg_types, int nargs,
   return sym_return_val;
 }
 
-/* Used for cleanups to reset the "searched" flag in case of an
-   error.  */
-
-static void
-reset_directive_searched (void *data)
-{
-  struct using_direct *direct = (struct using_direct *) data;
-  direct->searched = 0;
-}
-
 /* This applies the using directives to add namespaces to search in,
    and then searches for overloads in all of those namespaces.  It
    adds the symbols found to sym_return_val.  Arguments are as in
@@ -1374,16 +1373,11 @@ make_symbol_overload_list_using (const char *func_name,
          {
            /* Mark this import as searched so that the recursive call
               does not search it again.  */
-           struct cleanup *old_chain;
-           current->searched = 1;
-           old_chain = make_cleanup (reset_directive_searched,
-                                     current);
+           scoped_restore reset_directive_searched
+             = make_scoped_restore (&current->searched, 1);
 
            make_symbol_overload_list_using (func_name,
                                             current->import_src);
-
-           current->searched = 0;
-           discard_cleanups (old_chain);
          }
       }
 
@@ -1579,32 +1573,27 @@ gdb_demangle (const char *name, int options)
 
          if (!error_reported)
            {
-             char *short_msg, *long_msg;
-             struct cleanup *back_to;
+             std::string short_msg
+               = string_printf (_("unable to demangle '%s' "
+                                  "(demangler failed with signal %d)"),
+                                name, crash_signal);
 
-             short_msg = xstrprintf (_("unable to demangle '%s' "
-                                     "(demangler failed with signal %d)"),
-                                   name, crash_signal);
-             back_to = make_cleanup (xfree, short_msg);
+             std::string long_msg
+               = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
+                                "demangler-warning", short_msg.c_str ());
 
-             long_msg = xstrprintf ("%s:%d: %s: %s", __FILE__, __LINE__,
-                                   "demangler-warning", short_msg);
-             make_cleanup (xfree, long_msg);
-
-             make_cleanup_restore_target_terminal ();
-             target_terminal_ours_for_output ();
+             target_terminal::scoped_restore_terminal_state term_state;
+             target_terminal::ours_for_output ();
 
              begin_line ();
              if (core_dump_allowed)
                fprintf_unfiltered (gdb_stderr,
                                    _("%s\nAttempting to dump core.\n"),
-                                   long_msg);
+                                   long_msg.c_str ());
              else
-               warn_cant_dump_core (long_msg);
-
-             demangler_warning (__FILE__, __LINE__, "%s", short_msg);
+               warn_cant_dump_core (long_msg.c_str ());
 
-             do_cleanups (back_to);
+             demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
 
              error_reported = 1;
            }
@@ -1626,10 +1615,511 @@ gdb_sniff_from_mangled_name (const char *mangled, char **demangled)
   return *demangled != NULL;
 }
 
+/* See cp-support.h.  */
+
+unsigned int
+cp_search_name_hash (const char *search_name)
+{
+  /* cp_entire_prefix_len assumes a fully-qualified name with no
+     leading "::".  */
+  if (startswith (search_name, "::"))
+    search_name += 2;
+
+  unsigned int prefix_len = cp_entire_prefix_len (search_name);
+  if (prefix_len != 0)
+    search_name += prefix_len + 2;
+
+  unsigned int hash = 0;
+  for (const char *string = search_name; *string != '\0'; ++string)
+    {
+      string = skip_spaces (string);
+
+      if (*string == '(')
+       break;
+
+      /* Ignore ABI tags such as "[abi:cxx11].  */
+      if (*string == '['
+         && startswith (string + 1, "abi:")
+         && string[5] != ':')
+       break;
+
+      hash = SYMBOL_HASH_NEXT (hash, *string);
+    }
+  return hash;
+}
+
+/* Helper for cp_symbol_name_matches (i.e., symbol_name_matcher_ftype
+   implementation for symbol_name_match_type::WILD matching).  Split
+   to a separate function for unit-testing convenience.
+
+   If SYMBOL_SEARCH_NAME has more scopes than LOOKUP_NAME, we try to
+   match ignoring the extra leading scopes of SYMBOL_SEARCH_NAME.
+   This allows conveniently setting breakpoints on functions/methods
+   inside any namespace/class without specifying the fully-qualified
+   name.
+
+   E.g., these match:
+
+    [symbol search name]   [lookup name]
+    foo::bar::func         foo::bar::func
+    foo::bar::func         bar::func
+    foo::bar::func         func
+
+   While these don't:
+
+    [symbol search name]   [lookup name]
+    foo::zbar::func        bar::func
+    foo::bar::func         foo::func
+
+   See more examples in the test_cp_symbol_name_matches selftest
+   function below.
+
+   See symbol_name_matcher_ftype for description of SYMBOL_SEARCH_NAME
+   and COMP_MATCH_RES.
+
+   LOOKUP_NAME/LOOKUP_NAME_LEN is the name we're looking up.
+
+   See strncmp_iw_with_mode for description of MODE.
+*/
+
+static bool
+cp_symbol_name_matches_1 (const char *symbol_search_name,
+                         const char *lookup_name,
+                         size_t lookup_name_len,
+                         strncmp_iw_mode mode,
+                         completion_match_result *comp_match_res)
+{
+  const char *sname = symbol_search_name;
+  completion_match_for_lcd *match_for_lcd
+    = (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
+
+  while (true)
+    {
+      if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
+                               mode, language_cplus, match_for_lcd) == 0)
+       {
+         if (comp_match_res != NULL)
+           {
+             /* Note here we set different MATCH and MATCH_FOR_LCD
+                strings.  This is because with
+
+                 (gdb) b push_bac[TAB]
+
+                we want the completion matches to list
+
+                 std::vector<int>::push_back(...)
+                 std::vector<char>::push_back(...)
+
+                etc., which are SYMBOL_SEARCH_NAMEs, while we want
+                the input line to auto-complete to
+
+                 (gdb) push_back(...)
+
+                which is SNAME, not to
+
+                 (gdb) std::vector<
+
+                which would be the regular common prefix between all
+                the matches otherwise.  */
+             comp_match_res->set_match (symbol_search_name, sname);
+           }
+         return true;
+       }
+
+      unsigned int len = cp_find_first_component (sname);
+
+      if (sname[len] == '\0')
+       return false;
+
+      gdb_assert (sname[len] == ':');
+      /* Skip the '::'.  */
+      sname += len + 2;
+    }
+}
+
+/* C++ symbol_name_matcher_ftype implementation.  */
+
+static bool
+cp_fq_symbol_name_matches (const char *symbol_search_name,
+                          const lookup_name_info &lookup_name,
+                          completion_match_result *comp_match_res)
+{
+  /* Get the demangled name.  */
+  const std::string &name = lookup_name.cplus ().lookup_name ();
+  completion_match_for_lcd *match_for_lcd
+    = (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
+  strncmp_iw_mode mode = (lookup_name.completion_mode ()
+                         ? strncmp_iw_mode::NORMAL
+                         : strncmp_iw_mode::MATCH_PARAMS);
+
+  if (strncmp_iw_with_mode (symbol_search_name,
+                           name.c_str (), name.size (),
+                           mode, language_cplus, match_for_lcd) == 0)
+    {
+      if (comp_match_res != NULL)
+       comp_match_res->set_match (symbol_search_name);
+      return true;
+    }
+
+  return false;
+}
+
+/* C++ symbol_name_matcher_ftype implementation for wild matches.
+   Defers work to cp_symbol_name_matches_1.  */
+
+static bool
+cp_symbol_name_matches (const char *symbol_search_name,
+                       const lookup_name_info &lookup_name,
+                       completion_match_result *comp_match_res)
+{
+  /* Get the demangled name.  */
+  const std::string &name = lookup_name.cplus ().lookup_name ();
+
+  strncmp_iw_mode mode = (lookup_name.completion_mode ()
+                         ? strncmp_iw_mode::NORMAL
+                         : strncmp_iw_mode::MATCH_PARAMS);
+
+  return cp_symbol_name_matches_1 (symbol_search_name,
+                                  name.c_str (), name.size (),
+                                  mode, comp_match_res);
+}
+
+/* See cp-support.h.  */
+
+symbol_name_matcher_ftype *
+cp_get_symbol_name_matcher (const lookup_name_info &lookup_name)
+{
+  switch (lookup_name.match_type ())
+    {
+    case symbol_name_match_type::FULL:
+    case symbol_name_match_type::EXPRESSION:
+      return cp_fq_symbol_name_matches;
+    case symbol_name_match_type::WILD:
+      return cp_symbol_name_matches;
+    }
+
+  gdb_assert_not_reached ("");
+}
+
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+void
+test_cp_symbol_name_matches ()
+{
+#define CHECK_MATCH(SYMBOL, INPUT)                                     \
+  SELF_CHECK (cp_symbol_name_matches_1 (SYMBOL,                                \
+                                       INPUT, sizeof (INPUT) - 1,      \
+                                       strncmp_iw_mode::MATCH_PARAMS,  \
+                                       NULL))
+
+#define CHECK_NOT_MATCH(SYMBOL, INPUT)                                 \
+  SELF_CHECK (!cp_symbol_name_matches_1 (SYMBOL,                       \
+                                        INPUT, sizeof (INPUT) - 1,     \
+                                        strncmp_iw_mode::MATCH_PARAMS, \
+                                        NULL))
+
+  /* Like CHECK_MATCH, and also check that INPUT (and all substrings
+     that start at index 0) completes to SYMBOL.  */
+#define CHECK_MATCH_C(SYMBOL, INPUT)                                   \
+  do                                                                   \
+    {                                                                  \
+      CHECK_MATCH (SYMBOL, INPUT);                                     \
+      for (size_t i = 0; i < sizeof (INPUT) - 1; i++)                  \
+       SELF_CHECK (cp_symbol_name_matches_1 (SYMBOL, INPUT, i,         \
+                                             strncmp_iw_mode::NORMAL,  \
+                                             NULL));                   \
+    } while (0)
+
+  /* Like CHECK_NOT_MATCH, and also check that INPUT does NOT complete
+     to SYMBOL.  */
+#define CHECK_NOT_MATCH_C(SYMBOL, INPUT)                               \
+  do                                                                   \
+    {                                                                  \
+      CHECK_NOT_MATCH (SYMBOL, INPUT);                                 \
+      SELF_CHECK (!cp_symbol_name_matches_1 (SYMBOL, INPUT,            \
+                                            sizeof (INPUT) - 1,        \
+                                            strncmp_iw_mode::NORMAL,   \
+                                            NULL));                    \
+    } while (0)
+
+  /* Lookup name without parens matches all overloads.  */
+  CHECK_MATCH_C ("function()", "function");
+  CHECK_MATCH_C ("function(int)", "function");
+
+  /* Check whitespace around parameters is ignored.  */
+  CHECK_MATCH_C ("function()", "function ()");
+  CHECK_MATCH_C ("function ( )", "function()");
+  CHECK_MATCH_C ("function ()", "function( )");
+  CHECK_MATCH_C ("func(int)", "func( int )");
+  CHECK_MATCH_C ("func(int)", "func ( int ) ");
+  CHECK_MATCH_C ("func ( int )", "func( int )");
+  CHECK_MATCH_C ("func ( int )", "func ( int ) ");
+
+  /* Check symbol name prefixes aren't incorrectly matched.  */
+  CHECK_NOT_MATCH ("func", "function");
+  CHECK_NOT_MATCH ("function", "func");
+  CHECK_NOT_MATCH ("function()", "func");
+
+  /* Check that if the lookup name includes parameters, only the right
+     overload matches.  */
+  CHECK_MATCH_C ("function(int)", "function(int)");
+  CHECK_NOT_MATCH_C ("function(int)", "function()");
+
+  /* Check that whitespace within symbol names is not ignored.  */
+  CHECK_NOT_MATCH_C ("function", "func tion");
+  CHECK_NOT_MATCH_C ("func__tion", "func_ _tion");
+  CHECK_NOT_MATCH_C ("func11tion", "func1 1tion");
+
+  /* Check the converse, which can happen with template function,
+     where the return type is part of the demangled name.  */
+  CHECK_NOT_MATCH_C ("func tion", "function");
+  CHECK_NOT_MATCH_C ("func1 1tion", "func11tion");
+  CHECK_NOT_MATCH_C ("func_ _tion", "func__tion");
+
+  /* Within parameters too.  */
+  CHECK_NOT_MATCH_C ("func(param)", "func(par am)");
+
+  /* Check handling of whitespace around C++ operators.  */
+  CHECK_NOT_MATCH_C ("operator<<", "opera tor<<");
+  CHECK_NOT_MATCH_C ("operator<<", "operator< <");
+  CHECK_NOT_MATCH_C ("operator<<", "operator < <");
+  CHECK_NOT_MATCH_C ("operator==", "operator= =");
+  CHECK_NOT_MATCH_C ("operator==", "operator = =");
+  CHECK_MATCH_C ("operator<<", "operator <<");
+  CHECK_MATCH_C ("operator<<()", "operator <<");
+  CHECK_NOT_MATCH_C ("operator<<()", "operator<<(int)");
+  CHECK_NOT_MATCH_C ("operator<<(int)", "operator<<()");
+  CHECK_MATCH_C ("operator==", "operator ==");
+  CHECK_MATCH_C ("operator==()", "operator ==");
+  CHECK_MATCH_C ("operator <<", "operator<<");
+  CHECK_MATCH_C ("operator ==", "operator==");
+  CHECK_MATCH_C ("operator bool", "operator  bool");
+  CHECK_MATCH_C ("operator bool ()", "operator  bool");
+  CHECK_MATCH_C ("operatorX<<", "operatorX < <");
+  CHECK_MATCH_C ("Xoperator<<", "Xoperator < <");
+
+  CHECK_MATCH_C ("operator()(int)", "operator()(int)");
+  CHECK_MATCH_C ("operator()(int)", "operator ( ) ( int )");
+  CHECK_MATCH_C ("operator()<long>(int)", "operator ( ) < long > ( int )");
+  /* The first "()" is not the parameter list.  */
+  CHECK_NOT_MATCH ("operator()(int)", "operator");
+
+  /* Misc user-defined operator tests.  */
+
+  CHECK_NOT_MATCH_C ("operator/=()", "operator ^=");
+  /* Same length at end of input.  */
+  CHECK_NOT_MATCH_C ("operator>>", "operator[]");
+  /* Same length but not at end of input.  */
+  CHECK_NOT_MATCH_C ("operator>>()", "operator[]()");
+
+  CHECK_MATCH_C ("base::operator char*()", "base::operator char*()");
+  CHECK_MATCH_C ("base::operator char*()", "base::operator char * ()");
+  CHECK_MATCH_C ("base::operator char**()", "base::operator char * * ()");
+  CHECK_MATCH ("base::operator char**()", "base::operator char * *");
+  CHECK_MATCH_C ("base::operator*()", "base::operator*()");
+  CHECK_NOT_MATCH_C ("base::operator char*()", "base::operatorc");
+  CHECK_NOT_MATCH ("base::operator char*()", "base::operator char");
+  CHECK_NOT_MATCH ("base::operator char*()", "base::operat");
+
+  /* Check handling of whitespace around C++ scope operators.  */
+  CHECK_NOT_MATCH_C ("foo::bar", "foo: :bar");
+  CHECK_MATCH_C ("foo::bar", "foo :: bar");
+  CHECK_MATCH_C ("foo :: bar", "foo::bar");
+
+  CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi()");
+  CHECK_MATCH_C ("abc::def::ghi ( )", "abc::def::ghi()");
+  CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi ( )");
+  CHECK_MATCH_C ("function()", "function()");
+  CHECK_MATCH_C ("bar::function()", "bar::function()");
+
+  /* Wild matching tests follow.  */
+
+  /* Tests matching symbols in some scope.  */
+  CHECK_MATCH_C ("foo::function()", "function");
+  CHECK_MATCH_C ("foo::function(int)", "function");
+  CHECK_MATCH_C ("foo::bar::function()", "function");
+  CHECK_MATCH_C ("bar::function()", "bar::function");
+  CHECK_MATCH_C ("foo::bar::function()", "bar::function");
+  CHECK_MATCH_C ("foo::bar::function(int)", "bar::function");
+
+  /* Same, with parameters in the lookup name.  */
+  CHECK_MATCH_C ("foo::function()", "function()");
+  CHECK_MATCH_C ("foo::bar::function()", "function()");
+  CHECK_MATCH_C ("foo::function(int)", "function(int)");
+  CHECK_MATCH_C ("foo::function()", "foo::function()");
+  CHECK_MATCH_C ("foo::bar::function()", "bar::function()");
+  CHECK_MATCH_C ("foo::bar::function(int)", "bar::function(int)");
+  CHECK_MATCH_C ("bar::function()", "bar::function()");
+
+  CHECK_NOT_MATCH_C ("foo::bar::function(int)", "bar::function()");
+
+  CHECK_MATCH_C ("(anonymous namespace)::bar::function(int)",
+                "bar::function(int)");
+  CHECK_MATCH_C ("foo::(anonymous namespace)::bar::function(int)",
+                "function(int)");
+
+  /* Lookup scope wider than symbol scope, should not match.  */
+  CHECK_NOT_MATCH_C ("function()", "bar::function");
+  CHECK_NOT_MATCH_C ("function()", "bar::function()");
+
+  /* Explicit global scope doesn't match.  */
+  CHECK_NOT_MATCH_C ("foo::function()", "::function");
+  CHECK_NOT_MATCH_C ("foo::function()", "::function()");
+  CHECK_NOT_MATCH_C ("foo::function(int)", "::function()");
+  CHECK_NOT_MATCH_C ("foo::function(int)", "::function(int)");
+
+  /* Test ABI tag matching/ignoring.  */
+
+  /* If the symbol name has an ABI tag, but the lookup name doesn't,
+     then the ABI tag in the symbol name is ignored.  */
+  CHECK_MATCH_C ("function[abi:foo]()", "function");
+  CHECK_MATCH_C ("function[abi:foo](int)", "function");
+  CHECK_MATCH_C ("function[abi:foo]()", "function ()");
+  CHECK_NOT_MATCH_C ("function[abi:foo]()", "function (int)");
+
+  CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo]");
+  CHECK_MATCH_C ("function[abi:foo](int)", "function[abi:foo]");
+  CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo] ()");
+  CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function");
+  CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function");
+  CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo]");
+  CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function[abi:foo]");
+  CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] ()");
+  CHECK_NOT_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] (int)");
+
+  CHECK_MATCH_C ("function  [abi:foo][abi:bar] ( )", "function [abi:foo]");
+
+  /* If the symbol name does not have an ABI tag, while the lookup
+     name has one, then there's no match.  */
+  CHECK_NOT_MATCH_C ("function()", "function[abi:foo]()");
+  CHECK_NOT_MATCH_C ("function()", "function[abi:foo]");
+}
+
+/* If non-NULL, return STR wrapped in quotes.  Otherwise, return a
+   "<null>" string (with no quotes).  */
+
+static std::string
+quote (const char *str)
+{
+  if (str != NULL)
+    return std::string (1, '\"') + str + '\"';
+  else
+    return "<null>";
+}
+
+/* Check that removing parameter info out of NAME produces EXPECTED.
+   COMPLETION_MODE indicates whether we're testing normal and
+   completion mode.  FILE and LINE are used to provide better test
+   location information in case ithe check fails.  */
+
+static void
+check_remove_params (const char *file, int line,
+                     const char *name, const char *expected,
+                     bool completion_mode)
+{
+  gdb::unique_xmalloc_ptr<char> result
+    = cp_remove_params_if_any (name, completion_mode);
+
+  if ((expected == NULL) != (result == NULL)
+      || (expected != NULL
+         && strcmp (result.get (), expected) != 0))
+    {
+      error (_("%s:%d: make-paramless self-test failed: (completion=%d) "
+              "\"%s\" -> %s, expected %s"),
+            file, line, completion_mode, name,
+            quote (result.get ()).c_str (), quote (expected).c_str ());
+    }
+}
+
+/* Entry point for cp_remove_params unit tests.  */
+
+static void
+test_cp_remove_params ()
+{
+  /* Check that removing parameter info out of NAME produces EXPECTED.
+     Checks both normal and completion modes.  */
+#define CHECK(NAME, EXPECTED)                                          \
+  do                                                                   \
+    {                                                                  \
+      check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, false); \
+      check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, true);  \
+    }                                                                  \
+  while (0)
+
+  /* Similar, but used when NAME is incomplete -- i.e., is has
+     unbalanced parentheses.  In this case, looking for the exact name
+     should fail / return empty.  */
+#define CHECK_INCOMPL(NAME, EXPECTED)                                  \
+  do                                                                   \
+    {                                                                  \
+      check_remove_params (__FILE__, __LINE__, NAME, NULL, false);     \
+      check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, true);  \
+    }                                                                  \
+  while (0)
+
+  CHECK ("function()", "function");
+  CHECK_INCOMPL ("function(", "function");
+  CHECK ("function() const", "function");
+
+  CHECK ("(anonymous namespace)::A::B::C",
+        "(anonymous namespace)::A::B::C");
+
+  CHECK ("A::(anonymous namespace)",
+        "A::(anonymous namespace)");
+
+  CHECK_INCOMPL ("A::(anonymou", "A");
+
+  CHECK ("A::foo<int>()",
+        "A::foo<int>");
+
+  CHECK_INCOMPL ("A::foo<int>(",
+                "A::foo<int>");
+
+  CHECK ("A::foo<(anonymous namespace)::B>::func(int)",
+        "A::foo<(anonymous namespace)::B>::func");
+
+  CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>::func(in",
+                "A::foo<(anonymous namespace)::B>::func");
+
+  CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>::",
+                "A::foo<(anonymous namespace)::B>");
+
+  CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>:",
+                "A::foo<(anonymous namespace)::B>");
+
+  CHECK ("A::foo<(anonymous namespace)::B>",
+        "A::foo<(anonymous namespace)::B>");
+
+  CHECK_INCOMPL ("A::foo<(anonymous namespace)::B",
+                "A::foo");
+
+  /* Shouldn't this parse?  Looks like a bug in
+     cp_demangled_name_to_comp.  See PR c++/22411.  */
+#if 0
+  CHECK ("A::foo<void(int)>::func(int)",
+        "A::foo<void(int)>::func");
+#else
+  CHECK_INCOMPL ("A::foo<void(int)>::func(int)",
+                "A::foo");
+#endif
+
+  CHECK_INCOMPL ("A::foo<void(int",
+                "A::foo");
+
+#undef CHECK
+#undef CHECK_INCOMPL
+}
+
+} // namespace selftests
+
+#endif /* GDB_SELF_CHECK */
+
 /* Don't allow just "maintenance cplus".  */
 
 static  void
-maint_cplus_command (char *arg, int from_tty)
+maint_cplus_command (const char *arg, int from_tty)
 {
   printf_unfiltered (_("\"maintenance cplus\" must be followed "
                       "by the name of a command.\n"));
@@ -1643,7 +2133,7 @@ maint_cplus_command (char *arg, int from_tty)
    cp_find_first_component.  */
 
 static void
-first_component_command (char *arg, int from_tty)
+first_component_command (const char *arg, int from_tty)
 {
   int len;  
   char *prefix; 
@@ -1660,13 +2150,10 @@ first_component_command (char *arg, int from_tty)
   printf_unfiltered ("%s\n", prefix);
 }
 
-extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */
-
-
 /* Implement "info vtbl".  */
 
 static void
-info_vtbl_command (char *arg, int from_tty)
+info_vtbl_command (const char *arg, int from_tty)
 {
   struct value *value;
 
@@ -1711,4 +2198,11 @@ display the offending symbol."),
                           &maintenance_set_cmdlist,
                           &maintenance_show_cmdlist);
 #endif
+
+#if GDB_SELF_TEST
+  selftests::register_test ("cp_symbol_name_matches",
+                           selftests::test_cp_symbol_name_matches);
+  selftests::register_test ("cp_remove_params",
+                           selftests::test_cp_remove_params);
+#endif
 }
This page took 0.037658 seconds and 4 git commands to generate.