]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/cp-namespace.c
2005-02-11 Andrew Cagney <cagney@gnu.org>
[thirdparty/binutils-gdb.git] / gdb / cp-namespace.c
index db0839fb8379ff6040b2fe56376b0d6386aab638..f90b22abb71cbc94918af4c415fd5aac41ac57aa 100644 (file)
@@ -1,5 +1,5 @@
 /* Helper routines for C++ support in GDB.
-   Copyright 2003 Free Software Foundation, Inc.
+   Copyright 2003, 2004 Free Software Foundation, Inc.
 
    Contributed by David Carlton and by Kealia, Inc.
 
 #include "symfile.h"
 #include "gdb_assert.h"
 #include "block.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "dictionary.h"
+#include "command.h"
+#include "frame.h"
 
-/* When set, the file that we're processing seems to have debugging
-   info for C++ namespaces, so cp-namespace.c shouldn't try to guess
-   namespace info itself.  */
+/* When set, the file that we're processing is known to have debugging
+   info for C++ namespaces.  */
+
+/* NOTE: carlton/2004-01-13: No currently released version of GCC (the
+   latest of which is 3.3.x at the time of this writing) produces this
+   debug info.  GCC 3.4 should, however.  */
 
 unsigned char processing_has_namespace_info;
 
-/* If processing_has_namespace_info is nonzero, this string should
-   contain the name of the current namespace.  The string is
-   temporary; copy it if you need it.  */
+/* This contains our best guess as to the name of the current
+   enclosing namespace(s)/class(es), if any.  For example, if we're
+   within the method foo() in the following code:
+
+    namespace N {
+      class C {
+       void foo () {
+       }
+      };
+    }
 
-/* FIXME: carlton/2003-06-12: This isn't entirely reliable: currently,
-   we get mislead by DW_AT_specification.  */
+   then processing_current_prefix should be set to "N::C".  If
+   processing_has_namespace_info is false, then this variable might
+   not be reliable.  */
 
-const char *processing_current_namespace;
+const char *processing_current_prefix;
 
 /* List of using directives that are active in the current file.  */
 
@@ -70,6 +86,30 @@ static struct symbol *lookup_symbol_file (const char *name,
                                          struct symtab **symtab,
                                          int anonymous_namespace);
 
+static struct type *cp_lookup_transparent_type_loop (const char *name,
+                                                    const char *scope,
+                                                    int scope_len);
+
+static void initialize_namespace_symtab (struct objfile *objfile);
+
+static struct block *get_possible_namespace_block (struct objfile *objfile);
+
+static void free_namespace_block (struct symtab *symtab);
+
+static int check_possible_namespace_symbols_loop (const char *name,
+                                                 int len,
+                                                 struct objfile *objfile);
+
+static int check_one_possible_namespace_symbol (const char *name,
+                                               int len,
+                                               struct objfile *objfile);
+
+static
+struct symbol *lookup_possible_namespace_symbol (const char *name,
+                                                struct symtab **symtab);
+
+static void maintenance_cplus_namespace (char *args, int from_tty);
+
 /* Set up support for dealing with C++ namespace info in the current
    symtab.  */
 
