sgraenitz updated this revision to Diff 159767.
sgraenitz marked 5 inline comments as done.
sgraenitz added a comment.

Addressed Jim's feedback


https://reviews.llvm.org/D50071

Files:
  include/lldb/Core/Mangled.h
  include/lldb/Core/RichManglingContext.h
  include/lldb/Symbol/Symtab.h
  include/lldb/lldb-forward.h
  lldb.xcodeproj/project.pbxproj
  source/Core/CMakeLists.txt
  source/Core/Mangled.cpp
  source/Core/RichManglingContext.cpp
  source/Symbol/Symtab.cpp
  unittests/Core/CMakeLists.txt
  unittests/Core/RichManglingContextTest.cpp

Index: unittests/Core/RichManglingContextTest.cpp
===================================================================
--- /dev/null
+++ unittests/Core/RichManglingContextTest.cpp
@@ -0,0 +1,114 @@
+//===-- RichManglingContextTest.cpp -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/RichManglingContext.h"
+
+#include "lldb/Utility/ConstString.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(RichManglingContextTest, Basic) {
+  RichManglingContext RMC;
+  ConstString mangled("_ZN3foo3barEv");
+  EXPECT_TRUE(RMC.FromItaniumName(mangled));
+
+  EXPECT_TRUE(RMC.IsFunction());
+  EXPECT_FALSE(RMC.IsCtorOrDtor());
+
+  RMC.ParseFunctionDeclContextName();
+  EXPECT_EQ("foo", RMC.GetBufferRef());
+
+  RMC.ParseFunctionBaseName();
+  EXPECT_EQ("bar", RMC.GetBufferRef());
+
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, FromCxxMethodName) {
+  RichManglingContext ItaniumRMC;
+  ConstString mangled("_ZN3foo3barEv");
+  EXPECT_TRUE(ItaniumRMC.FromItaniumName(mangled));
+
+  RichManglingContext CxxMethodRMC;
+  ConstString demangled("foo::bar()");
+  EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(demangled));
+
+  EXPECT_TRUE(ItaniumRMC.IsFunction() == CxxMethodRMC.IsFunction());
+  EXPECT_TRUE(ItaniumRMC.IsCtorOrDtor() == CxxMethodRMC.IsCtorOrDtor());
+
+  ItaniumRMC.ParseFunctionDeclContextName();
+  CxxMethodRMC.ParseFunctionDeclContextName();
+  EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+
+  ItaniumRMC.ParseFunctionBaseName();
+  CxxMethodRMC.ParseFunctionBaseName();
+  EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+
+  ItaniumRMC.ParseFullName();
+  CxxMethodRMC.ParseFullName();
+  EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, SwitchProvider) {
+  RichManglingContext RMC;
+  llvm::StringRef mangled = "_ZN3foo3barEv";
+  llvm::StringRef demangled = "foo::bar()";
+
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+
+  EXPECT_TRUE(RMC.FromCxxMethodName(ConstString(demangled)));
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
+  RMC.ParseFullName();
+  EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, IPDRealloc) {
+  // The demangled name should fit into the Itanium default buffer.
+  const char *short_mangled = "_ZN3foo3barEv";
+
+  // The demangled name for this will certainly not fit into the default buffer.
+  const char *long_mangled =
+      "_ZNK3shk6detail17CallbackPublisherIZNS_5ThrowERKNSt15__exception_"
+      "ptr13exception_ptrEEUlOT_E_E9SubscribeINS0_9ConcatMapINS0_"
+      "18CallbackSubscriberIZNS_6GetAllIiNS1_IZZNS_9ConcatMapIZNS_6ConcatIJNS1_"
+      "IZZNS_3MapIZZNS_7IfEmptyIS9_EEDaS7_ENKUlS6_E_clINS1_IZZNS_4TakeIiEESI_"
+      "S7_ENKUlS6_E_clINS1_IZZNS_6FilterIZNS_9ElementAtEmEUlS7_E_EESI_S7_"
+      "ENKUlS6_E_clINS1_IZZNSL_ImEESI_S7_ENKUlS6_E_clINS1_IZNS_4FromINS0_"
+      "22InfiniteRangeContainerIiEEEESI_S7_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_"
+      "EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_EUlS7_E_EESI_S7_ENKUlS6_E_clIS14_"
+      "EESI_S6_EUlS7_E_EERNS1_IZZNSH_IS9_EESI_S7_ENKSK_IS14_EESI_S6_EUlS7_E0_"
+      "EEEEESI_DpOT_EUlS7_E_EESI_S7_ENKUlS6_E_clINS1_IZNS_5StartIJZNS_"
+      "4JustIJS19_S1C_EEESI_S1F_EUlvE_ZNS1K_IJS19_S1C_EEESI_S1F_EUlvE0_EEESI_"
+      "S1F_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESt6vectorIS6_SaIS6_EERKT0_NS_"
+      "12ElementCountEbEUlS7_E_ZNSD_IiS1Q_EES1T_S1W_S1X_bEUlOS3_E_ZNSD_IiS1Q_"
+      "EES1T_S1W_S1X_bEUlvE_EES1G_S1O_E25ConcatMapValuesSubscriberEEEDaS7_";
+
+  RichManglingContext RMC;
+
+  // Demangle the short one and remember the buffer address.
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(short_mangled)));
+  RMC.ParseFullName();
+  const char *short_demangled_ptr = RMC.GetBufferRef().data();
+
+  // Demangle the long one and make sure the buffer address changed.
+  EXPECT_TRUE(RMC.FromItaniumName(ConstString(long_mangled)));
+  RMC.ParseFullName();
+  const char *long_demangled_ptr = RMC.GetBufferRef().data();
+
+  EXPECT_TRUE(short_demangled_ptr != long_demangled_ptr);
+}
Index: unittests/Core/CMakeLists.txt
===================================================================
--- unittests/Core/CMakeLists.txt
+++ unittests/Core/CMakeLists.txt
@@ -4,6 +4,7 @@
   EventTest.cpp
   ListenerTest.cpp
   MangledTest.cpp
