1343181Sdim//===-- RichManglingContext.cpp ---------------------------------*- C++ -*-===//
2343181Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6343181Sdim//
7343181Sdim//===----------------------------------------------------------------------===//
8343181Sdim
9343181Sdim#include "lldb/Core/RichManglingContext.h"
10343181Sdim
11343181Sdim#include "lldb/Utility/Log.h"
12343181Sdim#include "lldb/Utility/Logging.h"
13343181Sdim
14343181Sdim#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
15343181Sdim
16343181Sdim#include "llvm/ADT/StringRef.h"
17343181Sdim
18343181Sdimusing namespace lldb;
19343181Sdimusing namespace lldb_private;
20343181Sdim
21343181Sdim// RichManglingContext
22343181Sdimvoid RichManglingContext::ResetProvider(InfoProvider new_provider) {
23343181Sdim  // If we want to support parsers for other languages some day, we need a
24343181Sdim  // switch here to delete the correct parser type.
25343181Sdim  if (m_cxx_method_parser.hasValue()) {
26343181Sdim    assert(m_provider == PluginCxxLanguage);
27343181Sdim    delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
28343181Sdim    m_cxx_method_parser.reset();
29343181Sdim  }
30343181Sdim
31343181Sdim  assert(new_provider != None && "Only reset to a valid provider");
32343181Sdim  m_provider = new_provider;
33343181Sdim}
34343181Sdim
35353358Sdimbool RichManglingContext::FromItaniumName(ConstString mangled) {
36343181Sdim  bool err = m_ipd.partialDemangle(mangled.GetCString());
37343181Sdim  if (!err) {
38343181Sdim    ResetProvider(ItaniumPartialDemangler);
39343181Sdim  }
40343181Sdim
41343181Sdim  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
42343181Sdim    if (!err) {
43343181Sdim      ParseFullName();
44343181Sdim      LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
45343181Sdim    } else {
46343181Sdim      LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
47343181Sdim               mangled);
48343181Sdim    }
49343181Sdim  }
50343181Sdim
51343181Sdim  return !err; // true == success
52343181Sdim}
53343181Sdim
54353358Sdimbool RichManglingContext::FromCxxMethodName(ConstString demangled) {
55343181Sdim  ResetProvider(PluginCxxLanguage);
56343181Sdim  m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
57343181Sdim  return true;
58343181Sdim}
59343181Sdim
60343181Sdimbool RichManglingContext::IsCtorOrDtor() const {
61343181Sdim  assert(m_provider != None && "Initialize a provider first");
62343181Sdim  switch (m_provider) {
63343181Sdim  case ItaniumPartialDemangler:
64343181Sdim    return m_ipd.isCtorOrDtor();
65343181Sdim  case PluginCxxLanguage: {
66343181Sdim    // We can only check for destructors here.
67343181Sdim    auto base_name =
68343181Sdim        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
69343181Sdim    return base_name.startswith("~");
70343181Sdim  }
71343181Sdim  case None:
72343181Sdim    return false;
73343181Sdim  }
74343181Sdim  llvm_unreachable("Fully covered switch above!");
75343181Sdim}
76343181Sdim
77343181Sdimbool RichManglingContext::IsFunction() const {
78343181Sdim  assert(m_provider != None && "Initialize a provider first");
79343181Sdim  switch (m_provider) {
80343181Sdim  case ItaniumPartialDemangler:
81343181Sdim    return m_ipd.isFunction();
82343181Sdim  case PluginCxxLanguage:
83343181Sdim    return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->IsValid();
84343181Sdim  case None:
85343181Sdim    return false;
86343181Sdim  }
87343181Sdim  llvm_unreachable("Fully covered switch above!");
88343181Sdim}
89343181Sdim
90343181Sdimvoid RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
91343181Sdim  // Error case: Clear the buffer.
92343181Sdim  if (LLVM_UNLIKELY(ipd_res == nullptr)) {
93343181Sdim    assert(res_size == m_ipd_buf_size &&
94343181Sdim           "Failed IPD queries keep the original size in the N parameter");
95343181Sdim
96343181Sdim    m_ipd_buf[0] = '\0';
97343181Sdim    m_buffer = llvm::StringRef(m_ipd_buf, 0);
98343181Sdim    return;
99343181Sdim  }
100343181Sdim
101343181Sdim  // IPD's res_size includes null terminator.
102343181Sdim  assert(ipd_res[res_size - 1] == '\0' &&
103343181Sdim         "IPD returns null-terminated strings and we rely on that");
104343181Sdim
105343181Sdim  // Update buffer/size on realloc.
106343181Sdim  if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) {
107343181Sdim    m_ipd_buf = ipd_res;       // std::realloc freed or reused the old buffer.
108343181Sdim    m_ipd_buf_size = res_size; // May actually be bigger, but we can't know.
109343181Sdim
110343181Sdim    if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE))
111343181Sdim      LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}",
112343181Sdim               m_ipd_buf_size);
113343181Sdim  }
114343181Sdim
115343181Sdim  // 99% case: Just remember the string length.
116343181Sdim  m_buffer = llvm::StringRef(m_ipd_buf, res_size - 1);
117343181Sdim}
118343181Sdim
119343181Sdimvoid RichManglingContext::ParseFunctionBaseName() {
120343181Sdim  assert(m_provider != None && "Initialize a provider first");
121343181Sdim  switch (m_provider) {
122343181Sdim  case ItaniumPartialDemangler: {
123343181Sdim    auto n = m_ipd_buf_size;
124343181Sdim    auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
125343181Sdim    processIPDStrResult(buf, n);
126343181Sdim    return;
127343181Sdim  }
128343181Sdim  case PluginCxxLanguage:
129343181Sdim    m_buffer =
130343181Sdim        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
131343181Sdim    return;
132343181Sdim  case None:
133343181Sdim    return;
134343181Sdim  }
135343181Sdim}
136343181Sdim
137343181Sdimvoid RichManglingContext::ParseFunctionDeclContextName() {
138343181Sdim  assert(m_provider != None && "Initialize a provider first");
139343181Sdim  switch (m_provider) {
140343181Sdim  case ItaniumPartialDemangler: {
141343181Sdim    auto n = m_ipd_buf_size;
142343181Sdim    auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
143343181Sdim    processIPDStrResult(buf, n);
144343181Sdim    return;
145343181Sdim  }
146343181Sdim  case PluginCxxLanguage:
147343181Sdim    m_buffer =
148343181Sdim        get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext();
149343181Sdim    return;
150343181Sdim  case None:
151343181Sdim    return;
152343181Sdim  }
153343181Sdim}
154343181Sdim
155343181Sdimvoid RichManglingContext::ParseFullName() {
156343181Sdim  assert(m_provider != None && "Initialize a provider first");
157343181Sdim  switch (m_provider) {
158343181Sdim  case ItaniumPartialDemangler: {
159343181Sdim    auto n = m_ipd_buf_size;
160343181Sdim    auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
161343181Sdim    processIPDStrResult(buf, n);
162343181Sdim    return;
163343181Sdim  }
164343181Sdim  case PluginCxxLanguage:
165343181Sdim    m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
166343181Sdim                   ->GetFullName()
167343181Sdim                   .GetStringRef();
168343181Sdim    return;
169343181Sdim  case None:
170343181Sdim    return;
171343181Sdim  }
172343181Sdim}
173