diff options
| author | Aleksandr Urakov <aleksandr.urakov@jetbrains.com> | 2018-08-14 07:57:44 +0000 |
|---|---|---|
| committer | Aleksandr Urakov <aleksandr.urakov@jetbrains.com> | 2018-08-14 07:57:44 +0000 |
| commit | 7d2a74fc545df8db42d40992a3027e09c523c26c (patch) | |
| tree | 038734fb1400e82b1b0b8f7dcac3b85320ed4813 /lldb/source/Plugins/SymbolFile/PDB | |
| parent | 3c859b3ec3fe20f0878c7e1c9ff66172ba3345ac (diff) | |
| download | bcm5719-llvm-7d2a74fc545df8db42d40992a3027e09c523c26c.tar.gz bcm5719-llvm-7d2a74fc545df8db42d40992a3027e09c523c26c.zip | |
[PDB] Parse UDT symbols and pointers to members (combined patch)
Summary:
In this patch I've tried to combine the best ideas from D49368 and D49410,
so it implements following:
- Completion of UDTs from a PDB with a filling of a layout info;
- Pointers to members;
- Fixes the bug relating to a virtual base offset reading from `vbtable`.
The offset was treated as an unsigned, but it can be a negative sometimes.
- Support of MSInheritance attribute
Reviewers: asmith, zturner, rnk, labath, clayborg, lldb-commits
Reviewed By: zturner
Subscribers: aleksandr.urakov, stella.stamenova, JDevlieghere, lldb-commits
Differential Revision: https://reviews.llvm.org/D49980
llvm-svn: 339649
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/PDB')
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp | 393 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h | 38 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp | 29 |
3 files changed, 443 insertions, 17 deletions
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 8bea994aae5..713fa6e6703 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -9,11 +9,15 @@ #include "PDBASTParser.h" +#include "SymbolFilePDB.h" + #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "lldb/Core/Module.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" @@ -48,8 +52,9 @@ int TranslateUdtKind(PDB_UdtType pdb_kind) { return clang::TTK_Union; case PDB_UdtType::Interface: return clang::TTK_Interface; + default: + llvm_unreachable("unsuported PDB UDT type"); } - return -1; } lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { @@ -199,6 +204,68 @@ bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) { decl.SetLine(first_line_up->getLineNumber()); return true; } + +AccessType TranslateMemberAccess(PDB_MemberAccess access) { + switch (access) { + case PDB_MemberAccess::Private: + return eAccessPrivate; + case PDB_MemberAccess::Protected: + return eAccessProtected; + case PDB_MemberAccess::Public: + return eAccessPublic; + default: + return eAccessNone; + } +} + +AccessType GetDefaultAccessibilityForUdtKind(PDB_UdtType udt_kind) { + switch (udt_kind) { + case PDB_UdtType::Struct: + case PDB_UdtType::Union: + return eAccessPublic; + case PDB_UdtType::Class: + case PDB_UdtType::Interface: + return eAccessPrivate; + default: + llvm_unreachable("unsupported PDB UDT type"); + } +} + +AccessType GetAccessibilityForUdt(const PDBSymbolTypeUDT &udt) { + AccessType access = TranslateMemberAccess(udt.getAccess()); + if (access != lldb::eAccessNone || !udt.isNested()) + return access; + + auto parent = udt.getClassParent(); + if (!parent) + return lldb::eAccessNone; + + auto parent_udt = llvm::dyn_cast<PDBSymbolTypeUDT>(parent.get()); + if (!parent_udt) + return lldb::eAccessNone; + + return GetDefaultAccessibilityForUdtKind(parent_udt->getUdtKind()); +} + +clang::MSInheritanceAttr::Spelling GetMSInheritance( + const PDBSymbolTypeUDT &udt) { + int base_count = 0; + bool has_virtual = false; + + auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>(); + if (bases_enum) { + while (auto base = bases_enum->getNext()) { + base_count++; + has_virtual |= base->isVirtualBaseClass(); + } + } + + if (has_virtual) + return clang::MSInheritanceAttr::Keyword_virtual_inheritance; + if (base_count > 1) + return clang::MSInheritanceAttr::Keyword_multiple_inheritance; + return clang::MSInheritanceAttr::Keyword_single_inheritance; +} } // namespace PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} @@ -216,29 +283,90 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { Declaration decl; switch (type.getSymTag()) { + case PDB_SymType::BaseClass: { + auto symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + + auto ty = symbol_file->ResolveTypeUID(type.getRawSymbol().getTypeId()); + return ty ? ty->shared_from_this() : nullptr; + } break; case PDB_SymType::UDT: { auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type); assert(udt); - AccessType access = lldb::eAccessPublic; - PDB_UdtType udt_kind = udt->getUdtKind(); - auto tag_type_kind = TranslateUdtKind(udt_kind); - if (tag_type_kind == -1) + + // Note that, unnamed UDT being typedef-ed is generated as a UDT symbol + // other than a Typedef symbol in PDB. For example, + // typedef union { short Row; short Col; } Union; + // is generated as a named UDT in PDB: + // union Union { short Row; short Col; } + // Such symbols will be handled here. + + // Some UDT with trival ctor has zero length. Just ignore. + if (udt->getLength() == 0) + return nullptr; + + // Ignore unnamed-tag UDTs. + if (udt->getName().empty()) return nullptr; - if (udt_kind == PDB_UdtType::Class) - access = lldb::eAccessPrivate; + auto access = GetAccessibilityForUdt(*udt); + + auto tag_type_kind = TranslateUdtKind(udt->getUdtKind()); + + ClangASTMetadata metadata; + metadata.SetUserID(type.getSymIndexId()); + metadata.SetIsDynamicCXXType(false); CompilerType clang_type = m_ast.CreateRecordType( tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind, - lldb::eLanguageTypeC_plus_plus, nullptr); + lldb::eLanguageTypeC_plus_plus, &metadata); + assert(clang_type.IsValid()); + + if (udt->isConstType()) + clang_type = clang_type.AddConstModifier(); + + if (udt->isVolatileType()) + clang_type = clang_type.AddVolatileModifier(); + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + assert(record_decl); + auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit( + *m_ast.getASTContext(), GetMSInheritance(*udt)); + record_decl->addAttr(inheritance_attr); + + ClangASTContext::StartTagDeclarationDefinition(clang_type); - m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); + Type::ResolveStateTag type_resolve_state_tag; + auto children = udt->findAllChildren(); + if (!children || children->getChildCount() == 0) { + // PDB does not have symbol of forwarder. We assume we get an udt w/o any + // fields. Just complete it at this point. + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false); + + type_resolve_state_tag = Type::eResolveStateFull; + } else { + // Add the type to the forward declarations. It will help us to avoid + // an endless recursion in CompleteTypeFromUdt function. + auto clang_type_removed_fast_quals = + ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(); + m_forward_decl_clang_type_to_uid[clang_type_removed_fast_quals] = + type.getSymIndexId(); + + m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); + + type_resolve_state_tag = Type::eResolveStateForward; + } + + GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(udt->getName()), udt->getLength(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, - lldb_private::Type::eResolveStateForward); + type_resolve_state_tag); } break; case PDB_SymType::Enum: { auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type); @@ -441,6 +569,26 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { if (!pointee_type) return nullptr; + if (pointer_type->isPointerToDataMember() || + pointer_type->isPointerToMemberFunction()) { + auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId(); + auto class_parent_type = + m_ast.GetSymbolFile()->ResolveTypeUID(class_parent_uid); + assert(class_parent_type); + + CompilerType pointer_ast_type; + pointer_ast_type = ClangASTContext::CreateMemberPointerType( + class_parent_type->GetLayoutCompilerType(), + pointee_type->GetForwardCompilerType()); + assert(pointer_ast_type); + + return std::make_shared<lldb_private::Type>( + pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), + pointer_type->getLength(), nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type, + lldb_private::Type::eResolveStateForward); + } + CompilerType pointer_ast_type; pointer_ast_type = pointee_type->GetFullCompilerType(); if (pointer_type->isReference()) @@ -471,6 +619,47 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return nullptr; } +bool PDBASTParser::CompleteTypeFromPDB( + lldb_private::CompilerType &compiler_type) { + if (GetClangASTImporter().CanImport(compiler_type)) + return GetClangASTImporter().CompleteType(compiler_type); + + // Remove the type from the forward declarations to avoid + // an endless recursion for types like a linked list. + CompilerType compiler_type_no_qualifiers = + ClangUtil::RemoveFastQualifiers(compiler_type); + auto uid_it = m_forward_decl_clang_type_to_uid.find( + compiler_type_no_qualifiers.GetOpaqueQualType()); + if (uid_it == m_forward_decl_clang_type_to_uid.end()) + return true; + + auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile()); + if (!symbol_file) + return false; + + std::unique_ptr<PDBSymbol> symbol = + symbol_file->GetPDBSession().getSymbolById(uid_it->getSecond()); + if (!symbol) + return false; + + m_forward_decl_clang_type_to_uid.erase(uid_it); + + ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), + false); + + switch (symbol->getSymTag()) { + case PDB_SymType::UDT: { + auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(symbol.get()); + if (!udt) + return false; + + return CompleteTypeFromUDT(*symbol_file, compiler_type, *udt); + } + default: + llvm_unreachable("not a forward clang type decl!"); + } +} + bool PDBASTParser::AddEnumValue(CompilerType enum_type, const PDBSymbolData &enum_value) const { Declaration decl; @@ -513,3 +702,187 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type, enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(), raw_value, byte_size * 8); } + +bool PDBASTParser::CompleteTypeFromUDT( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &compiler_type, + llvm::pdb::PDBSymbolTypeUDT &udt) { + ClangASTImporter::LayoutInfo layout_info; + layout_info.bit_size = udt.getLength() * 8; + + auto nested_enums = udt.findAllChildren<PDBSymbolTypeUDT>(); + if (nested_enums) + while (auto nested = nested_enums->getNext()) + symbol_file.ResolveTypeUID(nested->getSymIndexId()); + + auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>(); + if (bases_enum) + AddRecordBases(symbol_file, compiler_type, + TranslateUdtKind(udt.getUdtKind()), *bases_enum, + layout_info); + + auto members_enum = udt.findAllChildren<PDBSymbolData>(); + if (members_enum) + AddRecordMembers(symbol_file, compiler_type, *members_enum, layout_info); + + auto methods_enum = udt.findAllChildren<PDBSymbolFunc>(); + if (methods_enum) + AddRecordMethods(symbol_file, compiler_type, *methods_enum); + + m_ast.AddMethodOverridesForCXXRecordType(compiler_type.GetOpaqueQualType()); + ClangASTContext::BuildIndirectFields(compiler_type); + ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType()); + if (!record_decl) + return static_cast<bool>(compiler_type); + + GetClangASTImporter().InsertRecordDecl(record_decl, layout_info); + + return static_cast<bool>(compiler_type); +} + +void PDBASTParser::AddRecordMembers( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBDataSymbolEnumerator &members_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const { + while (auto member = members_enum.getNext()) { + if (member->isCompilerGenerated()) + continue; + + auto member_name = member->getName(); + + auto member_type = symbol_file.ResolveTypeUID(member->getTypeId()); + if (!member_type) + continue; + + auto member_comp_type = member_type->GetLayoutCompilerType(); + if (!member_comp_type.GetCompleteType()) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + ":: Class '%s' has a member '%s' of type '%s' " + "which does not have a complete definition.", + record_type.GetTypeName().GetCString(), member_name.c_str(), + member_comp_type.GetTypeName().GetCString()); + if (ClangASTContext::StartTagDeclarationDefinition(member_comp_type)) + ClangASTContext::CompleteTagDeclarationDefinition(member_comp_type); + } + + auto access = TranslateMemberAccess(member->getAccess()); + + switch (member->getDataKind()) { + case PDB_DataKind::Member: { + auto location_type = member->getLocationType(); + + auto bit_size = member->getLength(); + if (location_type == PDB_LocType::ThisRel) + bit_size *= 8; + + auto decl = ClangASTContext::AddFieldToRecordType( + record_type, member_name.c_str(), member_comp_type, access, bit_size); + if (!decl) + continue; + + auto offset = member->getOffset() * 8; + if (location_type == PDB_LocType::BitField) + offset += member->getBitPosition(); + + layout_info.field_offsets.insert(std::make_pair(decl, offset)); + + break; + } + case PDB_DataKind::StaticMember: + ClangASTContext::AddVariableToRecordType(record_type, member_name.c_str(), + member_comp_type, access); + break; + default: + llvm_unreachable("unsupported PDB data kind"); + } + } +} + +void PDBASTParser::AddRecordBases( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, int record_kind, + PDBBaseClassSymbolEnumerator &bases_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const { + std::vector<clang::CXXBaseSpecifier *> base_classes; + while (auto base = bases_enum.getNext()) { + auto base_type = symbol_file.ResolveTypeUID(base->getTypeId()); + if (!base_type) + continue; + + auto base_comp_type = base_type->GetFullCompilerType(); + if (!base_comp_type.GetCompleteType()) { + symbol_file.GetObjectFile()->GetModule()->ReportError( + ":: Class '%s' has a base class '%s' " + "which does not have a complete definition.", + record_type.GetTypeName().GetCString(), + base_comp_type.GetTypeName().GetCString()); + if (ClangASTContext::StartTagDeclarationDefinition(base_comp_type)) + ClangASTContext::CompleteTagDeclarationDefinition(base_comp_type); + } + + auto access = TranslateMemberAccess(base->getAccess()); + + auto is_virtual = base->isVirtualBaseClass(); + + auto base_class_spec = m_ast.CreateBaseClassSpecifier( + base_comp_type.GetOpaqueQualType(), access, is_virtual, + record_kind == clang::TTK_Class); + if (!base_class_spec) + continue; + + base_classes.push_back(base_class_spec); + + if (is_virtual) + continue; + + auto decl = m_ast.GetAsCXXRecordDecl(base_comp_type.GetOpaqueQualType()); + if (!decl) + continue; + + auto offset = clang::CharUnits::fromQuantity(base->getOffset()); + layout_info.base_offsets.insert(std::make_pair(decl, offset)); + } + if (!base_classes.empty()) { + m_ast.SetBaseClassesForClassType(record_type.GetOpaqueQualType(), + &base_classes.front(), + base_classes.size()); + ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(), + base_classes.size()); + } +} + +void PDBASTParser::AddRecordMethods( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBFuncSymbolEnumerator &methods_enum) const { + while (auto method = methods_enum.getNext()) { + auto method_type = symbol_file.ResolveTypeUID(method->getSymIndexId()); + // MSVC specific __vecDelDtor. + if (!method_type) + break; + + 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. + m_ast.AddMethodToCXXRecordType( + record_type.GetOpaqueQualType(), method->getName().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()); + } +} diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h index d1ac138b811..5d18d0eac85 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -28,9 +28,14 @@ class CompilerType; namespace llvm { namespace pdb { +template <typename ChildType> class ConcreteSymbolEnumerator; + class PDBSymbol; class PDBSymbolData; +class PDBSymbolFunc; +class PDBSymbolTypeBaseClass; class PDBSymbolTypeBuiltin; +class PDBSymbolTypeUDT; } // namespace pdb } // namespace llvm @@ -40,13 +45,46 @@ public: ~PDBASTParser(); lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type); + bool CompleteTypeFromPDB(lldb_private::CompilerType &compiler_type); + + lldb_private::ClangASTImporter &GetClangASTImporter() { + return m_ast_importer; + } private: + typedef llvm::DenseMap<lldb::opaque_compiler_type_t, lldb::user_id_t> + ClangTypeToUidMap; + typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolData> + PDBDataSymbolEnumerator; + typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolTypeBaseClass> + PDBBaseClassSymbolEnumerator; + typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolFunc> + PDBFuncSymbolEnumerator; + bool AddEnumValue(lldb_private::CompilerType enum_type, const llvm::pdb::PDBSymbolData &data) const; + bool CompleteTypeFromUDT(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &compiler_type, + llvm::pdb::PDBSymbolTypeUDT &udt); + void AddRecordMembers( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBDataSymbolEnumerator &members_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const; + void AddRecordBases( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + int record_kind, + PDBBaseClassSymbolEnumerator &bases_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const; + void AddRecordMethods( + lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBFuncSymbolEnumerator &methods_enum) const; lldb_private::ClangASTContext &m_ast; lldb_private::ClangASTImporter m_ast_importer; + ClangTypeToUidMap m_forward_decl_clang_type_to_uid; }; #endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 05f3017819f..d5b88171a01 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -45,7 +45,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" // For IsCPPMangledName #include "Plugins/SymbolFile/PDB/PDBASTParser.h" #include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h" @@ -459,10 +459,13 @@ size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) { // This should cause the type to get cached and stored in the `m_types` // lookup. - if (!ResolveTypeUID(symbol->getSymIndexId())) - continue; - - ++num_added; + if (auto type = ResolveTypeUID(symbol->getSymIndexId())) { + // Resolve the type completely to avoid a completion + // (and so a list change, which causes an iterators invalidation) + // during a TypeList dumping + type->GetFullCompilerType(); + ++num_added; + } } } }; @@ -568,8 +571,20 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { } bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) { - // TODO: Implement this - return false; + std::lock_guard<std::recursive_mutex> guard( + GetObjectFile()->GetModule()->GetMutex()); + + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return false; + + PDBASTParser *pdb = + llvm::dyn_cast<PDBASTParser>(clang_ast_ctx->GetPDBParser()); + if (!pdb) + return false; + + return pdb->CompleteTypeFromPDB(compiler_type); } lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) { |