+  RichManglingContextTest.cpp
   ScalarTest.cpp
   StateTest.cpp
   StreamCallbackTest.cpp
Index: source/Symbol/Symtab.cpp
===================================================================
--- source/Symbol/Symtab.cpp
+++ source/Symbol/Symtab.cpp
@@ -10,9 +10,10 @@
 #include <map>
 #include <set>
 
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
 #include "Plugins/Language/ObjC/ObjCLanguage.h"
+
 #include "lldb/Core/Module.h"
+#include "lldb/Core/RichManglingContext.h"
 #include "lldb/Core/STLUtils.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -23,6 +24,8 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
 
+#include "llvm/ADT/StringRef.h"
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -215,6 +218,39 @@
 //----------------------------------------------------------------------
 // InitNameIndexes
 //----------------------------------------------------------------------
+static bool lldb_skip_name(llvm::StringRef mangled,
+                           Mangled::ManglingScheme scheme) {
+  switch (scheme) {
+  case Mangled::eManglingSchemeItanium: {
+    if (mangled.size() < 3 || !mangled.startswith("_Z"))
+      return true;
+
+    // Avoid the following types of symbols in the index.
+    switch (mangled[2]) {
+    case 'G': // guard variables
+    case 'T': // virtual tables, VTT structures, typeinfo structures + names
+    case 'Z': // named local entities (if we eventually handle
+              // eSymbolTypeData, we will want this back)
+      return true;
+
+    default:
+      break;
+    }
+
+    // Include this name in the index.
+    return false;
+  }
+
+  // No filters for this scheme yet. Include all names in indexing.
+  case Mangled::eManglingSchemeMSVC:
+    return false;
+
+  // Don't try and demangle things we can't categorize.
+  case Mangled::eManglingSchemeNone:
+    return true;
+  }
+}
+
 void Symtab::InitNameIndexes() {
   // Protected function, no need to lock mutex...
   if (!m_name_indexes_computed) {
@@ -243,25 +279,30 @@
     m_name_to_index.Reserve(actual_count);
 #endif
 
-    NameToIndexMap::Entry entry;
-
-    // The "const char *" in "class_contexts" must come from a
-    // ConstString::GetCString()
+    // The "const char *" in "class_contexts" and backlog::value_type::second
+    // must come from a ConstString::GetCString()
     std::set<const char *> class_contexts;
-    UniqueCStringMap<uint32_t> mangled_name_to_index;
-    std::vector<const char *> symbol_contexts(num_symbols, nullptr);
+    std::vector<std::pair<NameToIndexMap::Entry, const char *>> backlog;
+    backlog.reserve(num_symbols / 2);
+
+    // Instantiation of the demangler is expensive, so better use a single one
+    // for all entries during batch processing.
+    RichManglingContext rmc;
+    NameToIndexMap::Entry entry;
 
     for (entry.value = 0; entry.value < num_symbols; ++entry.value) {
-      const Symbol *symbol = &m_symbols[entry.value];
+      Symbol *symbol = &m_symbols[entry.value];
 
       // Don't let trampolines get into the lookup by name map If we ever need
       // the trampoline symbols to be searchable by name we can remove this and
       // then possibly add a new bool to any of the Symtab functions that
       // lookup symbols by name to indicate if they want trampolines.
       if (symbol->IsTrampoline())
         continue;
 
-      const Mangled &mangled = symbol->GetMangled();
+      // If the symbol's name string matched a Mangled::ManglingScheme, it is
+      // stored in the mangled field.
+      Mangled &mangled = symbol->GetMangled();
       entry.cstring = mangled.GetMangledName();
       if (entry.cstring) {
         m_name_to_index.Append(entry);
@@ -274,70 +315,15 @@
           m_name_to_index.Append(entry);
         }
 
-        const SymbolType symbol_type = symbol->GetType();
-        if (symbol_type == eSymbolTypeCode ||
-            symbol_type == eSymbolTypeResolver) {
-          llvm::StringRef entry_ref(entry.cstring.GetStringRef());
-          if (entry_ref[0] == '_' && entry_ref[1] == 'Z' &&
-              (entry_ref[2] != 'T' && // avoid virtual table, VTT structure,
-                                      // typeinfo structure, and typeinfo
-                                      // name
-               entry_ref[2] != 'G' && // avoid guard variables
-               entry_ref[2] != 'Z'))  // named local entities (if we
-                                          // eventually handle eSymbolTypeData,
-                                          // we will want this back)
-          {
-            CPlusPlusLanguage::MethodName cxx_method(
-                mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus));
-            entry.cstring = ConstString(cxx_method.GetBasename());
-            if (entry.cstring) {
-              // ConstString objects permanently store the string in the pool
-              // so calling GetCString() on the value gets us a const char *
-              // that will never go away
-              const char *const_context =
-                  ConstString(cxx_method.GetContext()).GetCString();
-
-              if (!const_context || const_context[0] == 0) {
-                // No context for this function so this has to be a basename
-                m_basename_to_index.Append(entry);
-                // If there is no context (no namespaces or class scopes that
-                // come before the function name) then this also could be a
-                // fullname.
-                m_name_to_index.Append(entry);
-              } else {
-                entry_ref = entry.cstring.GetStringRef();
-                if (entry_ref[0] == '~' ||
-                    !cxx_method.GetQualifiers().empty()) {
-                  // The first character of the demangled basename is '~' which
-                  // means we have a class destructor. We can use this
-                  // information to help us know what is a class and what
-                  // isn't.
-                  if (class_contexts.find(const_context) == class_contexts.end())
-                    class_contexts.insert(const_context);
-                  m_method_to_index.Append(entry);
-                } else {
-                  if (class_contexts.find(const_context) !=
-                      class_contexts.end()) {
-                    // The current decl context is in our "class_contexts"
-                    // which means this is a method on a class
-                    m_method_to_index.Append(entry);
-                  } else {
-                    // We don't know if this is a function basename or a
-                    // method, so put it into a temporary collection so once we
-                    // are done we can look in class_contexts to see if each
-                    // entry is a class or just a function and will put any
-                    // remaining items into m_method_to_index or
-                    // m_basename_to_index as needed
-                    mangled_name_to_index.Append(entry);
-                    symbol_contexts[entry.value] = const_context;
-                  }
-                }
-              }
-            }
-          }
+        const SymbolType type = symbol->GetType();
+        if (type == eSymbolTypeCode || type == eSymbolTypeResolver) {
+          if (mangled.DemangleWithRichManglingInfo(rmc, lldb_skip_name))
+            RegisterMangledNameEntry(entry, class_contexts, backlog, rmc);
         }
       }
 
+      // Symbol name strings that didn't match a Mangled::ManglingScheme, are
+      // stored in the demangled field.
       entry.cstring = mangled.GetDemangledName(symbol->GetLanguage());
       if (entry.cstring) {
         m_name_to_index.Append(entry);
@@ -367,25 +353,10 @@
       }
     }
 
-    size_t count;
-    if (!mangled_name_to_index.IsEmpty()) {
-      count = mangled_name_to_index.GetSize();
-      for (size_t i = 0; i < count; ++i) {
-        if (mangled_name_to_index.GetValueAtIndex(i, entry.value)) {
-          entry.cstring = mangled_name_to_index.GetCStringAtIndex(i);
-          if (symbol_contexts[entry.value] &&
-              class_contexts.find(symbol_contexts[entry.value]) !=
-                  class_contexts.end()) {
-            m_method_to_index.Append(entry);
-          } else {
-            // If we got here, we have something that had a context (was inside
-            // a namespace or class) yet we don't know if the entry
-            m_method_to_index.Append(entry);
-            m_basename_to_index.Append(entry);
-          }
-        }
-      }
+    for (const auto &record : backlog) {
+      RegisterBacklogEntry(record.first, record.second, class_contexts);
     }
+
     m_name_to_index.Sort();
     m_name_to_index.SizeToFit();
     m_selector_to_index.Sort();
@@ -397,6 +368,71 @@
   }
 }
 
