Allow for the possibility that the local labels won't be in the objdump output.
[deliverable/binutils-gdb.git] / gdb / c-typeprint.c
index 90b626d8a95cfc58bb875654de1dce22632fb306..bdc5a689ee1dc8ffed41c421399d839102dad529 100644 (file)
@@ -1,5 +1,6 @@
 /* Support for printing C and C++ types for GDB, the GNU debugger.
-   Copyright 1986, 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1998, 1999
+   Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+   1999, 2000
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "gdb_string.h"
 #include <errno.h>
-#include <ctype.h>
 
 /* Flag indicating target was compiled by HP compiler */
 extern int hp_som_som_object_present;
 
-static void cp_type_print_method_args PARAMS ((struct type ** args, char *prefix, char *varstring, int staticp, GDB_FILE * stream));
+static void cp_type_print_method_args (struct type ** args, char *prefix,
+                                      char *varstring, int staticp,
+                                      struct ui_file *stream);
 
-static void
-c_type_print_args PARAMS ((struct type *, GDB_FILE *));
+static void c_type_print_args (struct type *, struct ui_file *);
 
-static void
-cp_type_print_derivation_info PARAMS ((GDB_FILE *, struct type *));
+static void cp_type_print_derivation_info (struct ui_file *, struct type *);
 
-void
-c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int));
+void c_type_print_varspec_prefix (struct type *, struct ui_file *, int,
+                                 int);
 
-static void
-c_type_print_cv_qualifier PARAMS ((struct type *, GDB_FILE *, int, int));
+static void c_type_print_cv_qualifier (struct type *, struct ui_file *,
+                                      int, int);
 \f
 
 
-/* Print a description of a type in the format of a 
-   typedef for the current language.
-   NEW is the new name for a type TYPE. */
-
-void
-c_typedef_print (type, new, stream)
-     struct type *type;
-     struct symbol *new;
-     GDB_FILE *stream;
-{
-  CHECK_TYPEDEF (type);
-  switch (current_language->la_language)
-    {
-#ifdef _LANG_c
-    case language_c:
-    case language_cplus:
-      fprintf_filtered (stream, "typedef ");
-      type_print (type, "", stream, 0);
-      if (TYPE_NAME ((SYMBOL_TYPE (new))) == 0
-         || !STREQ (TYPE_NAME ((SYMBOL_TYPE (new))), SYMBOL_NAME (new)))
-       fprintf_filtered (stream, " %s", SYMBOL_SOURCE_NAME (new));
-      break;
-#endif
-#ifdef _LANG_m2
-    case language_m2:
-      fprintf_filtered (stream, "TYPE ");
-      if (!TYPE_NAME (SYMBOL_TYPE (new)) ||
-         !STREQ (TYPE_NAME (SYMBOL_TYPE (new)), SYMBOL_NAME (new)))
-       fprintf_filtered (stream, "%s = ", SYMBOL_SOURCE_NAME (new));
-      else
-       fprintf_filtered (stream, "<builtin> = ");
-      type_print (type, "", stream, 0);
-      break;
-#endif
-#ifdef _LANG_chill
-    case language_chill:
-      fprintf_filtered (stream, "SYNMODE ");
-      if (!TYPE_NAME (SYMBOL_TYPE (new)) ||
-         !STREQ (TYPE_NAME (SYMBOL_TYPE (new)), SYMBOL_NAME (new)))
-       fprintf_filtered (stream, "%s = ", SYMBOL_SOURCE_NAME (new));
-      else
-       fprintf_filtered (stream, "<builtin> = ");
-      type_print (type, "", stream, 0);
-      break;
-#endif
-    default:
-      error ("Language not supported.");
-    }
-  fprintf_filtered (stream, ";\n");
-}
-
 
 /* LEVEL is the depth to indent lines by.  */
 
 void
