[lldb] Improve RichManglingContext ergonomics (NFC)

Have the different ::Parse.* methods return the demangled string
directly instead of having to go through ::GetBufferRef.

Differential revision: https://reviews.llvm.org/D118953
This commit is contained in:
Jonas Devlieghere 2022-02-03 17:26:19 -08:00
parent 9d1857f69f
commit fa52788b7a
5 changed files with 46 additions and 88 deletions

View File

@ -43,25 +43,15 @@ public:
bool IsCtorOrDtor() const; bool IsCtorOrDtor() const;
/// Get the base name of a function. This doesn't include trailing template /// Get the base name of a function. This doesn't include trailing template
/// arguments, ie "a::b<int>" gives "b". The result will overwrite the /// arguments, ie "a::b<int>" gives "b".
/// internal buffer. It can be obtained via GetBufferRef(). llvm::StringRef ParseFunctionBaseName();
void ParseFunctionBaseName();
/// Get the context name for a function. For "a::b::c", this function returns /// Get the context name for a function. For "a::b::c", this function returns
/// "a::b". The result will overwrite the internal buffer. It can be obtained /// "a::b".
/// via GetBufferRef(). llvm::StringRef ParseFunctionDeclContextName();
void ParseFunctionDeclContextName();
/// Get the entire demangled name. The result will overwrite the internal /// Get the entire demangled name.
/// buffer. It can be obtained via GetBufferRef(). llvm::StringRef ParseFullName();
void ParseFullName();
/// Obtain a StringRef to the internal buffer that holds the result of the
/// most recent ParseXy() operation. The next ParseXy() call invalidates it.
llvm::StringRef GetBufferRef() const {
assert(m_provider != None && "Initialize a provider first");
return m_buffer;
}
private: private:
enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage }; enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage };
@ -69,9 +59,6 @@ private:
/// Selects the rich mangling info provider. /// Selects the rich mangling info provider.
InfoProvider m_provider = None; InfoProvider m_provider = None;
/// Reference to the buffer used for results of ParseXy() operations.
llvm::StringRef m_buffer;
/// Members for ItaniumPartialDemangler /// Members for ItaniumPartialDemangler
llvm::ItaniumPartialDemangler m_ipd; llvm::ItaniumPartialDemangler m_ipd;
/// Note: m_ipd_buf is a raw pointer due to being resized by realloc via /// Note: m_ipd_buf is a raw pointer due to being resized by realloc via
@ -93,7 +80,7 @@ private:
void ResetProvider(InfoProvider new_provider); void ResetProvider(InfoProvider new_provider);
/// Uniform handling of string buffers for ItaniumPartialDemangler. /// Uniform handling of string buffers for ItaniumPartialDemangler.
void processIPDStrResult(char *ipd_res, size_t res_len); llvm::StringRef processIPDStrResult(char *ipd_res, size_t res_len);
/// Cast the given parser to the given type. Ideally we would have a type /// Cast the given parser to the given type. Ideally we would have a type
/// trait to deduce \a ParserT from a given InfoProvider, but unfortunately we /// trait to deduce \a ParserT from a given InfoProvider, but unfortunately we

View File