+void Symtab::RegisterMangledNameEntry(
+    NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+    std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
+    RichManglingContext &rmc) {
+  // Only register functions that have a base name.
+  rmc.ParseFunctionBaseName();
+  llvm::StringRef base_name = rmc.GetBufferRef();
+  if (base_name.empty())
+    return;
+
+  // The base name will be our entry's name.
+  entry.cstring = ConstString(base_name);
+
+  rmc.ParseFunctionDeclContextName();
+  llvm::StringRef decl_context = rmc.GetBufferRef();
+
+  // Register functions with no context.
+  if (decl_context.empty()) {
+    // This has to be a basename
+    m_basename_to_index.Append(entry);
+    // If there is no context (no namespaces or class scopes that come before
+    // the function name) then this also could be a fullname.
+    m_name_to_index.Append(entry);
+    return;
+  }
+
+  // Make sure we have a pool-string pointer and see if we already know the
+  // context name.
+  const char *decl_context_ccstr = ConstString(decl_context).GetCString();
+  auto it = class_contexts.find(decl_context_ccstr);
+
+  // Register constructors and destructors. They are methods and create
+  // declaration contexts.
+  if (rmc.IsCtorOrDtor()) {
+    m_method_to_index.Append(entry);
+    if (it == class_contexts.end())
+      class_contexts.insert(it, decl_context_ccstr);
+    return;
+  }
+
+  // Register regular methods with a known declaration context.
+  if (it != class_contexts.end()) {
+    m_method_to_index.Append(entry);
+    return;
+  }
+
+  // Regular methods in unknown declaration contexts are put to the backlog. We
+  // will revisit them once we processed all remaining symbols.
+  backlog.push_back(std::make_pair(entry, decl_context_ccstr));
+}
+
+void Symtab::RegisterBacklogEntry(
+    const NameToIndexMap::Entry &entry, const char *decl_context,
+    const std::set<const char *> &class_contexts) {
+  auto it = class_contexts.find(decl_context);
+  if (it != class_contexts.end()) {
+    m_method_to_index.Append(entry);
+  } else {
+    // If we got here, we have something that had a context (was inside
+    // a namespace or class) yet we don't know the entry
+    m_method_to_index.Append(entry);
+    m_basename_to_index.Append(entry);
+  }
+}
+
 void Symtab::PreloadSymbols() {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   InitNameIndexes();
Index: source/Core/RichManglingContext.cpp
===================================================================
--- /dev/null
+++ source/Core/RichManglingContext.cpp
@@ -0,0 +1,178 @@
+//===-- RichManglingContext.cpp ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/RichManglingContext.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RichManglingContext
+//----------------------------------------------------------------------
+void RichManglingContext::ResetProvider(InfoProvider new_provider) {
+  // If we want to support parsers for other languages some day, we need a
+  // switch here to delete the correct parser type.
+  if (m_cxx_method_parser.hasValue()) {
+    assert(m_provider == PluginCxxLanguage);
+    delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
+    m_cxx_method_parser.reset();
+  }
+
+  assert(new_provider != None && "Only reset to a valid provider");
+  m_provider = new_provider;
+}
+
+bool RichManglingContext::FromItaniumName(const ConstString &mangled) {
+  bool err = m_ipd.partialDemangle(mangled.GetCString());
+  if (!err) {
+    ResetProvider(ItaniumPartialDemangler);
+  }
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (!err) {
+      ParseFullName();
+      LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
+    } else {
+      LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
+               mangled);
+    }
+  }
+
+  return !err; // true == success
+}
+
+bool RichManglingContext::FromCxxMethodName(const ConstString &demangled) {
+  ResetProvider(PluginCxxLanguage);
+  m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
+  return true;
+}
+
+bool RichManglingContext::IsCtorOrDtor() const {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_ipd.isCtorOrDtor();
+  case PluginCxxLanguage: {
+    // We can only check for destructors here.
+    auto base_name =
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
+    return base_name.startswith("~");
+  }
+  case None:
+    return false;
+  }
+}
+
+bool RichManglingContext::IsFunction() const {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler:
+    return m_ipd.isFunction();
+  case PluginCxxLanguage:
+    return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->IsValid();
+  case None:
+    return false;
+  }
+}
+
+void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
+  if (LLVM_UNLIKELY(ipd_res == nullptr)) {
+    assert(res_size == m_ipd_buf_size &&
+           "Failed IPD queries keep the original size in the N parameter");
+
+    // Error case: Clear the buffer.
+    m_ipd_str_len = 0;
+    m_ipd_buf[m_ipd_str_len] = '\0';
+  } else {
+    // IPD's res_size includes null terminator.
+    size_t res_len = res_size - 1;
+    assert(ipd_res[res_len] == '\0' &&
+           "IPD returns null-terminated strings and we rely on that");
+
+    if (LLVM_UNLIKELY(ipd_res != m_ipd_buf)) {
+      // Realloc case: Take over the new buffer.
+      m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer.
+      m_ipd_buf_size =
+          res_size; // Actual buffer may be bigger, but we can't know.
+      m_ipd_str_len = res_len;
+
+      Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
+      if (log)
+        log->Printf("ItaniumPartialDemangler Realloc: new buffer size %lu",
+                    m_ipd_buf_size);
+    } else {
+      // 99% case: Just remember the string length.
+      m_ipd_str_len = res_len;
+    }
+  }
+
+  m_buffer = llvm::StringRef(m_ipd_buf, m_ipd_str_len);
+}
+
+void RichManglingContext::ParseFunctionBaseName() {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto n = m_ipd_buf_size;
+    auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
+    processIPDStrResult(buf, n);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_buffer =
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
+    return;
+  case None:
+    return;
+  }
+}
+
+void RichManglingContext::ParseFunctionDeclContextName() {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto n = m_ipd_buf_size;
+    auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
+    processIPDStrResult(buf, n);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_buffer =
+        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext();
+    return;
+  case None:
+    return;
+  }
+}
+
+void RichManglingContext::ParseFullName() {
+  assert(m_provider != None && "Initialize a provider first");
+  switch (m_provider) {
+  case ItaniumPartialDemangler: {
+    auto n = m_ipd_buf_size;
+    auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
+    processIPDStrResult(buf, n);
+    return;
+  }
+  case PluginCxxLanguage:
+    m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
+                   ->GetFullName()
+                   .GetStringRef();
+    return;
+  case None:
+    return;
+  }
+}
Index: source/Core/Mangled.cpp
===================================================================
--- source/Core/Mangled.cpp
+++ source/Core/Mangled.cpp
@@ -16,6 +16,7 @@
 #pragma comment(lib, "dbghelp.lib")
 #endif
 
