diff options
author | Joel Brobecker <brobecker@gnat.com> | 2011-07-01 18:26:50 +0000 |
---|---|---|
committer | Joel Brobecker <brobecker@gnat.com> | 2011-07-01 18:26:50 +0000 |
commit | 8f17729f21e54827ba8de614be382c4fbd6b690f (patch) | |
tree | 92add7a0018deb53f1793f0ea2d22f4fc38fd14d /gdb/ada-lang.c | |
parent | f5aa6869dee6874a9d1a3a386b1d5893f0ac46d4 (diff) | |
download | gdb-8f17729f21e54827ba8de614be382c4fbd6b690f.zip gdb-8f17729f21e54827ba8de614be382c4fbd6b690f.tar.gz gdb-8f17729f21e54827ba8de614be382c4fbd6b690f.tar.bz2 |
treat identical enum types as the same type
This is to avoid an unnecessary multiple-choice menu for an
expression involving an enumeral declared in two types, when
the second type is an identical copy of the first type. This
happens in the following situation:
type Color is (Black, Red, Green, Blue, White);
type RGB_Color is new Color range Red .. Blue;
In that case, an implict type is created, and is used as the base
type for type RGB_Color. This base type is a copy of type Color.
We've added some extensive comments explaining the situation and
our approach further.
gdb/ChangeLog:
* ada-lang.c (ada_identical_enum_types_p): New function.
(symbols_are_identical_enums): New function.
(remove_extra_symbols): Do nothing if NSYMS < 2.
Use symbols_are_identical_enums.
gdb/testsuite/ChangeLog:
* gdb.ada/same_enum: New testcase.
Diffstat (limited to 'gdb/ada-lang.c')
-rw-r--r-- | gdb/ada-lang.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index dd77852..766bfc8 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -4365,6 +4365,108 @@ is_nondebugging_type (struct type *type) return (name != NULL && strcmp (name, "<variable, no debug info>") == 0); } +/* Return nonzero if TYPE1 and TYPE2 are two enumeration types + that are deemed "identical" for practical purposes. + + This function assumes that TYPE1 and TYPE2 are both TYPE_CODE_ENUM + types and that their number of enumerals is identical (in other + words, TYPE_NFIELDS (type1) == TYPE_NFIELDS (type2)). */ + +static int +ada_identical_enum_types_p (struct type *type1, struct type *type2) +{ + int i; + + /* The heuristic we use here is fairly conservative. We consider + that 2 enumerate types are identical if they have the same + number of enumerals and that all enumerals have the same + underlying value and name. */ + + /* All enums in the type should have an identical underlying value. */ + for (i = 0; i < TYPE_NFIELDS (type1); i++) + if (TYPE_FIELD_BITPOS (type1, i) != TYPE_FIELD_BITPOS (type2, i)) + return 0; + + /* All enumerals should also have the same name (modulo any numerical + suffix). */ + for (i = 0; i < TYPE_NFIELDS (type1); i++) + { + char *name_1 = TYPE_FIELD_NAME (type1, i); + char *name_2 = TYPE_FIELD_NAME (type2, i); + int len_1 = strlen (name_1); + int len_2 = strlen (name_2); + + ada_remove_trailing_digits (TYPE_FIELD_NAME (type1, i), &len_1); + ada_remove_trailing_digits (TYPE_FIELD_NAME (type2, i), &len_2); + if (len_1 != len_2 + || strncmp (TYPE_FIELD_NAME (type1, i), + TYPE_FIELD_NAME (type2, i), + len_1) != 0) + return 0; + } + + return 1; +} + +/* Return nonzero if all the symbols in SYMS are all enumeral symbols + that are deemed "identical" for practical purposes. Sometimes, + enumerals are not strictly identical, but their types are so similar + that they can be considered identical. + + For instance, consider the following code: + + type Color is (Black, Red, Green, Blue, White); + type RGB_Color is new Color range Red .. Blue; + + Type RGB_Color is a subrange of an implicit type which is a copy + of type Color. If we call that implicit type RGB_ColorB ("B" is + for "Base Type"), then type RGB_ColorB is a copy of type Color. + As a result, when an expression references any of the enumeral + by name (Eg. "print green"), the expression is technically + ambiguous and the user should be asked to disambiguate. But + doing so would only hinder the user, since it wouldn't matter + what choice he makes, the outcome would always be the same. + So, for practical purposes, we consider them as the same. */ + +static int +symbols_are_identical_enums (struct ada_symbol_info *syms, int nsyms) +{ + int i; + + /* Before performing a thorough comparison check of each type, + we perform a series of inexpensive checks. We expect that these + checks will quickly fail in the vast majority of cases, and thus + help prevent the unnecessary use of a more expensive comparison. + Said comparison also expects us to make some of these checks + (see ada_identical_enum_types_p). */ + + /* Quick check: All symbols should have an enum type. */ + for (i = 0; i < nsyms; i++) + if (TYPE_CODE (SYMBOL_TYPE (syms[i].sym)) != TYPE_CODE_ENUM) + return 0; + + /* Quick check: They should all have the same value. */ + for (i = 1; i < nsyms; i++) + if (SYMBOL_VALUE (syms[i].sym) != SYMBOL_VALUE (syms[0].sym)) + return 0; + + /* Quick check: They should all have the same number of enumerals. */ + for (i = 1; i < nsyms; i++) + if (TYPE_NFIELDS (SYMBOL_TYPE (syms[i].sym)) + != TYPE_NFIELDS (SYMBOL_TYPE (syms[0].sym))) + return 0; + + /* All the sanity checks passed, so we might have a set of + identical enumeration types. Perform a more complete + comparison of the type of each symbol. */ + for (i = 1; i < nsyms; i++) + if (!ada_identical_enum_types_p (SYMBOL_TYPE (syms[i].sym), + SYMBOL_TYPE (syms[0].sym))) + return 0; + + return 1; +} + /* Remove any non-debugging symbols in SYMS[0 .. NSYMS-1] that definitely duplicate other symbols in the list (The only case I know of where this happens is when object files containing stabs-in-ecoff are @@ -4377,6 +4479,12 @@ remove_extra_symbols (struct ada_symbol_info *syms, int nsyms) { int i, j; + /* We should never be called with less than 2 symbols, as there + cannot be any extra symbol in that case. But it's easy to + handle, since we have nothing to do in that case. */ + if (nsyms < 2) + return nsyms; + i = 0; while (i < nsyms) { @@ -4428,6 +4536,22 @@ remove_extra_symbols (struct ada_symbol_info *syms, int nsyms) i += 1; } + + /* If all the remaining symbols are identical enumerals, then + just keep the first one and discard the rest. + + Unlike what we did previously, we do not discard any entry + unless they are ALL identical. This is because the symbol + comparison is not a strict comparison, but rather a practical + comparison. If all symbols are considered identical, then + we can just go ahead and use the first one and discard the rest. + But if we cannot reduce the list to a single element, we have + to ask the user to disambiguate anyways. And if we have to + present a multiple-choice menu, it's less confusing if the list + isn't missing some choices that were identical and yet distinct. */ + if (symbols_are_identical_enums (syms, nsyms)) + nsyms = 1; + return nsyms; } |