+/* Inspect the given RET_COMP for its type. If it is a typedef,
+ replace the node with the typedef's tree.
+
+ Returns 1 if any typedef substitutions were made, 0 otherwise. */
+
+static int
+inspect_type (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ canonicalization_ftype *finder,
+ void *data)
+{
+ int i;
+ char *name;
+ struct symbol *sym;
+ volatile struct gdb_exception except;
+
+ /* Copy the symbol's name from RET_COMP and look it up
+ in the symbol table. */
+ name = (char *) alloca (ret_comp->u.s_name.len + 1);
+ memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
+ name[ret_comp->u.s_name.len] = '\0';
+
+ /* Ignore any typedefs that should not be substituted. */
+ for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+ {
+ if (strcmp (name, ignore_typedefs[i]) == 0)
+ return 0;
+ }
+
+ sym = NULL;
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+ }
+
+ if (except.reason >= 0 && sym != NULL)
+ {
+ struct type *otype = SYMBOL_TYPE (sym);
+
+ if (finder != NULL)
+ {
+ const char *new_name = (*finder) (otype, data);
+
+ if (new_name != NULL)
+ {
+ ret_comp->u.s_name.s = new_name;
+ ret_comp->u.s_name.len = strlen (new_name);
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /* If the type is a typedef or namespace alias, replace it. */
+ if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF
+ || TYPE_CODE (otype) == TYPE_CODE_NAMESPACE)
+ {
+ long len;
+ int is_anon;
+ struct type *type;
+ struct demangle_parse_info *i;
+ struct ui_file *buf;
+
+ /* Get the real type of the typedef. */
+ type = check_typedef (otype);
+
+ /* If the symbol is a namespace and its type name is no different
+ than the name we looked up, this symbol is not a namespace
+ alias and does not need to be substituted. */
+ if (TYPE_CODE (otype) == TYPE_CODE_NAMESPACE
+ && strcmp (TYPE_NAME (type), name) == 0)
+ return 0;
+
+ is_anon = (TYPE_TAG_NAME (type) == NULL
+ && (TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION));
+ if (is_anon)
+ {
+ struct type *last = otype;
+
+ /* Find the last typedef for the type. */
+ while (TYPE_TARGET_TYPE (last) != NULL
+ && (TYPE_CODE (TYPE_TARGET_TYPE (last))
+ == TYPE_CODE_TYPEDEF))
+ last = TYPE_TARGET_TYPE (last);
+
+ /* If there is only one typedef for this anonymous type,
+ do not substitute it. */
+ if (type == otype)
+ return 0;
+ else
+ /* Use the last typedef seen as the type for this
+ anonymous type. */
+ type = last;
+ }
+
+ buf = mem_fileopen ();
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ type_print (type, "", buf, -1);
+ }
+
+ /* If type_print threw an exception, there is little point
+ in continuing, so just bow out gracefully. */
+ if (except.reason < 0)
+ {
+ ui_file_delete (buf);
+ return 0;
+ }
+
+ name = ui_file_obsavestring (buf, &info->obstack, &len);
+ ui_file_delete (buf);
+
+ /* Turn the result into a new tree. Note that this
+ tree will contain pointers into NAME, so NAME cannot
+ be free'd until all typedef conversion is done and
+ the final result is converted into a string. */
+ i = cp_demangled_name_to_comp (name, NULL);
+ if (i != NULL)
+ {
+ /* Merge the two trees. */
+ cp_merge_demangle_parse_infos (info, ret_comp, i);
+
+ /* Replace any newly introduced typedefs -- but not
+ if the type is anonymous (that would lead to infinite
+ looping). */
+ if (!is_anon)
+ replace_typedefs (info, ret_comp, finder, data);
+ }
+ else
+ {
+ /* This shouldn't happen unless the type printer has
+ output something that the name parser cannot grok.
+ Nonetheless, an ounce of prevention...
+
+ Canonicalize the name again, and store it in the
+ current node (RET_COMP). */
+ char *canon = cp_canonicalize_string_no_typedefs (name);
+
+ if (canon != NULL)
+ {
+ /* Copy the canonicalization into the obstack and
+ free CANON. */
+ name = copy_string_to_obstack (&info->obstack, canon, &len);
+ xfree (canon);
+ }
+
+ ret_comp->u.s_name.s = name;
+ ret_comp->u.s_name.len = len;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Replace any typedefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ canonicalization_ftype *finder,
+ void *data)
+{
+ long len;
+ char *name;
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Walk each node of the qualified name, reconstructing the name of
+ this element. With every node, check for any typedef substitutions.
+ If a substitution has occurred, replace the qualified name node
+ with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
+ substituted name. */
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ struct demangle_component new;
+
+ 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);
+ new.type = DEMANGLE_COMPONENT_NAME;
+ new.u.s_name.s = name;
+ new.u.s_name.len = len;
+ if (inspect_type (info, &new, finder, data))
+ {
+ char *n, *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 (&new, 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);
+
+ d_left (ret_comp)->type = DEMANGLE_COMPONENT_NAME;
+ d_left (ret_comp)->u.s_name.s = s;
+ d_left (ret_comp)->u.s_name.len = slen;
+ d_right (ret_comp) = d_right (comp);
+ comp = ret_comp;
+ continue;
+ }
+ }
+ else
+ {
+ /* The current node is not a name, so simply replace any
+ 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);
+ if (name == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+ fputs_unfiltered (name, buf);
+ xfree (name);
+ }
+
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, save the qualified
+ name assembled above and append the name given by COMP. Then use this
+ reassembled name to check for a typedef. */
+
+ 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);
+
+ /* 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;
+ inspect_type (info, ret_comp, finder, data);
+ }
+ else
+ replace_typedefs (info, comp, finder, data);
+
+ ui_file_delete (buf);
+}
+
+
+/* A function to check const and volatile qualifiers for argument types.
+
+ "Parameter declarations that differ only in the presence
+ or absence of `const' and/or `volatile' are equivalent."
+ C++ Standard N3290, clause 13.1.3 #4. */
+
+static void
+check_cv_qualifiers (struct demangle_component *ret_comp)
+{
+ while (d_left (ret_comp) != NULL
+ && (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST
+ || d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE))
+ {
+ d_left (ret_comp) = d_left (d_left (ret_comp));
+ }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+ their basic types. */
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ canonicalization_ftype *finder,
+ void *data)
+{
+ if (ret_comp)
+ {
+ if (finder != NULL
+ && (ret_comp->type == DEMANGLE_COMPONENT_NAME
+ || ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME
+ || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE
+ || ret_comp->type == DEMANGLE_COMPONENT_BUILTIN_TYPE))
+ {
+ char *local_name = cp_comp_to_string (ret_comp, 10);
+
+ if (local_name != NULL)
+ {
+ struct symbol *sym;
+ volatile struct gdb_exception except;
+
+ sym = NULL;
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ sym = lookup_symbol (local_name, 0, VAR_DOMAIN, 0);
+ }
+ xfree (local_name);
+
+ if (except.reason >= 0 && sym != NULL)
+ {
+ struct type *otype = SYMBOL_TYPE (sym);
+ const char *new_name = (*finder) (otype, data);
+
+ if (new_name != NULL)
+ {
+ ret_comp->type = DEMANGLE_COMPONENT_NAME;
+ ret_comp->u.s_name.s = new_name;
+ ret_comp->u.s_name.len = strlen (new_name);
+ return;
+ }
+ }
+ }
+ }
+
+ switch (ret_comp->type)
+ {
+ case DEMANGLE_COMPONENT_ARGLIST:
+ check_cv_qualifiers (ret_comp);
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ replace_typedefs (info, d_left (ret_comp), finder, data);
+ replace_typedefs (info, d_right (ret_comp), finder, data);
+ break;
+
+ case DEMANGLE_COMPONENT_NAME:
+ inspect_type (info, ret_comp, finder, data);
+ break;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ replace_typedefs_qualified_name (info, ret_comp, finder, data);
+ break;
+
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_CTOR:
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ replace_typedefs (info, d_right (ret_comp), finder, data);
+ break;
+
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ replace_typedefs (info, d_left (ret_comp), finder, data);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* Parse STRING and convert it to canonical form, resolving any typedefs.
+ If parsing fails, or if STRING is already canonical, return NULL.
+ Otherwise return the canonical form. The return value is allocated via
+ xmalloc. If FINDER is not NULL, then type components are passed to
+ FINDER to be looked up. DATA is passed verbatim to FINDER. */
+
+char *
+cp_canonicalize_string_full (const char *string,
+ canonicalization_ftype *finder,
+ void *data)
+{
+ char *ret;
+ unsigned int estimated_len;
+ struct demangle_parse_info *info;
+
+ ret = NULL;
+ 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);
+
+ /* Convert the tree back into a string. */
+ ret = cp_comp_to_string (info->tree, estimated_len);
+ gdb_assert (ret != NULL);
+
+ /* Free the parse information. */
+ cp_demangled_name_parse_free (info);
+
+ /* Finally, compare the original string with the computed
+ name, returning NULL if they are the same. */
+ if (strcmp (string, ret) == 0)
+ {
+ xfree (ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+/* Like cp_canonicalize_string_full, but always passes NULL for
+ FINDER. */
+
+char *
+cp_canonicalize_string_no_typedefs (const char *string)
+{
+ return cp_canonicalize_string_full (string, NULL, NULL);
+}
+