+#include "lldb/Core/RichManglingContext.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Logging.h"
@@ -232,6 +233,128 @@
   }
 }
 
+//----------------------------------------------------------------------
+// Local helpers for different demangling implementations.
+//----------------------------------------------------------------------
+static char *GetMSVCDemangledStr(const char *M) {
+#if defined(_MSC_VER)
+  const size_t demangled_length = 2048;
+  char *demangled_cstr = static_cast<char *>(::malloc(demangled_length));
+  ::ZeroMemory(demangled_cstr, demangled_length);
+  DWORD result = safeUndecorateName(M, demangled_cstr, demangled_length);
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (demangled_cstr && demangled_cstr[0])
+      log->Printf("demangled msvc: %s -> \"%s\"", M, demangled_cstr);
+    else
+      log->Printf("demangled msvc: %s -> error: 0x%lu", M, result);
+  }
+
+  if (result != 0) {
+    return demangled_cstr;
+  } else {
+    ::free(demangled_cstr);
+    return nullptr;
+  }
+#else
+  return nullptr;
+#endif
+}
+
+static char *GetItaniumDemangledStr(const char *M,
+                                    llvm::ItaniumPartialDemangler &ipd) {
+  char *demangled_cstr = nullptr;
+  bool err = ipd.partialDemangle(M);
+  if (!err) {
+    // Default buffer and size (will realloc in case it's too small).
+    size_t demangled_size = 80;
+    demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
+    demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size);
+
+    assert(demangled_cstr &&
+           "finishDemangle must always succeed if partialDemangle did");
+    assert(demangled_cstr[demangled_size - 1] == '\0' &&
+           "Expected demangled_size to return length including trailing null");
+  }
+
+  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+    if (demangled_cstr)
+      log->Printf("demangled itanium: %s -> \"%s\"", M, demangled_cstr);
+    else
+      log->Printf("demangled itanium: %s -> error: failed to demangle", M);
+  }
+
+  return demangled_cstr;
+}
+
+//----------------------------------------------------------------------
+// Explicit demangling for scheduled requests during batch processing. This
+// makes use of ItaniumPartialDemangler's rich demangle info
+//----------------------------------------------------------------------
+bool Mangled::DemangleWithRichManglingInfo(
+    RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) {
+  // We need to generate and cache the demangled name.
+  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+  Timer scoped_timer(func_cat,
+                     "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)",
+                     m_mangled.GetCString());
+
+  // Others are not meant to arrive here. ObjC names or C's main() for example
+  // have their names stored in m_demangled, while m_mangled is empty.
+  assert(m_mangled);
+
+  // Check whether or not we are interested in this name at all.
+  ManglingScheme scheme = cstring_mangling_scheme(m_mangled.GetCString());
+  if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme))
+    return false;
+
+  switch (scheme) {
+  case eManglingSchemeNone:
+    // The current mangled_name_filter would allow llvm_unreachable here.
+    return false;
+
+  case eManglingSchemeItanium:
+    // We want the rich mangling info here, so we don't care whether or not
+    // there is a demangled string in the pool already.
+    if (context.FromItaniumName(m_mangled)) {
+      // If we got an info, we have a name. Copy to string pool and connect the
+      // counterparts to accelerate later access in GetDemangledName().
+      context.ParseFullName();
+      m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(),
+                                                  m_mangled);
+      return true;
+    } else {
+      m_demangled.SetCString("");
+      return false;
+    }
+
+  case eManglingSchemeMSVC: {
+    // We have no rich mangling for MSVC-mangled names yet, so first try to
+    // demangle it if necessary.
+    if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {
+      if (char *d = GetMSVCDemangledStr(m_mangled.GetCString())) {
+        // If we got an info, we have a name. Copy to string pool and connect
+        // the counterparts to accelerate later access in GetDemangledName().
+        m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(d),
+                                                    m_mangled);
+        ::free(d);
+      } else {
+        m_demangled.SetCString("");
+      }
+    }
+
+    if (m_demangled.IsEmpty()) {
+      // Cannot demangle it, so don't try parsing.
+      return false;
+    } else {
+      // Demangled successfully, we can try and parse it with
+      // CPlusPlusLanguage::MethodName.
+      return context.FromCxxMethodName(m_demangled);
+    }
+  }
+  }
+}
+
 //----------------------------------------------------------------------
 // Generate the demangled name on demand using this accessor. Code in this
 // class will need to use this accessor if it wishes to decode the demangled
