text: //===-- RichManglingContext.cpp -------------------------------------------===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  
  #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
  RichManglingContext::~RichManglingContext() {
    std::free(m_ipd_buf);
    ResetCxxMethodParser();
  }
  
  void RichManglingContext::ResetCxxMethodParser() {
    // 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();
    }
  }
  
  void RichManglingContext::ResetProvider(InfoProvider new_provider) {
    ResetCxxMethodParser();
  
    assert(new_provider != None && "Only reset to a valid provider");
    m_provider = new_provider;
  }
  
  bool RichManglingContext::FromItaniumName(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(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;
    }
    llvm_unreachable("Fully covered switch above!");
  }
  
  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;
    }
    llvm_unreachable("Fully covered switch above!");
  }
  
  void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
    // Error case: Clear the buffer.
    if (LLVM_UNLIKELY(ipd_res == nullptr)) {
      assert(res_size == m_ipd_buf_size &&
             "Failed IPD queries keep the original size in the N parameter");
  
      m_ipd_buf[0] = '\0';
      m_buffer = llvm::StringRef(m_ipd_buf, 0);
      return;
    }
  
    // IPD's res_size includes null terminator.
    assert(ipd_res[res_size - 1] == '\0' &&
           "IPD returns null-terminated strings and we rely on that");
  
    // Update buffer/size on realloc.
    if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) {
      m_ipd_buf = ipd_res;       // std::realloc freed or reused the old buffer.
      m_ipd_buf_size = res_size; // May actually be bigger, but we can't know.
  
      if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE))
        LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}",
                 m_ipd_buf_size);
    }
  
    // 99% case: Just remember the string length.
    m_buffer = llvm::StringRef(m_ipd_buf, res_size - 1);
  }
  
  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;
    }
  }
  