@ -217,8 +217,7 @@ bool Mangled::DemangleWithRichManglingInfo(
if (context.FromItaniumName(m_mangled)) { if (context.FromItaniumName(m_mangled)) {
// If we got an info, we have a name. Copy to string pool and connect the // If we got an info, we have a name. Copy to string pool and connect the
// counterparts to accelerate later access in GetDemangledName(). // counterparts to accelerate later access in GetDemangledName().
context.ParseFullName(); m_demangled.SetStringWithMangledCounterpart(context.ParseFullName(),
m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(),
m_mangled); m_mangled);
return true; return true;
} else { } else {

View File

@ -80,15 +80,15 @@ bool RichManglingContext::IsCtorOrDtor() const {
llvm_unreachable("Fully covered switch above!"); llvm_unreachable("Fully covered switch above!");
} }
void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) { llvm::StringRef RichManglingContext::processIPDStrResult(char *ipd_res,
size_t res_size) {
// Error case: Clear the buffer. // Error case: Clear the buffer.
if (LLVM_UNLIKELY(ipd_res == nullptr)) { if (LLVM_UNLIKELY(ipd_res == nullptr)) {
assert(res_size == m_ipd_buf_size && assert(res_size == m_ipd_buf_size &&
"Failed IPD queries keep the original size in the N parameter"); "Failed IPD queries keep the original size in the N parameter");
m_ipd_buf[0] = '\0'; m_ipd_buf[0] = '\0';
m_buffer = llvm::StringRef(m_ipd_buf, 0); return llvm::StringRef(m_ipd_buf, 0);
return;
} }
// IPD's res_size includes null terminator. // IPD's res_size includes null terminator.
@ -106,60 +106,54 @@ void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
} }
// 99% case: Just remember the string length. // 99% case: Just remember the string length.
m_buffer = llvm::StringRef(m_ipd_buf, res_size - 1); return llvm::StringRef(m_ipd_buf, res_size - 1);
} }
void RichManglingContext::ParseFunctionBaseName() { llvm::StringRef RichManglingContext::ParseFunctionBaseName() {
assert(m_provider != None && "Initialize a provider first"); assert(m_provider != None && "Initialize a provider first");
switch (m_provider) { switch (m_provider) {
case ItaniumPartialDemangler: { case ItaniumPartialDemangler: {
auto n = m_ipd_buf_size; auto n = m_ipd_buf_size;
auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n); auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
processIPDStrResult(buf, n); return processIPDStrResult(buf, n);
return;
} }
case PluginCxxLanguage: case PluginCxxLanguage:
m_buffer = return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename(); ->GetBasename();
return;
case None: case None:
return; return {};
} }
} }
void RichManglingContext::ParseFunctionDeclContextName() { llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() {
assert(m_provider != None && "Initialize a provider first"); assert(m_provider != None && "Initialize a provider first");
switch (m_provider) { switch (m_provider) {
case ItaniumPartialDemangler: { case ItaniumPartialDemangler: {
auto n = m_ipd_buf_size; auto n = m_ipd_buf_size;
auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n); auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
processIPDStrResult(buf, n); return processIPDStrResult(buf, n);
return;
} }
case PluginCxxLanguage: case PluginCxxLanguage:
m_buffer = return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext(); ->GetContext();
return;
case None: case None:
return; return {};
} }
} }
void RichManglingContext::ParseFullName() { llvm::StringRef RichManglingContext::ParseFullName() {
assert(m_provider != None && "Initialize a provider first"); assert(m_provider != None && "Initialize a provider first");
switch (m_provider) { switch (m_provider) {
case ItaniumPartialDemangler: { case ItaniumPartialDemangler: {
auto n = m_ipd_buf_size; auto n = m_ipd_buf_size;
auto buf = m_ipd.finishDemangle(m_ipd_buf, &n); auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
processIPDStrResult(buf, n); return processIPDStrResult(buf, n);
return;
} }
case PluginCxxLanguage: case PluginCxxLanguage:
m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
->GetFullName() ->GetFullName()
.GetStringRef(); .GetStringRef();
return;
case None: case None:
return; return {};
} }
} }

View File