@@ -248,8 +371,6 @@
     Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
                        m_mangled.GetCString());
 
-    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
-
     // Don't bother running anything that isn't mangled
     const char *mangled_name = m_mangled.GetCString();
     ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
@@ -259,56 +380,20 @@
       // add it to our map.
       char *demangled_name = nullptr;
       switch (mangling_scheme) {
-      case eManglingSchemeMSVC: {
-#if defined(_MSC_VER)
-        if (log)
-          log->Printf("demangle msvc: %s", mangled_name);
-        const size_t demangled_length = 2048;
-        demangled_name = static_cast<char *>(::malloc(demangled_length));
-        ::ZeroMemory(demangled_name, demangled_length);
-        DWORD result =
-            safeUndecorateName(mangled_name, demangled_name, demangled_length);
-        if (log) {
-          if (demangled_name && demangled_name[0])
-            log->Printf("demangled msvc: %s -> \"%s\"", mangled_name,
-                        demangled_name);
-          else
-            log->Printf("demangled msvc: %s -> error: 0x%lu", mangled_name,
-                        result);
-        }
-
-        if (result == 0) {
-          free(demangled_name);
-          demangled_name = nullptr;
-        }
-#endif
+      case eManglingSchemeMSVC:
+        demangled_name = GetMSVCDemangledStr(mangled_name);
         break;
-      }
       case eManglingSchemeItanium: {
-        llvm::ItaniumPartialDemangler IPD;
-        bool demangle_err = IPD.partialDemangle(mangled_name);
-        if (!demangle_err) {
-          // Default buffer and size (realloc is used in case it's too small).
-          size_t demangled_size = 80;
-          demangled_name = static_cast<char *>(::malloc(demangled_size));
-          demangled_name = IPD.finishDemangle(demangled_name, &demangled_size);
-        }
-
-        if (log) {
-          if (demangled_name)
-            log->Printf("demangled itanium: %s -> \"%s\"", mangled_name,
-                        demangled_name);
-          else
-            log->Printf("demangled itanium: %s -> error: failed to demangle",
-                        mangled_name);
-        }
+        llvm::ItaniumPartialDemangler ipd;
+        demangled_name = GetItaniumDemangledStr(mangled_name, ipd);
         break;
       }
       case eManglingSchemeNone:
-        break;
+        llvm_unreachable("eManglingSchemeNone was handled already");
       }
       if (demangled_name) {
-        m_demangled.SetStringWithMangledCounterpart(demangled_name, m_mangled);
+        m_demangled.SetStringWithMangledCounterpart(
+            llvm::StringRef(demangled_name), m_mangled);
         free(demangled_name);
       }
     }