-c_print_type (type, varstring, stream, show, level)
-     struct type *type;
-     char *varstring;
-     GDB_FILE *stream;
-     int show;
-     int level;
+c_print_type (struct type *type, char *varstring, struct ui_file *stream,
+             int show, int level)
 {
   register enum type_code code;
   int demangled_args;
@@ -182,9 +127,7 @@ c_print_type (type, varstring, stream, show, level)
    derivation via protected inheritance, so gdb can print it out */
 
 static void
-cp_type_print_derivation_info (stream, type)
-     GDB_FILE *stream;
-     struct type *type;
+cp_type_print_derivation_info (struct ui_file *stream, struct type *type)
 {
   char *name;
   int i;
@@ -207,12 +150,8 @@ cp_type_print_derivation_info (stream, type)
 /* Print the C++ method arguments ARGS to the file STREAM.  */
 
 static void
-cp_type_print_method_args (args, prefix, varstring, staticp, stream)
-     struct type **args;
-     char *prefix;
-     char *varstring;
-     int staticp;
-     GDB_FILE *stream;
+cp_type_print_method_args (struct type **args, char *prefix, char *varstring,
+                          int staticp, struct ui_file *stream)
 {
   int i;
 
@@ -256,11 +195,8 @@ cp_type_print_method_args (args, prefix, varstring, staticp, stream)
    SHOW is always zero on recursive calls.  */
 
 void
-c_type_print_varspec_prefix (type, stream, show, passed_a_ptr)
-     struct type *type;
-     GDB_FILE *stream;
-     int show;
-     int passed_a_ptr;
+c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
+                            int show, int passed_a_ptr)
 {
   char *name;
   if (type == 0)
@@ -354,11 +290,8 @@ c_type_print_varspec_prefix (type, stream, show, passed_a_ptr)
    NEED_SPACE = 1 indicates an initial white space is needed */
 
 static void
-c_type_print_cv_qualifier (type, stream, need_pre_space, need_post_space)
-     struct type *type;
-     GDB_FILE *stream;
-     int need_pre_space;
-     int need_post_space;
+c_type_print_cv_qualifier (struct type *type, struct ui_file *stream,
+                          int need_pre_space, int need_post_space)
 {
   int flag = 0;
 
@@ -386,9 +319,7 @@ c_type_print_cv_qualifier (type, stream, need_pre_space, need_post_space)
 
 
 static void
-c_type_print_args (type, stream)
-     struct type *type;
-     GDB_FILE *stream;
+c_type_print_args (struct type *type, struct ui_file *stream)
 {
   int i;
   struct type **args;
@@ -433,17 +364,142 @@ c_type_print_args (type, stream)
   fprintf_filtered (stream, ")");
 }
 
+
+/* Return true iff the j'th overloading of the i'th method of TYPE
+   is a type conversion operator, like `operator int () { ... }'.
+   When listing a class's methods, we don't print the return type of
+   such operators.  */
+static int
+is_type_conversion_operator (struct type *type, int i, int j)
+{
+  /* I think the whole idea of recognizing type conversion operators
+     by their name is pretty terrible.  But I don't think our present
+     data structure gives us any other way to tell.  If you know of
+     some other way, feel free to rewrite this function.  */
+  char *name = TYPE_FN_FIELDLIST_NAME (type, i);
+
+  if (strncmp (name, "operator", 8) != 0)
+    return 0;
+
+  name += 8;
+  if (! strchr (" \t\f\n\r", *name))
+    return 0;
+
+  while (strchr (" \t\f\n\r", *name))
+    name++;
+
+  if (strncmp (name, "new", 3) == 0)
+    name += 3;
+  else if (strncmp (name, "delete", 6) == 0)
+    name += 6;
+  else
+    return 0;
+
+  /* Is that really the end of the name?  */
+  if (('a' <= *name && *name <= 'z')
+      || ('A' <= *name && *name <= 'Z')
+      || ('0' <= *name && *name <= '9')
+      || *name == '_')
+    /* No, so the identifier following "operator" must be a type name,
+       and this is a type conversion operator.  */
+    return 1;
+
+  /* That was indeed the end of the name, so it was `operator new' or
+     `operator delete', neither of which are type conversion operators.  */
+  return 0;
+}
+
+
+/* Given a C++ qualified identifier QID, strip off the qualifiers,
+   yielding the unqualified name.  The return value is a pointer into
+   the original string.
+
+   It's a pity we don't have this information in some more structured
+   form.  Even the author of this function feels that writing little
+   parsers like this everywhere is stupid.  */
+static char *
+remove_qualifiers (char *qid)
+{
+  int quoted = 0;              /* zero if we're not in quotes;
+                                  '"' if we're in a double-quoted string;
+                                  '\'' if we're in a single-quoted string.  */
+  int depth = 0;               /* number of unclosed parens we've seen */
+  char *parenstack = (char *) alloca (strlen (qid));
+  char *scan;
+  char *last = 0;              /* The character after the rightmost
+                                  `::' token we've seen so far.  */
+
+  for (scan = qid; *scan; scan++)
+    {
+      if (quoted)
+       {
+         if (*scan == quoted)
+           quoted = 0;
+         else if (*scan == '\\' && *(scan + 1))
+           scan++;
+       }
+      else if (scan[0] == ':' && scan[1] == ':')
+       {
+         /* If we're inside parenthesis (i.e., an argument list) or
+            angle brackets (i.e., a list of template arguments), then
+            we don't record the position of this :: token, since it's
+            not relevant to the top-level structure we're trying
+            to operate on.  */
+         if (depth == 0)
+           {
+             last = scan + 2;
+             scan++;
+           }
+       }
+      else if (*scan == '"' || *scan == '\'')
+       quoted = *scan;
+      else if (*scan == '(')
+       parenstack[depth++] = ')';
+      else if (*scan == '[')
+       parenstack[depth++] = ']';
+      /* We're going to treat <> as a pair of matching characters,
+        since we're more likely to see those in template id's than
+        real less-than characters.  What a crock.  */
+      else if (*scan == '<')
+       parenstack[depth++] = '>';
+      else if (*scan == ')' || *scan == ']' || *scan == '>')
+       {
+         if (depth > 0 && parenstack[depth - 1] == *scan)
+           depth--;
+         else
+           {
+             /* We're going to do a little error recovery here.  If we
+                don't find a match for *scan on the paren stack, but
+                there is something lower on the stack that does match, we
+                pop the stack to that point.  */
+             int i;
+
+             for (i = depth - 1; i >= 0; i--)
+               if (parenstack[i] == *scan)
+                 {
+                   depth = i;
+                   break;
+                 }
+           }
+       }
+    }
+
+  if (last)
+    return last;
+  else
+    /* We didn't find any :: tokens at the top level, so declare the
+       whole thing an unqualified identifier.  */
+    return qid;
+}
+
+
 /* Print any array sizes, function arguments or close parentheses
    needed after the variable name (to describe its type).
    Args work like c_type_print_varspec_prefix.  */
 
 void
-c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args)
-     struct type *type;
-     GDB_FILE *stream;
-     int show;
-     int passed_a_ptr;
-     int demangled_args;
+c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
+                            int show, int passed_a_ptr, int demangled_args)
 {
   if (type == 0)
     return;
@@ -561,11 +617,8 @@ c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args)
    We increase it for some recursive calls.  */
 
 void
-c_type_print_base (type, stream, show, level)
-     struct type *type;
-     GDB_FILE *stream;
-     int show;
-     int level;
+c_type_print_base (struct type *type, struct ui_file *stream, int show,
+                  int level)
 {
   register int i;
   register int len;
@@ -896,8 +949,7 @@ c_type_print_base (type, stream, show, level)
                    }
                  else if (!is_constructor &&   /* constructors don't have declared types */
                           !is_full_physname_constructor &&     /*    " "  */
-                          !strstr (method_name, "operator "))  /* Not a type conversion operator */
-                   /* (note space -- other operators don't have it) */
+                          !is_type_conversion_operator (type, i, j))
                    {
                      type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
                                  "", stream, -1);
@@ -931,15 +983,10 @@ c_type_print_base (type, stream, show, level)
                  else
                    {
                      char *p;
-                     char *demangled_no_class = strrchr (demangled_name, ':');
+                     char *demangled_no_class
+                       = remove_qualifiers (demangled_name);
 
-                      if (demangled_no_class == NULL)
-                        demangled_no_class = demangled_name;
-                      else
-                        {
-                          ++demangled_no_class; /* skip over last ':' */
-                       }
-                     /* get rid of the static word appended by the demangler */
+                     /* get rid of the `static' appended by the demangler */
                      p = strstr (demangled_no_class, " static");
                      if (p != NULL)
                        {
@@ -948,15 +995,15 @@ c_type_print_base (type, stream, show, level)
                          strncpy (demangled_no_static, demangled_no_class, length);
                          *(demangled_no_static + length) = '\0';
                          fputs_filtered (demangled_no_static, stream);
-                         free (demangled_no_static);
+                         xfree (demangled_no_static);
                        }
                      else
                        fputs_filtered (demangled_no_class, stream);
-                     free (demangled_name);
+                     xfree (demangled_name);
                    }
 
                  if (TYPE_FN_FIELD_STUB (f, j))
-                   free (mangled_name);
+                   xfree (mangled_name);
 
                  fprintf_filtered (stream, ";\n");
                }
This page took 0.026995 seconds and 4 git commands to generate.