mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-06 15:43:09 +00:00
This patch adds another minor hack to cooked_index_entry::full_name. In particular, if GNAT emits non-hierarchical names (still the default as the hierarchical series is blocked on one tricky problem), then a request to compute the "linkage-style" name will now just return the 'name' field. Without this tweak, this series would regress ada-cold-name.exp, because the search would look for "name.cold" but the index would return "name[cold]" as the "linkage" name (which would be wrong). This area is a bit difficult to unravel. The best plan here, IMO, is to change Ada to work like the other languages in gdb: store the natural name and do searches with that name. I think this is achievable, but I didn't want to try it here. I've updated the relevant bug (tagged below) to reflect this. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32766 Acked-By: Simon Marchi <simon.marchi@efficios.com>
249 lines
7.3 KiB
C
249 lines
7.3 KiB
C
/* Entry in the cooked index
|
|
|
|
Copyright (C) 2022-2025 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/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),
|
|
MAP_ENUM_FLAG (IS_SYNTHESIZED),
|
|
};
|
|
|
|
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 c_tolower (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 GNAT emits hierarchical names (patches not in at the time
|
|
of writing), then we need to compute the linkage name here.
|
|
However for traditional GNAT, the linkage name will be in
|
|
'name'. Detect this by looking for "__"; see also
|
|
cooked_index_shard::finalize. */
|
|
if ((name_flags & FOR_ADA_LINKAGE_NAME) != 0)
|
|
{
|
|
if (strstr (name, "__") != nullptr)
|
|
return name;
|
|
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));
|
|
}
|
|
|
|
INIT_GDB_FILE (dwarf2_entry)
|
|
{
|
|
#if GDB_SELF_TEST
|
|
selftests::register_test ("cooked_index_entry::compare", test_compare);
|
|
#endif
|
|
}
|