Index: source/Core/CMakeLists.txt
===================================================================
--- source/Core/CMakeLists.txt
+++ source/Core/CMakeLists.txt
@@ -35,6 +35,7 @@
   Opcode.cpp
   PluginManager.cpp
   RegisterValue.cpp
+  RichManglingContext.cpp
   Scalar.cpp
   SearchFilter.cpp
   Section.cpp
Index: lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb.xcodeproj/project.pbxproj
+++ lldb.xcodeproj/project.pbxproj
@@ -489,6 +489,9 @@
 		8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; };
 		2689004313353E0400698AC0 /* Mangled.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8010F1B85900F91463 /* Mangled.cpp */; };
 		4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4F29D3CD21010F84003B549A /* MangledTest.cpp */; };
+		4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FBC04EE211A06820015A814 /* RichManglingContext.h */; };
+		4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */; };
+		4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */; };
 		4CD44CFC20B37C440003557C /* ManualDWARFIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */; };
 		49DCF702170E70120092F75E /* Materializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF700170E70120092F75E /* Materializer.cpp */; };
 		2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2690B3701381D5C300ECFBAE /* Memory.cpp */; };
@@ -2196,6 +2199,9 @@
 		26BC7E8010F1B85900F91463 /* Mangled.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mangled.cpp; path = source/Core/Mangled.cpp; sourceTree = "<group>"; };
 		26BC7D6910F1B77400F91463 /* Mangled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mangled.h; path = include/lldb/Core/Mangled.h; sourceTree = "<group>"; };
 		4F29D3CD21010F84003B549A /* MangledTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MangledTest.cpp; sourceTree = "<group>"; };
+		4FBC04EE211A06820015A814 /* RichManglingContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RichManglingContext.h; path = include/lldb/Core/RichManglingContext.h; sourceTree = "<group>"; };
+		4FBC04EC211A06200015A814 /* RichManglingContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RichManglingContext.cpp; path = source/Core/RichManglingContext.cpp; sourceTree = "<group>"; };
+		4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RichManglingContextTest.cpp; sourceTree = "<group>"; };
 		4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ManualDWARFIndex.cpp; sourceTree = "<group>"; };
 		4CD44D0020B37C580003557C /* ManualDWARFIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ManualDWARFIndex.h; sourceTree = "<group>"; };
 		2682100C143A59AE004BCF2D /* MappedHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MappedHash.h; path = include/lldb/Core/MappedHash.h; sourceTree = "<group>"; };
@@ -3668,15 +3674,16 @@
 		23CB14E51D66CBEB00EDDDE1 /* Core */ = {
 			isa = PBXGroup;
 			children = (
+				23CB14E61D66CC0E00EDDDE1 /* BroadcasterTest.cpp */,
+				23CB14E71D66CC0E00EDDDE1 /* CMakeLists.txt */,
+				23CB14E81D66CC0E00EDDDE1 /* DataExtractorTest.cpp */,
 				58A080B12112AB2200D5580F /* HighlighterTest.cpp */,
-				4F29D3CD21010F84003B549A /* MangledTest.cpp */,
 				9A3D43E31F3237D500EB767C /* ListenerTest.cpp */,
+				4F29D3CD21010F84003B549A /* MangledTest.cpp */,
+				4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */,
+				23CB14E91D66CC0E00EDDDE1 /* ScalarTest.cpp */,
 				9A3D43E21F3237D500EB767C /* StateTest.cpp */,
 				9A3D43E11F3237D500EB767C /* StreamCallbackTest.cpp */,
-				23CB14E71D66CC0E00EDDDE1 /* CMakeLists.txt */,
-				23CB14E61D66CC0E00EDDDE1 /* BroadcasterTest.cpp */,
-				23CB14E81D66CC0E00EDDDE1 /* DataExtractorTest.cpp */,
-				23CB14E91D66CC0E00EDDDE1 /* ScalarTest.cpp */,
 			);
 			path = Core;
 			sourceTree = "<group>";
@@ -5033,6 +5040,8 @@
 				2626B6AD143E1BEA00EF935C /* RangeMap.h */,
 				26C6886D137880B900407EDF /* RegisterValue.h */,
 				26C6886E137880C400407EDF /* RegisterValue.cpp */,
+				4FBC04EE211A06820015A814 /* RichManglingContext.h */,
+				4FBC04EC211A06200015A814 /* RichManglingContext.cpp */,
 				26BC7D7410F1B77400F91463 /* Scalar.h */,
 				26BC7E8D10F1B85900F91463 /* Scalar.cpp */,
 				26BC7CF910F1B71400F91463 /* SearchFilter.h */,
@@ -6943,6 +6952,7 @@
 				267F68541CC02E920086832B /* RegisterContextLinux_s390x.h in Headers */,
 				AF235EB11FBE77B6009C5541 /* RegisterContextPOSIX_ppc64le.h in Headers */,
 				267F68501CC02E270086832B /* RegisterContextPOSIXCore_s390x.h in Headers */,
+				4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */,
 				4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */,
 				26C7C4841BFFEA7E009BD01F /* WindowsMiniDump.h in Headers */,
 				30B38A001CAAA6D7009524E3 /* ClangUtil.h in Headers */,
@@ -7461,6 +7471,7 @@
 				9A2057181F3B861400F6C293 /* TestType.cpp in Sources */,
 				9A2057171F3B861400F6C293 /* TestDWARFCallFrameInfo.cpp in Sources */,
 				4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */,
+				4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */,
 				9A3D43EC1F3237F900EB767C /* ListenerTest.cpp in Sources */,
 				9A3D43DC1F3151C400EB767C /* TimeoutTest.cpp in Sources */,
 				9A3D43D61F3151C400EB767C /* ConstStringTest.cpp in Sources */,
@@ -7578,6 +7589,7 @@
 				4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */,
 				AF415AE71D949E4400FCE0D4 /* x86AssemblyInspectionEngine.cpp in Sources */,
 				26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */,
+				4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */,
 				AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */,
 				2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */,
 				267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */,
Index: include/lldb/lldb-forward.h
===================================================================
--- include/lldb/lldb-forward.h
+++ include/lldb/lldb-forward.h
@@ -191,6 +191,7 @@
 class RegisterValue;
 class RegularExpression;
 class REPL;
+class RichManglingContext;
 class Scalar;
 class ScriptInterpreter;
 class ScriptInterpreterLocker;
@@ -492,5 +493,15 @@
 
 } // namespace lldb
 
