diff options
Diffstat (limited to 'gdb/dwarf2/cooked-index-entry.c')
-rw-r--r-- | gdb/dwarf2/cooked-index-entry.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/gdb/dwarf2/cooked-index-entry.c b/gdb/dwarf2/cooked-index-entry.c new file mode 100644 index 0000000..3e322f1 --- /dev/null +++ b/gdb/dwarf2/cooked-index-entry.c @@ -0,0 +1,242 @@ +/* Entry in the cooked index + + Copyright (C) 2022-2024 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "dwarf2/cooked-index-entry.h" +#include "dwarf2/tag.h" +#include "gdbsupport/gdb-safe-ctype.h" +#include "gdbsupport/selftest.h" + +/* See cooked-index-entry.h. */ + +std::string +to_string (cooked_index_flag flags) +{ + static constexpr cooked_index_flag::string_mapping mapping[] = { + MAP_ENUM_FLAG (IS_MAIN), + MAP_ENUM_FLAG (IS_STATIC), + MAP_ENUM_FLAG (IS_LINKAGE), + MAP_ENUM_FLAG (IS_TYPE_DECLARATION), + MAP_ENUM_FLAG (IS_PARENT_DEFERRED), + }; + + return flags.to_string (mapping); +} + +/* See cooked-index-entry.h. */ + +int +cooked_index_entry::compare (const char *stra, const char *strb, + comparison_mode mode) +{ +#if defined (__GNUC__) && !defined (__clang__) && __GNUC__ <= 7 + /* Work around error with gcc 7.5.0. */ + auto munge = [] (char c) -> unsigned char +#else + auto munge = [] (char c) constexpr -> unsigned char +#endif + { + /* Treat '<' as if it ended the string. This lets something + like "func<t>" match "func<t<int>>". See the "Breakpoints in + template functions" section in the manual. */ + if (c == '<') + return '\0'; + return TOLOWER ((unsigned char) c); + }; + + unsigned char a = munge (*stra); + unsigned char b = munge (*strb); + + while (a != '\0' && b != '\0' && a == b) + { + a = munge (*++stra); + b = munge (*++strb); + } + + if (a == b) + return 0; + + /* When completing, if STRB ends earlier than STRA, consider them as + equal. */ + if (mode == COMPLETE && b == '\0') + return 0; + + return a < b ? -1 : 1; +} + +#if GDB_SELF_TEST + +namespace { + +void +test_compare () +{ + /* Convenience aliases. */ + const auto mode_compare = cooked_index_entry::MATCH; + const auto mode_sort = cooked_index_entry::SORT; + const auto mode_complete = cooked_index_entry::COMPLETE; + + SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", + mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", + mode_compare) < 0); + SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", + mode_compare) > 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", + mode_complete) < 0); + SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", + mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("name", "name<>", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<>", "name", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name", "name<>", + mode_complete) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<>", "name", + mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>", + mode_complete) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>", + mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", + "name<arg<more>>", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg>", + "name<arg<more>>", + mode_compare) == 0); + + SELF_CHECK (cooked_index_entry::compare ("name", "name<arg<more>>", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<", + mode_compare) == 0); + SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<", + mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_compare) < 0); + SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_complete) < 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_compare) > 0); + SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0); + + SELF_CHECK (cooked_index_entry::compare ("func", "func<type>", + mode_sort) == 0); + SELF_CHECK (cooked_index_entry::compare ("func<type>", "func1", + mode_sort) < 0); +} + +} /* anonymous namespace */ + +#endif /* GDB_SELF_TEST */ + +/* See cooked-index-entry.h. */ + +bool +cooked_index_entry::matches (domain_search_flags kind) const +{ + /* Just reject type declarations. */ + if ((flags & IS_TYPE_DECLARATION) != 0) + return false; + + return tag_matches_domain (tag, kind, lang); +} + +/* See cooked-index-entry.h. */ + +const char * +cooked_index_entry::full_name (struct obstack *storage, + cooked_index_full_name_flag name_flags, + const char *default_sep) const +{ + const char *local_name = ((name_flags & FOR_MAIN) != 0) ? name : canonical; + + if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr) + return local_name; + + const char *sep = default_sep; + switch (lang) + { + case language_cplus: + case language_rust: + case language_fortran: + sep = "::"; + break; + + case language_ada: + if ((name_flags & FOR_ADA_LINKAGE_NAME) != 0) + { + sep = "__"; + break; + } + [[fallthrough]]; + case language_go: + case language_d: + sep = "."; + break; + + default: + if (sep == nullptr) + return local_name; + break; + } + + /* The FOR_ADA_LINKAGE_NAME flag should only affect Ada entries, so + disable it here if we don't need it. */ + if (lang != language_ada) + name_flags &= ~FOR_ADA_LINKAGE_NAME; + + get_parent ()->write_scope (storage, sep, name_flags); + obstack_grow0 (storage, local_name, strlen (local_name)); + return (const char *) obstack_finish (storage); +} + +/* See cooked-index-entry.h. */ + +void +cooked_index_entry::write_scope (struct obstack *storage, + const char *sep, + cooked_index_full_name_flag flags) const +{ + if (get_parent () != nullptr) + get_parent ()->write_scope (storage, sep, flags); + /* When computing the Ada linkage name, the entry might not have + been canonicalized yet, so use the 'name'. */ + const char *local_name = ((flags & (FOR_MAIN | FOR_ADA_LINKAGE_NAME)) != 0 + ? name + : canonical); + obstack_grow (storage, local_name, strlen (local_name)); + obstack_grow (storage, sep, strlen (sep)); +} + +void _initialize_dwarf2_entry (); +void _initialize_dwarf2_entry () +{ +#if GDB_SELF_TEST + selftests::register_test ("cooked_index_entry::compare", test_compare); +#endif +} |