aboutsummaryrefslogtreecommitdiff
path: root/gdb/dwarf2/cooked-index-entry.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/dwarf2/cooked-index-entry.c')
-rw-r--r--gdb/dwarf2/cooked-index-entry.c242
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
+}