+//----------------------------------------------------------------------
+// llvm forward declarations
+//----------------------------------------------------------------------
+namespace llvm {
+
+struct ItaniumPartialDemangler;
+class StringRef;
+
+} // namespace llvm
+
 #endif // #if defined(__cplusplus)
 #endif // LLDB_lldb_forward_h_
Index: include/lldb/Symbol/Symtab.h
===================================================================
--- include/lldb/Symbol/Symtab.h
+++ include/lldb/Symbol/Symtab.h
@@ -197,6 +197,15 @@
   void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes,
                                         SymbolContextList &sc_list);
 
+  void RegisterMangledNameEntry(
+      NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+      std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
+      RichManglingContext &rmc);
+
+  void RegisterBacklogEntry(const NameToIndexMap::Entry &entry,
+                            const char *decl_context,
+                            const std::set<const char *> &class_contexts);
+
   DISALLOW_COPY_AND_ASSIGN(Symtab);
 };
 
Index: include/lldb/Core/RichManglingContext.h
===================================================================
--- /dev/null
+++ include/lldb/Core/RichManglingContext.h
@@ -0,0 +1,110 @@
+//===-- RichManglingContext.h -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RichManglingContext_h_
+#define liblldb_RichManglingContext_h_
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+
+#include "lldb/Utility/ConstString.h"
+
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Demangle/Demangle.h"
+
+namespace lldb_private {
+
+/// Uniform wrapper for access to rich mangling information from different
+/// providers. See Mangled::DemangleWithRichManglingInfo()
+class RichManglingContext {
+public:
+  RichManglingContext()
+      : m_provider(None), m_ipd_buf_size(2048), m_ipd_str_len(0) {
+    m_ipd_buf = static_cast<char *>(std::malloc(m_ipd_buf_size));
+    m_ipd_buf[m_ipd_str_len] = '\0';
+  }
+
+  ~RichManglingContext() { std::free(m_ipd_buf); }
+
+  /// Use the ItaniumPartialDemangler to obtain rich mangling information from
+  /// the given mangled name.
+  bool FromItaniumName(const ConstString &mangled);
+
+  /// Use the legacy language parser implementation to obtain rich mangling
+  /// information from the given demangled name.
+  bool FromCxxMethodName(const ConstString &demangled);
+
+  /// If this symbol describes a constructor or destructor.
+  bool IsCtorOrDtor() const;
+
+  /// If this symbol describes a function.
+  bool IsFunction() const;
+
+  /// 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
+  /// internal buffer. It can be obtained via GetBufferRef().
+  void ParseFunctionBaseName();
+
+  /// 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
+  /// via GetBufferRef().
+  void ParseFunctionDeclContextName();
+
+  /// Get the entire demangled name. The result will overwrite the internal
+  /// buffer. It can be obtained via GetBufferRef().
+  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:
+  enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage };
+
+  /// Selects the rich mangling info provider.
+  InfoProvider m_provider;
+
+  /// Reference to the buffer used for results of ParseXy() operations.
+  llvm::StringRef m_buffer;
+
+  /// Members for ItaniumPartialDemangler
+  llvm::ItaniumPartialDemangler m_ipd;
+  char *m_ipd_buf;
+  size_t m_ipd_buf_size;
+  size_t m_ipd_str_len;
+
+  /// Members for PluginCxxLanguage
+  /// Cannot forward declare inner class CPlusPlusLanguage::MethodName. The
+  /// respective header is in Plugins and including it from here causes cyclic
+  /// dependency. Instead keep a llvm::Any and cast it on-access in the cpp.
+  llvm::Any m_cxx_method_parser;
+
+  /// Clean up memory and set a new info provider for this instance.
+  void ResetProvider(InfoProvider new_provider);
+
+  /// Uniform handling of string buffers for ItaniumPartialDemangler.
+  void processIPDStrResult(char *ipd_res, size_t res_len);
+
+  /// 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
+  /// can't access CPlusPlusLanguage::MethodName from within the header.
+  template <class ParserT> static ParserT *get(llvm::Any parser) {
+    assert(parser.hasValue());
+    assert(llvm::any_isa<ParserT *>(parser));
+    return llvm::any_cast<ParserT *>(parser);
+  }
+};
+
+} // namespace lldb_private
+
+#endif
Index: include/lldb/Core/Mangled.h
===================================================================
--- include/lldb/Core/Mangled.h
+++ include/lldb/Core/Mangled.h
@@ -11,18 +11,15 @@
 #define liblldb_Mangled_h_
 #if defined(__cplusplus)
 
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
 #include "lldb/Utility/ConstString.h"
