summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksandr Urakov <aleksandr.urakov@jetbrains.com>2018-11-06 08:02:55 +0000
committerAleksandr Urakov <aleksandr.urakov@jetbrains.com>2018-11-06 08:02:55 +0000
commit7ec859446c3fecfefa1c8e8a0785c00b4ca74faf (patch)
tree50ac266aa5a5fab8b613e1407f8e506e68c89bbc
parentaebc4e59778d5f4e53a914c71cedd863e2f123c8 (diff)
[PDB] Introduce `MSVCUndecoratedNameParser`
This patch introduces the simple MSVCUndecoratedNameParser. It is needed for parsing names of PDB symbols corresponding to template instantiations. For example, for the name `operator<<A>'::`2'::B::operator> we can't just split the name with :: (as it is implemented for now) to retrieve its scopes. This parser processes such names in a more correct way. Differential Revision: https://reviews.llvm.org/D52461
-rw-r--r--lldb/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp10
-rw-r--r--lldb/lit/SymbolFile/PDB/ast-restore.test6
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp5
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp98
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h51
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp226
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h6
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp42
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h2
-rw-r--r--lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp9
11 files changed, 333 insertions, 123 deletions
diff --git a/lldb/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp b/lldb/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
index 8a56fd7e048..8c9e26744d5 100644
--- a/lldb/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
+++ b/lldb/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp
@@ -36,7 +36,15 @@ private:
};
int Class::ClassStatic = 7;
-void foo() { Class::StaticFunc(Class(Enum_0)); }
+template<typename T>
+struct Template {
+ template<Enum E>
+ void TemplateFunc() {
+ T::StaticFunc(T(E));
+ }
+};
+
+void foo() { Template<Class>().TemplateFunc<Enum_0>(); }
} // namespace N1
} // namespace N0
diff --git a/lldb/lit/SymbolFile/PDB/ast-restore.test b/lldb/lit/SymbolFile/PDB/ast-restore.test
index 95e130186d7..77cdd283f38 100644
--- a/lldb/lit/SymbolFile/PDB/ast-restore.test
+++ b/lldb/lit/SymbolFile/PDB/ast-restore.test
@@ -6,6 +6,7 @@ RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=GLOBAL %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=BASE %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=CLASS %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=INNER %s
+RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=TEMPLATE %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=FOO %s
RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=MAIN %s
@@ -66,6 +67,11 @@ INNER: };
INNER: }
INNER: }
+TEMPLATE: Module: {{.*}}
+TEMPLATE: struct Template<N0::N1::Class> {
+TEMPLATE: inline void TemplateFunc<1>();
+TEMPLATE: };
+
FOO: Module: {{.*}}
FOO: namespace N0 {
FOO: namespace N1 {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index 715334412f8..bc357aa52b8 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -18,6 +18,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibStdcpp.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
+ MSVCUndecoratedNameParser.cpp
LINK_LIBS
lldbCore
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index f437582fbd2..badfb948ed9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -41,6 +41,7 @@
#include "LibCxxAtomic.h"
#include "LibCxxVariant.h"
#include "LibStdcpp.h"
+#include "MSVCUndecoratedNameParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -265,6 +266,10 @@ bool CPlusPlusLanguage::IsCPPMangledName(const char *name) {
bool CPlusPlusLanguage::ExtractContextAndIdentifier(
const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
+ if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
+ return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
+ identifier);
+
CPlusPlusNameParser parser(name);
if (auto full_name = parser.ParseAsFullName()) {
identifier = full_name.getValue().basename;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp
new file mode 100644
index 00000000000..d2207566de3
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp
@@ -0,0 +1,98 @@
+//===-- MSVCUndecoratedNameParser.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MSVCUndecoratedNameParser.h"
+
+#include <stack>
+
+MSVCUndecoratedNameParser::MSVCUndecoratedNameParser(llvm::StringRef name) {
+ std::size_t last_base_start = 0;
+
+ std::stack<std::size_t> stack;
+ unsigned int open_angle_brackets = 0;
+ for (size_t i = 0; i < name.size(); i++) {
+ switch (name[i]) {
+ case '<':
+ // Do not treat `operator<' and `operator<<' as templates
+ // (sometimes they represented as `<' and `<<' in the name).
+ if (i == last_base_start ||
+ i == last_base_start + 1 && name[last_base_start] == '<')
+ break;
+
+ stack.push(i);
+ open_angle_brackets++;
+
+ break;
+ case '>':
+ if (!stack.empty() && name[stack.top()] == '<') {
+ open_angle_brackets--;
+ stack.pop();
+ }
+
+ break;
+ case '`':
+ stack.push(i);
+
+ break;
+ case '\'':
+ while (!stack.empty()) {
+ std::size_t top = stack.top();
+ if (name[top] == '<')
+ open_angle_brackets--;
+
+ stack.pop();
+
+ if (name[top] == '`')
+ break;
+ }
+
+ break;
+ case ':':
+ if (open_angle_brackets)
+ break;
+ if (i == 0 || name[i - 1] != ':')
+ break;
+
+ m_specifiers.emplace_back(name.take_front(i - 1),
+ name.slice(last_base_start, i - 1));
+
+ last_base_start = i + 1;
+ default:
+ break;
+ }
+ }
+
+ m_specifiers.emplace_back(name, name.drop_front(last_base_start));
+}
+
+bool MSVCUndecoratedNameParser::IsMSVCUndecoratedName(llvm::StringRef name) {
+ return name.find('`') != llvm::StringRef::npos;
+}
+
+bool MSVCUndecoratedNameParser::ExtractContextAndIdentifier(
+ llvm::StringRef name, llvm::StringRef &context,
+ llvm::StringRef &identifier) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ std::size_t count = specs.size();
+ identifier = count > 0 ? specs[count - 1].GetBaseName() : "";
+ context = count > 1 ? specs[count - 2].GetFullName() : "";
+
+ return count;
+}
+
+llvm::StringRef MSVCUndecoratedNameParser::DropScope(llvm::StringRef name) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+ if (specs.empty())
+ return "";
+
+ return specs[specs.size() - 1].GetBaseName();
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h
new file mode 100644
index 00000000000..0c49100d8d4
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h
@@ -0,0 +1,51 @@
+//===-- MSVCUndecoratedNameParser.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_MSVCUndecoratedNameParser_h_
+#define liblldb_MSVCUndecoratedNameParser_h_
+
+#include <vector>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+class MSVCUndecoratedNameSpecifier {
+public:
+ MSVCUndecoratedNameSpecifier(llvm::StringRef full_name,
+ llvm::StringRef base_name)
+ : m_full_name(full_name), m_base_name(base_name) {}
+
+ llvm::StringRef GetFullName() const { return m_full_name; }
+ llvm::StringRef GetBaseName() const { return m_base_name; }
+
+private:
+ llvm::StringRef m_full_name;
+ llvm::StringRef m_base_name;
+};
+
+class MSVCUndecoratedNameParser {
+public:
+ explicit MSVCUndecoratedNameParser(llvm::StringRef name);
+
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> GetSpecifiers() const {
+ return m_specifiers;
+ }
+
+ static bool IsMSVCUndecoratedName(llvm::StringRef name);
+ static bool ExtractContextAndIdentifier(llvm::StringRef name,
+ llvm::StringRef &context,
+ llvm::StringRef &identifier);
+
+ static llvm::StringRef DropScope(llvm::StringRef name);
+
+private:
+ std::vector<MSVCUndecoratedNameSpecifier> m_specifiers;
+};
+
+#endif
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
index 2134071db22..b2f6a296557 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -38,6 +38,8 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace llvm::pdb;
@@ -330,7 +332,7 @@ GetDeclFromContextByName(const clang::ASTContext &ast,
return result[0];
}
-static bool IsAnonymousNamespaceName(const std::string &name) {
+static bool IsAnonymousNamespaceName(llvm::StringRef name) {
return name == "`anonymous namespace'" || name == "`anonymous-namespace'";
}
@@ -387,7 +389,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
return nullptr;
// Ignore unnamed-tag UDTs.
- auto name = PDBNameDropScope(udt->getName());
+ std::string name = MSVCUndecoratedNameParser::DropScope(udt->getName());
if (name.empty())
return nullptr;
@@ -465,7 +467,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
assert(enum_type);
- std::string name = PDBNameDropScope(enum_type->getName());
+ std::string name =
+ MSVCUndecoratedNameParser::DropScope(enum_type->getName());
auto decl_context = GetDeclContextContainingSymbol(type);
uint64_t bytes = enum_type->getLength();
@@ -537,7 +540,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
if (!target_type)
return nullptr;
- std::string name = PDBNameDropScope(type_def->getName());
+ std::string name =
+ MSVCUndecoratedNameParser::DropScope(type_def->getName());
auto decl_ctx = GetDeclContextContainingSymbol(type);
// Check if such a typedef already exists in the current context
@@ -583,7 +587,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
return nullptr;
func_sig = sig.release();
// Function type is named.
- name = PDBNameDropScope(pdb_func->getName());
+ name = MSVCUndecoratedNameParser::DropScope(pdb_func->getName());
} else if (auto pdb_func_sig =
llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) {
func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig);
@@ -796,7 +800,8 @@ bool PDBASTParser::CompleteTypeFromPDB(
clang::Decl *
PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
- auto it = m_uid_to_decl.find(symbol.getSymIndexId());
+ uint32_t sym_id = symbol.getSymIndexId();
+ auto it = m_uid_to_decl.find(sym_id);
if (it != m_uid_to_decl.end())
return it->second;
@@ -812,14 +817,50 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
const IPDBRawSymbol &raw = symbol.getRawSymbol();
auto class_parent_id = raw.getClassParentId();
- if (session.getSymbolById(class_parent_id)) {
+ if (std::unique_ptr<PDBSymbol> class_parent =
+ session.getSymbolById(class_parent_id)) {
auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_id);
if (!class_parent_type)
return nullptr;
- class_parent_type->GetFullCompilerType();
+ CompilerType class_parent_ct = class_parent_type->GetFullCompilerType();
+
+ // Look a declaration up in the cache after completing the class
+ clang::Decl *decl = m_uid_to_decl.lookup(sym_id);
+ if (decl)
+ return decl;
+
+ // A declaration was not found in the cache. It means that the symbol
+ // has the class parent, but the class doesn't have the symbol in its
+ // children list.
+ if (auto func = llvm::dyn_cast_or_null<PDBSymbolFunc>(&symbol)) {
+ // Try to find a class child method with the same RVA and use its
+ // declaration if found.
+ if (uint32_t rva = func->getRelativeVirtualAddress()) {
+ if (std::unique_ptr<ConcreteSymbolEnumerator<PDBSymbolFunc>>
+ methods_enum =
+ class_parent->findAllChildren<PDBSymbolFunc>()) {
+ while (std::unique_ptr<PDBSymbolFunc> method =
+ methods_enum->getNext()) {
+ if (method->getRelativeVirtualAddress() == rva) {
+ decl = m_uid_to_decl.lookup(method->getSymIndexId());
+ if (decl)
+ break;
+ }
+ }
+ }
+ }
+
+ // If no class methods with the same RVA were found, then create a new
+ // method. It is possible for template methods.
+ if (!decl)
+ decl = AddRecordMethod(*symbol_file, class_parent_ct, *func);
+ }
- return m_uid_to_decl.lookup(symbol.getSymIndexId());
+ if (decl)
+ m_uid_to_decl[sym_id] = decl;
+
+ return decl;
}
}
@@ -841,7 +882,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
if (auto parent_decl = llvm::dyn_cast_or_null<clang::TagDecl>(decl_context))
m_ast.GetCompleteDecl(parent_decl);
- auto name = PDBNameDropScope(data->getName());
+ std::string name = MSVCUndecoratedNameParser::DropScope(data->getName());
// Check if the current context already contains the symbol with the name.
clang::Decl *decl =
@@ -856,7 +897,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
ClangUtil::GetQualType(type->GetLayoutCompilerType()));
}
- m_uid_to_decl[data->getSymIndexId()] = decl;
+ m_uid_to_decl[sym_id] = decl;
return decl;
}
@@ -867,9 +908,9 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
auto decl_context = GetDeclContextContainingSymbol(symbol);
assert(decl_context);
- auto name = PDBNameDropScope(func->getName());
+ std::string name = MSVCUndecoratedNameParser::DropScope(func->getName());
- auto type = symbol_file->ResolveTypeUID(func->getSymIndexId());
+ Type *type = symbol_file->ResolveTypeUID(sym_id);
if (!type)
return nullptr;
@@ -880,17 +921,17 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
decl_context, name.c_str(), type->GetForwardCompilerType(), storage,
func->hasInlineAttribute());
- m_uid_to_decl[func->getSymIndexId()] = decl;
+ m_uid_to_decl[sym_id] = decl;
return decl;
}
default: {
// It's not a variable and not a function, check if it's a type
- auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId());
+ Type *type = symbol_file->ResolveTypeUID(sym_id);
if (!type)
return nullptr;
- return m_uid_to_decl.lookup(symbol.getSymIndexId());
+ return m_uid_to_decl.lookup(sym_id);
}
}
}
@@ -937,19 +978,15 @@ clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol(
// We can't find any class or function parent of the symbol. So analyze
// the full symbol name. The symbol may be belonging to a namespace
// or function (or even to a class if it's e.g. a static variable symbol).
- // We do not use CPlusPlusNameParser because it fails on things like
- // `anonymous namespace'.
// TODO: Make clang to emit full names for variables in namespaces
// (as MSVC does)
- auto context = symbol.getRawSymbol().getName();
- auto context_size = context.rfind("::");
- if (context_size == std::string::npos)
- context_size = 0;
- context = context.substr(0, context_size);
-
- // Check if there is a symbol with the name of the context.
+ std::string name(symbol.getRawSymbol().getName());
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+ if (specs.empty())
+ return m_ast.GetTranslationUnitDecl();
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
@@ -959,32 +996,43 @@ clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol(
if (!global)
return m_ast.GetTranslationUnitDecl();
- TypeMap types;
- if (auto children_enum =
- global->findChildren(PDB_SymType::None, context, NS_CaseSensitive))
- while (auto child = children_enum->getNext())
- if (auto child_context = GetDeclContextForSymbol(*child))
- return child_context;
-
- // Split context and retrieve nested namespaces
+ bool has_type_or_function_parent = false;
clang::DeclContext *curr_context = m_ast.GetTranslationUnitDecl();
- std::string::size_type from = 0;
- while (from < context_size) {
- auto to = context.find("::", from);
- if (to == std::string::npos)
- to = context_size;
-
- auto namespace_name = context.substr(from, to - from);
- auto namespace_name_c_str = IsAnonymousNamespaceName(namespace_name)
- ? nullptr
- : namespace_name.c_str();
- auto namespace_decl =
- m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str, curr_context);
-
- m_parent_to_namespaces[curr_context].insert(namespace_decl);
-
- curr_context = namespace_decl;
- from = to + 2;
+ for (std::size_t i = 0; i < specs.size() - 1; i++) {
+ // Check if there is a function or a type with the current context's name.
+ if (std::unique_ptr<IPDBEnumSymbols> children_enum = global->findChildren(
+ PDB_SymType::None, specs[i].GetFullName(), NS_CaseSensitive)) {
+ while (IPDBEnumChildren<PDBSymbol>::ChildTypePtr child =
+ children_enum->getNext()) {
+ if (clang::DeclContext *child_context =
+ GetDeclContextForSymbol(*child)) {
+ // Note that `GetDeclContextForSymbol' retrieves
+ // a declaration context for functions and types only,
+ // so if we are here then `child_context' is guaranteed
+ // a function or a type declaration context.
+ has_type_or_function_parent = true;
+ curr_context = child_context;
+ }
+ }
+ }
+
+ // If there were no functions or types above then retrieve a namespace with
+ // the current context's name. There can be no namespaces inside a function
+ // or a type. We check it to avoid fake namespaces such as `__l2':
+ // `N0::N1::CClass::PrivateFunc::__l2::InnerFuncStruct'
+ if (!has_type_or_function_parent) {
+ std::string namespace_name = specs[i].GetBaseName();
+ const char *namespace_name_c_str =
+ IsAnonymousNamespaceName(namespace_name) ? nullptr
+ : namespace_name.data();
+ clang::NamespaceDecl *namespace_decl =
+ m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str,
+ curr_context);
+
+ m_parent_to_namespaces[curr_context].insert(namespace_decl);
+
+ curr_context = namespace_decl;
+ }
}
return curr_context;
@@ -1035,24 +1083,11 @@ PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent,
return nullptr;
}
-std::string PDBASTParser::PDBNameDropScope(const std::string &name) {
- // Not all PDB names can be parsed with CPlusPlusNameParser.
- // E.g. it fails on names containing `anonymous namespace'.
- // So we simply drop everything before '::'
-
- auto offset = name.rfind("::");
- if (offset == std::string::npos)
- return name;
- assert(offset + 2 <= name.size());
-
- return name.substr(offset + 2);
-}
-
bool PDBASTParser::AddEnumValue(CompilerType enum_type,
const PDBSymbolData &enum_value) {
Declaration decl;
Variant v = enum_value.getValue();
- std::string name = PDBNameDropScope(enum_value.getName());
+ std::string name = MSVCUndecoratedNameParser::DropScope(enum_value.getName());
int64_t raw_value;
switch (v.Type) {
case PDB_VariantType::Int8:
@@ -1257,36 +1292,43 @@ void PDBASTParser::AddRecordBases(
void PDBASTParser::AddRecordMethods(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum) {
- while (auto method = methods_enum.getNext()) {
- auto name = PDBNameDropScope(method->getName().c_str());
+ while (std::unique_ptr<PDBSymbolFunc> method = methods_enum.getNext())
+ if (clang::CXXMethodDecl *decl =
+ AddRecordMethod(symbol_file, record_type, *method))
+ m_uid_to_decl[method->getSymIndexId()] = decl;
+}
- auto method_type = symbol_file.ResolveTypeUID(method->getSymIndexId());
- // MSVC specific __vecDelDtor.
- if (!method_type)
- continue;
+clang::CXXMethodDecl *
+PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ const llvm::pdb::PDBSymbolFunc &method) const {
+ std::string name = MSVCUndecoratedNameParser::DropScope(method.getName());
- auto method_comp_type = method_type->GetFullCompilerType();
- if (!method_comp_type.GetCompleteType()) {
- symbol_file.GetObjectFile()->GetModule()->ReportError(
- ":: Class '%s' has a method '%s' whose type cannot be completed.",
- record_type.GetTypeName().GetCString(),
- method_comp_type.GetTypeName().GetCString());
- if (ClangASTContext::StartTagDeclarationDefinition(method_comp_type))
- ClangASTContext::CompleteTagDeclarationDefinition(method_comp_type);
- }
-
- // TODO: get mangled name for the method.
- auto decl = m_ast.AddMethodToCXXRecordType(
- record_type.GetOpaqueQualType(), name.c_str(),
- /*mangled_name*/ nullptr, method_comp_type,
- TranslateMemberAccess(method->getAccess()), method->isVirtual(),
- method->isStatic(), method->hasInlineAttribute(),
- /*is_explicit*/ false, // FIXME: Need this field in CodeView.
- /*is_attr_used*/ false,
- /*is_artificial*/ method->isCompilerGenerated());
- if (!decl)
- continue;
+ Type *method_type = symbol_file.ResolveTypeUID(method.getSymIndexId());
+ // MSVC specific __vecDelDtor.
+ if (!method_type)
+ return nullptr;
- m_uid_to_decl[method->getSymIndexId()] = decl;
+ CompilerType method_comp_type = method_type->GetFullCompilerType();
+ if (!method_comp_type.GetCompleteType()) {
+ symbol_file.GetObjectFile()->GetModule()->ReportError(
+ ":: Class '%s' has a method '%s' whose type cannot be completed.",
+ record_type.GetTypeName().GetCString(),
+ method_comp_type.GetTypeName().GetCString());
+ if (ClangASTContext::StartTagDeclarationDefinition(method_comp_type))
+ ClangASTContext::CompleteTagDeclarationDefinition(method_comp_type);
}
+
+ AccessType access = TranslateMemberAccess(method.getAccess());
+ if (access == eAccessNone)
+ access = eAccessPublic;
+
+ // TODO: get mangled name for the method.
+ return m_ast.AddMethodToCXXRecordType(
+ record_type.GetOpaqueQualType(), name.c_str(),
+ /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(),
+ method.isStatic(), method.hasInlineAttribute(),
+ /*is_explicit*/ false, // FIXME: Need this field in CodeView.
+ /*is_attr_used*/ false,
+ /*is_artificial*/ method.isCompilerGenerated());
}
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h
index 888c2170e1d..28de07fd8cd 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h
@@ -65,8 +65,6 @@ public:
return m_ast_importer;
}
- static std::string PDBNameDropScope(const std::string &name);
-
private:
typedef llvm::DenseMap<clang::CXXRecordDecl *, lldb::user_id_t>
CXXRecordDeclToUidMap;
@@ -100,6 +98,10 @@ private:
void AddRecordMethods(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum);
+ clang::CXXMethodDecl *
+ AddRecordMethod(lldb_private::SymbolFile &symbol_file,
+ lldb_private::CompilerType &record_type,
+ const llvm::pdb::PDBSymbolFunc &method) const;
lldb_private::ClangASTContext &m_ast;
lldb_private::ClangASTImporter m_ast_importer;
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 6096218552b..2779aee341d 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -9,6 +9,9 @@
#include "SymbolFilePDB.h"
+#include "PDBASTParser.h"
+#include "PDBLocationToDWARFExpression.h"
+
#include "clang/Lex/Lexer.h"
#include "lldb/Core/Module.h"
@@ -46,9 +49,8 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" // For IsCPPMangledName
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
#include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h"
-#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
-#include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h"
#include <regex>
@@ -1068,7 +1070,7 @@ uint32_t SymbolFilePDB::FindGlobalVariables(
lldbassert(sc.module_sp.get());
if (!name.GetStringRef().equals(
- PDBASTParser::PDBNameDropScope(pdb_data->getName())))
+ MSVCUndecoratedNameParser::DropScope(pdb_data->getName())))
continue;
sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get();
@@ -1175,22 +1177,11 @@ void SymbolFilePDB::CacheFunctionNames() {
// Class. We won't bother to check if the parent is UDT or Enum here.
m_func_method_names.Append(ConstString(name), uid);
- ConstString cstr_name(name);
-
// To search a method name, like NS::Class:MemberFunc, LLDB searches
// its base name, i.e. MemberFunc by default. Since PDBSymbolFunc does
// not have inforamtion of this, we extract base names and cache them
// by our own effort.
- llvm::StringRef basename;
- CPlusPlusLanguage::MethodName cpp_method(cstr_name);
- if (cpp_method.IsValid()) {
- llvm::StringRef context;
- basename = cpp_method.GetBasename();
- if (basename.empty())
- CPlusPlusLanguage::ExtractContextAndIdentifier(name.c_str(),
- context, basename);
- }
-
+ llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name);
if (!basename.empty())
m_func_base_names.Append(ConstString(basename), uid);
else {
@@ -1203,11 +1194,12 @@ void SymbolFilePDB::CacheFunctionNames() {
} else {
// Handle not-method symbols.
- // The function name might contain namespace, or its lexical scope. It
- // is not safe to get its base name by applying same scheme as we deal
- // with the method names.
- // FIXME: Remove namespace if function is static in a scope.
- m_func_base_names.Append(ConstString(name), uid);
+ // The function name might contain namespace, or its lexical scope.
+ llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name);
+ if (!basename.empty())
+ m_func_base_names.Append(ConstString(basename), uid);
+ else
+ m_func_base_names.Append(ConstString(name), uid);
if (name == "main") {
m_func_full_names.Append(ConstString(name), uid);
@@ -1353,10 +1345,8 @@ uint32_t SymbolFilePDB::FindTypes(
searched_symbol_files.clear();
searched_symbol_files.insert(this);
- std::string name_str = name.AsCString();
-
// There is an assumption 'name' is not a regex
- FindTypesByName(name_str, parent_decl_ctx, max_matches, types);
+ FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types);
return types.GetSize();
}
@@ -1425,7 +1415,7 @@ void SymbolFilePDB::FindTypesByRegex(
}
void SymbolFilePDB::FindTypesByName(
- const std::string &name,
+ llvm::StringRef name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::TypeMap &types) {
if (!parent_decl_ctx)
@@ -1443,8 +1433,8 @@ void SymbolFilePDB::FindTypesByName(
if (max_matches > 0 && matches >= max_matches)
break;
- if (PDBASTParser::PDBNameDropScope(result->getRawSymbol().getName()) !=
- name)
+ if (MSVCUndecoratedNameParser::DropScope(
+ result->getRawSymbol().getName()) != name)
continue;
switch (result->getSymTag()) {
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
index 8b95ff5c168..12491e30bf2 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -192,7 +192,7 @@ private:
const llvm::pdb::PDBSymbolCompiland &pdb_compiland,
llvm::DenseMap<uint32_t, uint32_t> &index_map) const;
- void FindTypesByName(const std::string &name,
+ void FindTypesByName(llvm::StringRef name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::TypeMap &types);
diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
index 81d3ac51fd9..ed9b6b08b76 100644
--- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
+++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
@@ -138,7 +138,14 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {
{"std::vector<Class, std::allocator<Class>>"
"::_M_emplace_back_aux<Class const&>",
"std::vector<Class, std::allocator<Class>>",
- "_M_emplace_back_aux<Class const&>"}};
+ "_M_emplace_back_aux<Class const&>"},
+ {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"},
+ {"`operator<<A>'::`2'::B<0>::operator>",
+ "`operator<<A>'::`2'::B<0>",
+ "operator>"},
+ {"`anonymous namespace'::S::<<::__l2::Foo",
+ "`anonymous namespace'::S::<<::__l2",
+ "Foo"}};
llvm::StringRef context, basename;
for (const auto &test : test_cases) {