@ -383,16 +383,13 @@ void Symtab::RegisterMangledNameEntry(
std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog, std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
RichManglingContext &rmc) { RichManglingContext &rmc) {
// Only register functions that have a base name. // Only register functions that have a base name.
rmc.ParseFunctionBaseName(); llvm::StringRef base_name = rmc.ParseFunctionBaseName();
llvm::StringRef base_name = rmc.GetBufferRef();
if (base_name.empty()) if (base_name.empty())
return; return;
// The base name will be our entry's name. // The base name will be our entry's name.
NameToIndexMap::Entry entry(ConstString(base_name), value); NameToIndexMap::Entry entry(ConstString(base_name), value);
llvm::StringRef decl_context = rmc.ParseFunctionDeclContextName();
rmc.ParseFunctionDeclContextName();
llvm::StringRef decl_context = rmc.GetBufferRef();
// Register functions with no context. // Register functions with no context.
if (decl_context.empty()) { if (decl_context.empty()) {

View File

@ -18,18 +18,12 @@ using namespace lldb_private;
TEST(RichManglingContextTest, Basic) { TEST(RichManglingContextTest, Basic) {
RichManglingContext RMC; RichManglingContext RMC;
ConstString mangled("_ZN3foo3barEv"); ConstString mangled("_ZN3foo3barEv");
EXPECT_TRUE(RMC.FromItaniumName(mangled)); EXPECT_TRUE(RMC.FromItaniumName(mangled));
EXPECT_FALSE(RMC.IsCtorOrDtor()); EXPECT_FALSE(RMC.IsCtorOrDtor());
EXPECT_EQ("foo", RMC.ParseFunctionDeclContextName());
RMC.ParseFunctionDeclContextName(); EXPECT_EQ("bar", RMC.ParseFunctionBaseName());
EXPECT_EQ("foo", RMC.GetBufferRef()); EXPECT_EQ("foo::bar()", RMC.ParseFullName());
RMC.ParseFunctionBaseName();
EXPECT_EQ("bar", RMC.GetBufferRef());
RMC.ParseFullName();
EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
} }
TEST(RichManglingContextTest, FromCxxMethodName) { TEST(RichManglingContextTest, FromCxxMethodName) {
@ -41,19 +35,12 @@ TEST(RichManglingContextTest, FromCxxMethodName) {
ConstString demangled("foo::bar()"); ConstString demangled("foo::bar()");
EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(demangled)); EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(demangled));
EXPECT_TRUE(ItaniumRMC.IsCtorOrDtor() == CxxMethodRMC.IsCtorOrDtor()); EXPECT_EQ(ItaniumRMC.IsCtorOrDtor(), CxxMethodRMC.IsCtorOrDtor());
EXPECT_EQ(ItaniumRMC.ParseFunctionDeclContextName(),
ItaniumRMC.ParseFunctionDeclContextName(); CxxMethodRMC.ParseFunctionDeclContextName());
CxxMethodRMC.ParseFunctionDeclContextName(); EXPECT_EQ(ItaniumRMC.ParseFunctionBaseName(),
EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef()); CxxMethodRMC.ParseFunctionBaseName());
EXPECT_EQ(ItaniumRMC.ParseFullName(), CxxMethodRMC.ParseFullName());
ItaniumRMC.ParseFunctionBaseName();
CxxMethodRMC.ParseFunctionBaseName();
EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
ItaniumRMC.ParseFullName();
CxxMethodRMC.ParseFullName();
EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
// Construct with a random name. // Construct with a random name.
{ {
@ -68,8 +55,7 @@ TEST(RichManglingContextTest, FromCxxMethodName) {
ConstString("void * operator new(unsigned __int64)"))); ConstString("void * operator new(unsigned __int64)")));
// We expect its context is empty. // We expect its context is empty.
CxxMethodRMC.ParseFunctionDeclContextName(); EXPECT_TRUE(CxxMethodRMC.ParseFunctionDeclContextName().empty());
EXPECT_TRUE(CxxMethodRMC.GetBufferRef().empty());
} }
} }
@ -79,16 +65,13 @@ TEST(RichManglingContextTest, SwitchProvider) {
llvm::StringRef demangled = "foo::bar()"; llvm::StringRef demangled = "foo::bar()";
EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled))); EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
RMC.ParseFullName(); EXPECT_EQ("foo::bar()", RMC.ParseFullName());
EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
EXPECT_TRUE(RMC.FromCxxMethodName(ConstString(demangled))); EXPECT_TRUE(RMC.FromCxxMethodName(ConstString(demangled)));
RMC.ParseFullName(); EXPECT_EQ("foo::bar()", RMC.ParseFullName());
EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled))); EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
RMC.ParseFullName(); EXPECT_EQ("foo::bar()", RMC.ParseFullName());
EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
} }
TEST(RichManglingContextTest, IPDRealloc) { TEST(RichManglingContextTest, IPDRealloc) {
@ -116,13 +99,11 @@ TEST(RichManglingContextTest, IPDRealloc) {
// Demangle the short one. // Demangle the short one.
EXPECT_TRUE(RMC.FromItaniumName(ConstString(ShortMangled))); EXPECT_TRUE(RMC.FromItaniumName(ConstString(ShortMangled)));
RMC.ParseFullName(); const char *ShortDemangled = RMC.ParseFullName().data();
const char *ShortDemangled = RMC.GetBufferRef().data();
// Demangle the long one. // Demangle the long one.
EXPECT_TRUE(RMC.FromItaniumName(ConstString(LongMangled))); EXPECT_TRUE(RMC.FromItaniumName(ConstString(LongMangled)));
RMC.ParseFullName(); const char *LongDemangled = RMC.ParseFullName().data();
const char *LongDemangled = RMC.GetBufferRef().data();
// Make sure a new buffer was allocated or the default buffer was extended. // Make sure a new buffer was allocated or the default buffer was extended.
bool AllocatedNewBuffer = (ShortDemangled != LongDemangled); bool AllocatedNewBuffer = (ShortDemangled != LongDemangled);