-#include "lldb/lldb-enumerations.h" // for LanguageType
-#include "llvm/ADT/StringRef.h"     // for StringRef
 
-#include <stddef.h> // for size_t
+#include "llvm/ADT/StringRef.h"
 
-namespace lldb_private {
-class RegularExpression;
-}
-namespace lldb_private {
-class Stream;
-}
+#include <memory>
+#include <stddef.h>
 
 namespace lldb_private {
 
@@ -238,7 +235,6 @@
       return true;
     return GetDemangledName(language) == name;
   }
-
   bool NameMatches(const RegularExpression &regex,
                    lldb::LanguageType language) const;
 
@@ -300,6 +296,36 @@
   //----------------------------------------------------------------------
   lldb::LanguageType GuessLanguage() const;
 
+  /// Function signature for filtering mangled names.
+  using SkipMangledNameFn = bool(llvm::StringRef, ManglingScheme);
+
+  //----------------------------------------------------------------------
+  /// Trigger explicit demangling to obtain rich mangling information. This is
+  /// optimized for batch processing while populating a name index. To get the
+  /// pure demangled name string for a single entity, use GetDemangledName()
+  /// instead.
+  ///
+  /// For names that match the Itanium mangling scheme, this uses LLVM's
+  /// ItaniumPartialDemangler. All other names fall back to LLDB's builtin
+  /// parser currently.
+  ///
+  /// This function is thread-safe when used with different \a context
+  /// instances in different threads.
+  ///
+  /// @param[in] context
+  ///     The context for this function. A single instance can be stack-
+  ///     allocated in the caller's frame and used for multiple calls.
+  ///
+  /// @param[in] skip_mangled_name
+  ///     A filtering function for skipping entities based on name and mangling
+  ///     scheme. This can be null if unused.
+  ///
+  /// @return
+  ///     True on success, false otherwise.
+  //----------------------------------------------------------------------
+  bool DemangleWithRichManglingInfo(RichManglingContext &context,
+                                    SkipMangledNameFn *skip_mangled_name);
+
 private:
   //----------------------------------------------------------------------
   /// Mangled member variables.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to