@@ -190,22 +230,15 @@ cp_set_block_scope (const struct symbol *symbol,
 
   if (SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
     {
-#if 0
-      /* FIXME: carlton/2003-06-12: As mentioned above,
-        'processing_has_namespace_info' currently isn't entirely
-        reliable, so let's always use demangled names to get this
-        information for now.  */
-
       if (processing_has_namespace_info)
        {
          block_set_scope
-           (block, obsavestring (processing_current_namespace,
-                                 strlen (processing_current_namespace),
+           (block, obsavestring (processing_current_prefix,
+                                 strlen (processing_current_prefix),
                                  obstack),
             obstack);
        }
       else
-#endif
        {
          /* Try to figure out the appropriate namespace from the
             demangled name.  */
@@ -316,7 +349,7 @@ cp_lookup_symbol_nonlocal (const char *name,
    cp_lookup_symbol_nonlocal.
 
    For example, if we're within a function A::B::f and looking for a
-   symbol f, this will get called with NAME = "f", SCOPE = "A::B", and
+   symbol x, this will get called with NAME = "x", SCOPE = "A::B", and
    SCOPE_LEN = 0.  It then calls itself with NAME and SCOPE the same,
    but with SCOPE_LEN = 1.  And then it calls itself with NAME and
    SCOPE the same, but with SCOPE_LEN = 4.  This third call looks for
@@ -453,13 +486,386 @@ lookup_symbol_file (const char *name,
       const struct block *global_block = block_global_block (block);
       
       if (global_block != NULL)
-       return lookup_symbol_aux_block (name, linkage_name, global_block,
-                                       domain, symtab);
-      else
-       return NULL;
+       sym = lookup_symbol_aux_block (name, linkage_name, global_block,
+                                      domain, symtab);
+    }
+  else
+    {
+      sym = lookup_symbol_global (name, linkage_name, domain, symtab);
+    }
+
+  if (sym != NULL)
+    return sym;
+
+  /* Now call "lookup_possible_namespace_symbol".  Symbols in here
+     claim to be associated to namespaces, but this claim might be
+     incorrect: the names in question might actually correspond to
+     classes instead of namespaces.  But if they correspond to
+     classes, then we should have found a match for them above.  So if
+     we find them now, they should be genuine.  */
+
+  /* FIXME: carlton/2003-06-12: This is a hack and should eventually
+     be deleted: see comments below.  */
+
+  if (domain == VAR_DOMAIN)
+    {
+      sym = lookup_possible_namespace_symbol (name, symtab);
+      if (sym != NULL)
+       return sym;
+    }
+
+  return NULL;
+}
+
+/* Look up a type named NESTED_NAME that is nested inside the C++
+   class or namespace given by PARENT_TYPE, from within the context
+   given by BLOCK.  Return NULL if there is no such nested type.  */
+
+struct type *
+cp_lookup_nested_type (struct type *parent_type,
+                      const char *nested_name,
+                      const struct block *block)
+{
+  switch (TYPE_CODE (parent_type))
+    {
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_NAMESPACE:
+      {
+       /* NOTE: carlton/2003-11-10: We don't treat C++ class members
+          of classes like, say, data or function members.  Instead,
+          they're just represented by symbols whose names are
+          qualified by the name of the surrounding class.  This is
+          just like members of namespaces; in particular,
+          lookup_symbol_namespace works when looking them up.  */
+
+       const char *parent_name = TYPE_TAG_NAME (parent_type);
+       struct symbol *sym = cp_lookup_symbol_namespace (parent_name,
+                                                        nested_name,
+                                                        NULL,
+                                                        block,
+                                                        VAR_DOMAIN,
+                                                        NULL);
+       if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+         return NULL;
+       else
+         return SYMBOL_TYPE (sym);
+      }
+    default:
+      internal_error (__FILE__, __LINE__,
+                     _("cp_lookup_nested_type called on a non-aggregate type."));
+    }
+}
+
+/* The C++-version of lookup_transparent_type.  */
+
+/* FIXME: carlton/2004-01-16: The problem that this is trying to
+   address is that, unfortunately, sometimes NAME is wrong: it may not
+   include the name of namespaces enclosing the type in question.
+   lookup_transparent_type gets called when the the type in question
+   is a declaration, and we're trying to find its definition; but, for
+   declarations, our type name deduction mechanism doesn't work.
+   There's nothing we can do to fix this in general, I think, in the
+   absence of debug information about namespaces (I've filed PR
+   gdb/1511 about this); until such debug information becomes more
+   prevalent, one heuristic which sometimes looks is to search for the
+   definition in namespaces containing the current namespace.
+
+   We should delete this functions once the appropriate debug
+   information becomes more widespread.  (GCC 3.4 will be the first
+   released version of GCC with such information.)  */
+
+struct type *
+cp_lookup_transparent_type (const char *name)
+{
+  /* First, try the honest way of looking up the definition.  */
+  struct type *t = basic_lookup_transparent_type (name);
+  const char *scope;
+
+  if (t != NULL)
+    return t;
+
+  /* If that doesn't work and we're within a namespace, look there
+     instead.  */
+  scope = block_scope (get_selected_block (0));
+
+  if (scope[0] == '\0')
+    return NULL;
+
+  return cp_lookup_transparent_type_loop (name, scope, 0);
+}
+
+/* Lookup the the type definition associated to NAME in
+   namespaces/classes containing SCOPE whose name is strictly longer
+   than LENGTH.  LENGTH must be the index of the start of a
+   component of SCOPE.  */
+
+static struct type *
+cp_lookup_transparent_type_loop (const char *name, const char *scope,
+                                int length)
+{
+  int scope_length = length + cp_find_first_component (scope + length);
+  char *full_name;
+
+  /* If the current scope is followed by "::", look in the next
+     component.  */
+  if (scope[scope_length] == ':')
+    {
+      struct type *retval
+       = cp_lookup_transparent_type_loop (name, scope, scope_length + 2);
+      if (retval != NULL)
+       return retval;
+    }
+
+  full_name = alloca (scope_length + 2 + strlen (name) + 1);
+  strncpy (full_name, scope, scope_length);
+  strncpy (full_name + scope_length, "::", 2);
+  strcpy (full_name + scope_length + 2, name);
+
+  return basic_lookup_transparent_type (full_name);
+}
+
+/* Now come functions for dealing with symbols associated to
+   namespaces.  (They're used to store the namespaces themselves, not
+   objects that live in the namespaces.)  These symbols come in two
+   varieties: if we run into a DW_TAG_namespace DIE, then we know that
+   we have a namespace, so dwarf2read.c creates a symbol for it just
+   like normal.  But, unfortunately, versions of GCC through at least
+   3.3 don't generate those DIE's.  Our solution is to try to guess
+   their existence by looking at demangled names.  This might cause us
+   to misidentify classes as namespaces, however.  So we put those
+   symbols in a special block (one per objfile), and we only search
+   that block as a last resort.  */
+
+/* FIXME: carlton/2003-06-12: Once versions of GCC that generate
+   DW_TAG_namespace have been out for a year or two, we should get rid
+   of all of this "possible namespace" nonsense.  */
+
+/* Allocate everything necessary for the possible namespace block
+   associated to OBJFILE.  */
+
+static void
+initialize_namespace_symtab (struct objfile *objfile)
+{
+  struct symtab *namespace_symtab;
+  struct blockvector *bv;
+  struct block *bl;
+
+  namespace_symtab = allocate_symtab ("<<C++-namespaces>>", objfile);
+  namespace_symtab->language = language_cplus;
+  namespace_symtab->free_code = free_nothing;
+  namespace_symtab->dirname = NULL;
+
+  bv = obstack_alloc (&objfile->objfile_obstack,
+                     sizeof (struct blockvector)
+                     + FIRST_LOCAL_BLOCK * sizeof (struct block *));
+  BLOCKVECTOR_NBLOCKS (bv) = FIRST_LOCAL_BLOCK + 1;
+  BLOCKVECTOR (namespace_symtab) = bv;
+  
+  /* Allocate empty GLOBAL_BLOCK and STATIC_BLOCK. */
+
+  bl = allocate_block (&objfile->objfile_obstack);
+  BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack,
+                                       NULL);
+  BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+  bl = allocate_block (&objfile->objfile_obstack);
+  BLOCK_DICT (bl) = dict_create_linear (&objfile->objfile_obstack,
+                                       NULL);
+  BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
+
+  /* Allocate the possible namespace block; we put it where the first
+     local block will live, though I don't think there's any need to
+     pretend that it's actually a local block (e.g. by setting
+     BLOCK_SUPERBLOCK appropriately).  We don't use the global or
+     static block because we don't want it searched during the normal
+     search of all global/static blocks in lookup_symbol: we only want
+     it used as a last resort.  */
+
+  /* NOTE: carlton/2003-09-11: I considered not associating the fake
+     symbols to a block/symtab at all.  But that would cause problems
+     with lookup_symbol's SYMTAB argument and with block_found, so
+     having a symtab/block for this purpose seems like the best
+     solution for now.  */
+
+  bl = allocate_block (&objfile->objfile_obstack);
+  BLOCK_DICT (bl) = dict_create_hashed_expandable ();
+  BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK) = bl;
+
+  namespace_symtab->free_func = free_namespace_block;
+
+  objfile->cp_namespace_symtab = namespace_symtab;
+}
+
+/* Locate the possible namespace block associated to OBJFILE,
+   allocating it if necessary.  */
+
+static struct block *
+get_possible_namespace_block (struct objfile *objfile)
+{
+  if (objfile->cp_namespace_symtab == NULL)
+    initialize_namespace_symtab (objfile);
+
+  return BLOCKVECTOR_BLOCK (BLOCKVECTOR (objfile->cp_namespace_symtab),
+                           FIRST_LOCAL_BLOCK);
+}
+
+/* Free the dictionary associated to the possible namespace block.  */
+
+static void
+free_namespace_block (struct symtab *symtab)
+{
+  struct block *possible_namespace_block;
+
+  possible_namespace_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab),
+                                               FIRST_LOCAL_BLOCK);
+  gdb_assert (possible_namespace_block != NULL);
+  dict_free (BLOCK_DICT (possible_namespace_block));
+}
+
+/* Ensure that there are symbols in the possible namespace block
+   associated to OBJFILE for all initial substrings of NAME that look
+   like namespaces or classes.  NAME should end in a member variable:
+   it shouldn't consist solely of namespaces.  */
+
+void
+cp_check_possible_namespace_symbols (const char *name, struct objfile *objfile)
+{
+  check_possible_namespace_symbols_loop (name,
+                                        cp_find_first_component (name),
+                                        objfile);
+}
+
+/* This is a helper loop for cp_check_possible_namespace_symbols; it
+   ensures that there are symbols in the possible namespace block
+   associated to OBJFILE for all namespaces that are initial
+   substrings of NAME of length at least LEN.  It returns 1 if a
+   previous loop had already created the shortest such symbol and 0
+   otherwise.
+
+   This function assumes that if there is already a symbol associated
+   to a substring of NAME of a given length, then there are already
+   symbols associated to all substrings of NAME whose length is less
+   than that length.  So if cp_check_possible_namespace_symbols has
+   been called once with argument "A::B::C::member", then that will
+   create symbols "A", "A::B", and "A::B::C".  If it is then later
+   called with argument "A::B::D::member", then the new call will
+   generate a new symbol for "A::B::D", but once it sees that "A::B"
+   has already been created, it doesn't bother checking to see if "A"
+   has also been created.  */
+
+static int
+check_possible_namespace_symbols_loop (const char *name, int len,
+                                      struct objfile *objfile)
+{
+  if (name[len] == ':')
+    {
+      int done;
+      int next_len = len + 2;
+
+      next_len += cp_find_first_component (name + next_len);
+      done = check_possible_namespace_symbols_loop (name, next_len,
+                                                   objfile);
+
+      if (!done)
+       done = check_one_possible_namespace_symbol (name, len, objfile);
+
+      return done;
+    }
+  else
+    return 0;
+}
+
+/* Check to see if there's already a possible namespace symbol in
+   OBJFILE whose name is the initial substring of NAME of length LEN.
+   If not, create one and return 0; otherwise, return 1.  */
+
+static int
+check_one_possible_namespace_symbol (const char *name, int len,
+                                    struct objfile *objfile)
+{
+  struct block *block = get_possible_namespace_block (objfile);
+  char *name_copy = alloca (len + 1);
+  struct symbol *sym;
+
+  memcpy (name_copy, name, len);
+  name_copy[len] = '\0';
+  sym = lookup_block_symbol (block, name_copy, NULL, VAR_DOMAIN);
+
+  if (sym == NULL)
+    {
+      struct type *type;
+      name_copy = obsavestring (name, len, &objfile->objfile_obstack);
+
+      type = init_type (TYPE_CODE_NAMESPACE, 0, 0, name_copy, objfile);
+
+      TYPE_TAG_NAME (type) = TYPE_NAME (type);
+
+      sym = obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol));
+      memset (sym, 0, sizeof (struct symbol));
+      SYMBOL_LANGUAGE (sym) = language_cplus;
+      SYMBOL_SET_NAMES (sym, name_copy, len, objfile);
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_TYPE (sym) = type;
+      SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+
+      dict_add_symbol (BLOCK_DICT (block), sym);
+
+      return 0;
     }
   else
+    return 1;
+}
+
+/* Look for a symbol named NAME in all the possible namespace blocks.
+   If one is found, return it; if SYMTAB is non-NULL, set *SYMTAB to
+   equal the symtab where it was found.  */
+
+static struct symbol *
+lookup_possible_namespace_symbol (const char *name, struct symtab **symtab)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+    {
+      struct symbol *sym;
+
+      sym = lookup_block_symbol (get_possible_namespace_block (objfile),
+                                name, NULL, VAR_DOMAIN);
+
+      if (sym != NULL)
+       {
+         if (symtab != NULL)
+           *symtab = objfile->cp_namespace_symtab;
+
+         return sym;
+       }
+    }
+
+  return NULL;
+}
+
+/* Print out all the possible namespace symbols.  */
+
+static void
+maintenance_cplus_namespace (char *args, int from_tty)
+{
+  struct objfile *objfile;
+  printf_unfiltered (_("Possible namespaces:\n"));
+  ALL_OBJFILES (objfile)
     {
-      return lookup_symbol_global (name, linkage_name, domain, symtab);
+      struct dict_iterator iter;
+      struct symbol *sym;
+
+      ALL_BLOCK_SYMBOLS (get_possible_namespace_block (objfile), iter, sym)
+       {
+         printf_unfiltered ("%s\n", SYMBOL_PRINT_NAME (sym));
+       }
     }
 }
+
+void
+_initialize_cp_namespace (void)
+{
+  add_cmd ("namespace", class_maintenance, maintenance_cplus_namespace,
+          "Print the list of possible C++ namespaces.",
+          &maint_cplus_cmd_list);
+}