Files
llvm/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
Raphael Isemann 722247c812 [lldb] Unify the two CreateTypedef implementations in TypeSystemClang
To get LLDB one step closer to fulfil the software redundancy requirements of
modern aircrafts, we apparently decided to have two separately maintained
implementations of `CreateTypedef` in TypeSystemClang. Let's pass on the idea of
an LLDB-powered jetliner and deleted one implementation.

On a more serious note: This function got duplicated a long time ago when the
idea of CompilerType with a backing TypeSystemClang subclass happened
(56939cb310). One implementation was supposed to
be called from CompilerType::CreateTypedef and the other has just always been
around to create typedefs. By accident one of the implementations is only used
by the PDB parser while the CompilerType::CreateTypedef backend is used by the
rest of LLDB.

We also had some patches over the year that only fixed one of the two functions
(D18099 for example only fixed up the CompilerType::CreateTypedef
implementation). D51162 and D86140 both fixed the same missing `addDecl` call
for one of the two implementations.

This patch:
* deletes the `CreateTypedefType` function as its only used by the PDB parser
  and the `CreateTypedef` implementation is anyway needed as it's the backend
  implementation of CompilerType.
* replaces the calls in the PDB parser by just calling the CompilerType wrapper.
* moves the documentation to the remaining function.
* moves the check for empty typedef names that was only in the deleted
  implementation to the other (I don't think this fixes anything as I believe
  all callers are already doing the same check).

I'll fix up the usual stuff (not using StringRef, not doing early exit) in a NFC
follow-up.

This patch is not NFC as the PDB parser now calls the function that has the fix
from D18099.

Reviewed By: labath, JDevlieghere

Differential Revision: https://reviews.llvm.org/D93382
2020-12-17 10:49:26 +01:00

1418 lines
50 KiB
C++

//===-- PDBASTParser.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 "PDBASTParser.h"
#include "SymbolFilePDB.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Declaration.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
#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;
static int TranslateUdtKind(PDB_UdtType pdb_kind) {
switch (pdb_kind) {
case PDB_UdtType::Class:
return clang::TTK_Class;
case PDB_UdtType::Struct:
return clang::TTK_Struct;
case PDB_UdtType::Union:
return clang::TTK_Union;
case PDB_UdtType::Interface:
return clang::TTK_Interface;
}
llvm_unreachable("unsuported PDB UDT type");
}
static lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) {
switch (type) {
case PDB_BuiltinType::Float:
return lldb::eEncodingIEEE754;
case PDB_BuiltinType::Int:
case PDB_BuiltinType::Long:
case PDB_BuiltinType::Char:
return lldb::eEncodingSint;
case PDB_BuiltinType::Bool:
case PDB_BuiltinType::Char16:
case PDB_BuiltinType::Char32:
case PDB_BuiltinType::UInt:
case PDB_BuiltinType::ULong:
case PDB_BuiltinType::HResult:
case PDB_BuiltinType::WCharT:
return lldb::eEncodingUint;
default:
return lldb::eEncodingInvalid;
}
}
static lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) {
switch (type) {
case PDB_VariantType::Int8:
case PDB_VariantType::Int16:
case PDB_VariantType::Int32:
case PDB_VariantType::Int64:
return lldb::eEncodingSint;
case PDB_VariantType::UInt8:
case PDB_VariantType::UInt16:
case PDB_VariantType::UInt32:
case PDB_VariantType::UInt64:
return lldb::eEncodingUint;
default:
break;
}
return lldb::eEncodingSint;
}
static CompilerType
GetBuiltinTypeForPDBEncodingAndBitSize(TypeSystemClang &clang_ast,
const PDBSymbolTypeBuiltin &pdb_type,
Encoding encoding, uint32_t width) {
clang::ASTContext &ast = clang_ast.getASTContext();
switch (pdb_type.getBuiltinType()) {
default:
break;
case PDB_BuiltinType::None:
return CompilerType();
case PDB_BuiltinType::Void:
return clang_ast.GetBasicType(eBasicTypeVoid);
case PDB_BuiltinType::Char:
return clang_ast.GetBasicType(eBasicTypeChar);
case PDB_BuiltinType::Bool:
return clang_ast.GetBasicType(eBasicTypeBool);
case PDB_BuiltinType::Long:
if (width == ast.getTypeSize(ast.LongTy))
return CompilerType(&clang_ast, ast.LongTy.getAsOpaquePtr());
if (width == ast.getTypeSize(ast.LongLongTy))
return CompilerType(&clang_ast, ast.LongLongTy.getAsOpaquePtr());
break;
case PDB_BuiltinType::ULong:
if (width == ast.getTypeSize(ast.UnsignedLongTy))
return CompilerType(&clang_ast, ast.UnsignedLongTy.getAsOpaquePtr());
if (width == ast.getTypeSize(ast.UnsignedLongLongTy))
return CompilerType(&clang_ast, ast.UnsignedLongLongTy.getAsOpaquePtr());
break;
case PDB_BuiltinType::WCharT:
if (width == ast.getTypeSize(ast.WCharTy))
return CompilerType(&clang_ast, ast.WCharTy.getAsOpaquePtr());
break;
case PDB_BuiltinType::Char16:
return CompilerType(&clang_ast, ast.Char16Ty.getAsOpaquePtr());
case PDB_BuiltinType::Char32:
return CompilerType(&clang_ast, ast.Char32Ty.getAsOpaquePtr());
case PDB_BuiltinType::Float:
// Note: types `long double` and `double` have same bit size in MSVC and
// there is no information in the PDB to distinguish them. So when falling
// back to default search, the compiler type of `long double` will be
// represented by the one generated for `double`.
break;
}
// If there is no match on PDB_BuiltinType, fall back to default search by
// encoding and width only
return clang_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, width);
}
static ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type,
CompilerType &compiler_type) {
PDB_BuiltinType kind = pdb_type.getBuiltinType();
switch (kind) {
default:
break;
case PDB_BuiltinType::Currency:
return ConstString("CURRENCY");
case PDB_BuiltinType::Date:
return ConstString("DATE");
case PDB_BuiltinType::Variant:
return ConstString("VARIANT");
case PDB_BuiltinType::Complex:
return ConstString("complex");
case PDB_BuiltinType::Bitfield:
return ConstString("bitfield");
case PDB_BuiltinType::BSTR:
return ConstString("BSTR");
case PDB_BuiltinType::HResult:
return ConstString("HRESULT");
case PDB_BuiltinType::BCD:
return ConstString("BCD");
case PDB_BuiltinType::Char16:
return ConstString("char16_t");
case PDB_BuiltinType::Char32:
return ConstString("char32_t");
case PDB_BuiltinType::None:
return ConstString("...");
}
return compiler_type.GetTypeName();
}
static bool GetDeclarationForSymbol(const PDBSymbol &symbol,
Declaration &decl) {
auto &raw_sym = symbol.getRawSymbol();
auto first_line_up = raw_sym.getSrcLineOnTypeDefn();
if (!first_line_up) {
auto lines_up = symbol.getSession().findLineNumbersByAddress(
raw_sym.getVirtualAddress(), raw_sym.getLength());
if (!lines_up)
return false;
first_line_up = lines_up->getNext();
if (!first_line_up)
return false;
}
uint32_t src_file_id = first_line_up->getSourceFileId();
auto src_file_up = symbol.getSession().getSourceFileById(src_file_id);
if (!src_file_up)
return false;
FileSpec spec(src_file_up->getFileName());
decl.SetFile(spec);
decl.SetColumn(first_line_up->getColumnNumber());
decl.SetLine(first_line_up->getLineNumber());
return true;
}
static 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;
}
return eAccessNone;
}
static 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;
}
llvm_unreachable("unsupported PDB UDT type");
}
static 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());
}
static 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;
}
static std::unique_ptr<llvm::pdb::PDBSymbol>
GetClassOrFunctionParent(const llvm::pdb::PDBSymbol &symbol) {
const IPDBSession &session = symbol.getSession();
const IPDBRawSymbol &raw = symbol.getRawSymbol();
auto tag = symbol.getSymTag();
// For items that are nested inside of a class, return the class that it is
// nested inside of.
// Note that only certain items can be nested inside of classes.
switch (tag) {
case PDB_SymType::Function:
case PDB_SymType::Data:
case PDB_SymType::UDT:
case PDB_SymType::Enum:
case PDB_SymType::FunctionSig:
case PDB_SymType::Typedef:
case PDB_SymType::BaseClass:
case PDB_SymType::VTable: {
auto class_parent_id = raw.getClassParentId();
if (auto class_parent = session.getSymbolById(class_parent_id))
return class_parent;
break;
}
default:
break;
}
// Otherwise, if it is nested inside of a function, return the function.
// Note that only certain items can be nested inside of functions.
switch (tag) {
case PDB_SymType::Block:
case PDB_SymType::Data: {
auto lexical_parent_id = raw.getLexicalParentId();
auto lexical_parent = session.getSymbolById(lexical_parent_id);
if (!lexical_parent)
return nullptr;
auto lexical_parent_tag = lexical_parent->getSymTag();
if (lexical_parent_tag == PDB_SymType::Function)
return lexical_parent;
if (lexical_parent_tag == PDB_SymType::Exe)
return nullptr;
return GetClassOrFunctionParent(*lexical_parent);
}
default:
return nullptr;
}
}
static clang::NamedDecl *
GetDeclFromContextByName(const clang::ASTContext &ast,
const clang::DeclContext &decl_context,
llvm::StringRef name) {
clang::IdentifierInfo &ident = ast.Idents.get(name);
clang::DeclarationName decl_name = ast.DeclarationNames.getIdentifier(&ident);
clang::DeclContext::lookup_result result = decl_context.lookup(decl_name);
if (result.empty())
return nullptr;
return result[0];
}
static bool IsAnonymousNamespaceName(llvm::StringRef name) {
return name == "`anonymous namespace'" || name == "`anonymous-namespace'";
}
static clang::CallingConv TranslateCallingConvention(PDB_CallingConv pdb_cc) {
switch (pdb_cc) {
case llvm::codeview::CallingConvention::NearC:
return clang::CC_C;
case llvm::codeview::CallingConvention::NearStdCall:
return clang::CC_X86StdCall;
case llvm::codeview::CallingConvention::NearFast:
return clang::CC_X86FastCall;
case llvm::codeview::CallingConvention::ThisCall:
return clang::CC_X86ThisCall;
case llvm::codeview::CallingConvention::NearVector:
return clang::CC_X86VectorCall;
case llvm::codeview::CallingConvention::NearPascal:
return clang::CC_X86Pascal;
default:
assert(false && "Unknown calling convention");
return clang::CC_C;
}
}
PDBASTParser::PDBASTParser(lldb_private::TypeSystemClang &ast) : m_ast(ast) {}
PDBASTParser::~PDBASTParser() {}
// DebugInfoASTParser interface
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);
// 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.
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(udt->getName()));
if (name.empty())
return nullptr;
auto decl_context = GetDeclContextContainingSymbol(type);
// Check if such an UDT already exists in the current context.
// This may occur with const or volatile types. There are separate type
// symbols in PDB for types with const or volatile modifiers, but we need
// to create only one declaration for them all.
Type::ResolveState type_resolve_state;
CompilerType clang_type = m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>(
ConstString(name), decl_context);
if (!clang_type.IsValid()) {
auto access = GetAccessibilityForUdt(*udt);
auto tag_type_kind = TranslateUdtKind(udt->getUdtKind());
ClangASTMetadata metadata;
metadata.SetUserID(type.getSymIndexId());
metadata.SetIsDynamicCXXType(false);
clang_type = m_ast.CreateRecordType(
decl_context, OptionalClangModuleID(), access, name, tag_type_kind,
lldb::eLanguageTypeC_plus_plus, &metadata);
assert(clang_type.IsValid());
auto record_decl =
m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
assert(record_decl);
m_uid_to_decl[type.getSymIndexId()] = record_decl;
auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit(
m_ast.getASTContext(), GetMSInheritance(*udt));
record_decl->addAttr(inheritance_attr);
TypeSystemClang::StartTagDeclarationDefinition(clang_type);
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.
TypeSystemClang::CompleteTagDeclarationDefinition(clang_type);
TypeSystemClang::SetHasExternalStorage(clang_type.GetOpaqueQualType(),
false);
type_resolve_state = Type::ResolveState::Full;
} else {
// Add the type to the forward declarations. It will help us to avoid
// an endless recursion in CompleteTypeFromUdt function.
m_forward_decl_to_uid[record_decl] = type.getSymIndexId();
TypeSystemClang::SetHasExternalStorage(clang_type.GetOpaqueQualType(),
true);
type_resolve_state = Type::ResolveState::Forward;
}
} else
type_resolve_state = Type::ResolveState::Forward;
if (udt->isConstType())
clang_type = clang_type.AddConstModifier();
if (udt->isVolatileType())
clang_type = clang_type.AddVolatileModifier();
GetDeclarationForSymbol(type, decl);
return std::make_shared<lldb_private::Type>(
type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name),
udt->getLength(), nullptr, LLDB_INVALID_UID,
lldb_private::Type::eEncodingIsUID, decl, clang_type,
type_resolve_state);
} break;
case PDB_SymType::Enum: {
auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
assert(enum_type);
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(enum_type->getName()));
auto decl_context = GetDeclContextContainingSymbol(type);
uint64_t bytes = enum_type->getLength();
// Check if such an enum already exists in the current context
CompilerType ast_enum = m_ast.GetTypeForIdentifier<clang::EnumDecl>(
ConstString(name), decl_context);
if (!ast_enum.IsValid()) {
auto underlying_type_up = enum_type->getUnderlyingType();
if (!underlying_type_up)
return nullptr;
lldb::Encoding encoding =
TranslateBuiltinEncoding(underlying_type_up->getBuiltinType());
// FIXME: Type of underlying builtin is always `Int`. We correct it with
// the very first enumerator's encoding if any.
auto first_child = enum_type->findOneChild<PDBSymbolData>();
if (first_child)
encoding = TranslateEnumEncoding(first_child->getValue().Type);
CompilerType builtin_type;
if (bytes > 0)
builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize(
m_ast, *underlying_type_up, encoding, bytes * 8);
else
builtin_type = m_ast.GetBasicType(eBasicTypeInt);
// FIXME: PDB does not have information about scoped enumeration (Enum
// Class). Set it false for now.
bool isScoped = false;
ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context,
OptionalClangModuleID(), decl,
builtin_type, isScoped);
auto enum_decl = TypeSystemClang::GetAsEnumDecl(ast_enum);
assert(enum_decl);
m_uid_to_decl[type.getSymIndexId()] = enum_decl;
auto enum_values = enum_type->findAllChildren<PDBSymbolData>();
if (enum_values) {
while (auto enum_value = enum_values->getNext()) {
if (enum_value->getDataKind() != PDB_DataKind::Constant)
continue;
AddEnumValue(ast_enum, *enum_value);
}
}
if (TypeSystemClang::StartTagDeclarationDefinition(ast_enum))
TypeSystemClang::CompleteTagDeclarationDefinition(ast_enum);
}
if (enum_type->isConstType())
ast_enum = ast_enum.AddConstModifier();
if (enum_type->isVolatileType())
ast_enum = ast_enum.AddVolatileModifier();
GetDeclarationForSymbol(type, decl);
return std::make_shared<lldb_private::Type>(
type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes,
nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
ast_enum, lldb_private::Type::ResolveState::Full);
} break;
case PDB_SymType::Typedef: {
auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type);
assert(type_def);
lldb_private::Type *target_type =
m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId());
if (!target_type)
return nullptr;
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(type_def->getName()));
auto decl_ctx = GetDeclContextContainingSymbol(type);
// Check if such a typedef already exists in the current context
CompilerType ast_typedef =
m_ast.GetTypeForIdentifier<clang::TypedefNameDecl>(ConstString(name),
decl_ctx);
if (!ast_typedef.IsValid()) {
CompilerType target_ast_type = target_type->GetFullCompilerType();
ast_typedef = target_ast_type.CreateTypedef(
name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0);
if (!ast_typedef)
return nullptr;
auto typedef_decl = TypeSystemClang::GetAsTypedefDecl(ast_typedef);
assert(typedef_decl);
m_uid_to_decl[type.getSymIndexId()] = typedef_decl;
}
if (type_def->isConstType())
ast_typedef = ast_typedef.AddConstModifier();
if (type_def->isVolatileType())
ast_typedef = ast_typedef.AddVolatileModifier();
GetDeclarationForSymbol(type, decl);
llvm::Optional<uint64_t> size;
if (type_def->getLength())
size = type_def->getLength();
return std::make_shared<lldb_private::Type>(
type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name),
size, nullptr, target_type->GetID(),
lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef,
lldb_private::Type::ResolveState::Full);
} break;
case PDB_SymType::Function:
case PDB_SymType::FunctionSig: {
std::string name;
PDBSymbolTypeFunctionSig *func_sig = nullptr;
if (auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(&type)) {
if (pdb_func->isCompilerGenerated())
return nullptr;
auto sig = pdb_func->getSignature();
if (!sig)
return nullptr;
func_sig = sig.release();
// Function type is named.
name = std::string(
MSVCUndecoratedNameParser::DropScope(pdb_func->getName()));
} else if (auto pdb_func_sig =
llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) {
func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig);
} else
llvm_unreachable("Unexpected PDB symbol!");
auto arg_enum = func_sig->getArguments();
uint32_t num_args = arg_enum->getChildCount();
std::vector<CompilerType> arg_list;
bool is_variadic = func_sig->isCVarArgs();
// Drop last variadic argument.
if (is_variadic)
--num_args;
for (uint32_t arg_idx = 0; arg_idx < num_args; arg_idx++) {
auto arg = arg_enum->getChildAtIndex(arg_idx);
if (!arg)
break;
lldb_private::Type *arg_type =
m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId());
// If there's some error looking up one of the dependent types of this
// function signature, bail.
if (!arg_type)
return nullptr;
CompilerType arg_ast_type = arg_type->GetFullCompilerType();
arg_list.push_back(arg_ast_type);
}
lldbassert(arg_list.size() <= num_args);
auto pdb_return_type = func_sig->getReturnType();
lldb_private::Type *return_type =
m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId());
// If there's some error looking up one of the dependent types of this
// function signature, bail.
if (!return_type)
return nullptr;
CompilerType return_ast_type = return_type->GetFullCompilerType();
uint32_t type_quals = 0;
if (func_sig->isConstType())
type_quals |= clang::Qualifiers::Const;
if (func_sig->isVolatileType())
type_quals |= clang::Qualifiers::Volatile;
auto cc = TranslateCallingConvention(func_sig->getCallingConvention());
CompilerType func_sig_ast_type =
m_ast.CreateFunctionType(return_ast_type, arg_list.data(),
arg_list.size(), is_variadic, type_quals, cc);
GetDeclarationForSymbol(type, decl);
return std::make_shared<lldb_private::Type>(
type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name),
llvm::None, nullptr, LLDB_INVALID_UID,
lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type,
lldb_private::Type::ResolveState::Full);
} break;
case PDB_SymType::ArrayType: {
auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type);
assert(array_type);
uint32_t num_elements = array_type->getCount();
uint32_t element_uid = array_type->getElementTypeId();
llvm::Optional<uint64_t> bytes;
if (uint64_t size = array_type->getLength())
bytes = size;
// If array rank > 0, PDB gives the element type at N=0. So element type
// will parsed in the order N=0, N=1,..., N=rank sequentially.
lldb_private::Type *element_type =
m_ast.GetSymbolFile()->ResolveTypeUID(element_uid);
if (!element_type)
return nullptr;
CompilerType element_ast_type = element_type->GetForwardCompilerType();
// If element type is UDT, it needs to be complete.
if (TypeSystemClang::IsCXXClassType(element_ast_type) &&
!element_ast_type.GetCompleteType()) {
if (TypeSystemClang::StartTagDeclarationDefinition(element_ast_type)) {
TypeSystemClang::CompleteTagDeclarationDefinition(element_ast_type);
} else {
// We are not able to start defintion.
return nullptr;
}
}
CompilerType array_ast_type = m_ast.CreateArrayType(
element_ast_type, num_elements, /*is_gnu_vector*/ false);
TypeSP type_sp = std::make_shared<lldb_private::Type>(
array_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(),
bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID,
decl, array_ast_type, lldb_private::Type::ResolveState::Full);
type_sp->SetEncodingType(element_type);
return type_sp;
} break;
case PDB_SymType::BuiltinType: {
auto *builtin_type = llvm::dyn_cast<PDBSymbolTypeBuiltin>(&type);
assert(builtin_type);
PDB_BuiltinType builtin_kind = builtin_type->getBuiltinType();
if (builtin_kind == PDB_BuiltinType::None)
return nullptr;
llvm::Optional<uint64_t> bytes;
if (uint64_t size = builtin_type->getLength())
bytes = size;
Encoding encoding = TranslateBuiltinEncoding(builtin_kind);
CompilerType builtin_ast_type = GetBuiltinTypeForPDBEncodingAndBitSize(
m_ast, *builtin_type, encoding, bytes.getValueOr(0) * 8);
if (builtin_type->isConstType())
builtin_ast_type = builtin_ast_type.AddConstModifier();
if (builtin_type->isVolatileType())
builtin_ast_type = builtin_ast_type.AddVolatileModifier();
auto type_name = GetPDBBuiltinTypeName(*builtin_type, builtin_ast_type);
return std::make_shared<lldb_private::Type>(
builtin_type->getSymIndexId(), m_ast.GetSymbolFile(), type_name, bytes,
nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
builtin_ast_type, lldb_private::Type::ResolveState::Full);
} break;
case PDB_SymType::PointerType: {
auto *pointer_type = llvm::dyn_cast<PDBSymbolTypePointer>(&type);
assert(pointer_type);
Type *pointee_type = m_ast.GetSymbolFile()->ResolveTypeUID(
pointer_type->getPointeeType()->getSymIndexId());
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 = TypeSystemClang::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::ResolveState::Forward);
}
CompilerType pointer_ast_type;
pointer_ast_type = pointee_type->GetFullCompilerType();
if (pointer_type->isReference())
pointer_ast_type = pointer_ast_type.GetLValueReferenceType();
else if (pointer_type->isRValueReference())
pointer_ast_type = pointer_ast_type.GetRValueReferenceType();
else
pointer_ast_type = pointer_ast_type.GetPointerType();
if (pointer_type->isConstType())
pointer_ast_type = pointer_ast_type.AddConstModifier();
if (pointer_type->isVolatileType())
pointer_ast_type = pointer_ast_type.AddVolatileModifier();
if (pointer_type->isRestrictedType())
pointer_ast_type = pointer_ast_type.AddRestrictModifier();
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::ResolveState::Full);
} break;
default:
break;
}
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.
clang::CXXRecordDecl *record_decl =
m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType());
auto uid_it = m_forward_decl_to_uid.find(record_decl);
if (uid_it == m_forward_decl_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_to_uid.erase(uid_it);
TypeSystemClang::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!");
}
}
clang::Decl *
PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
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;
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return nullptr;
// First of all, check if the symbol is a member of a class. Resolve the full
// class type and return the declaration from the cache if so.
auto tag = symbol.getSymTag();
if (tag == PDB_SymType::Data || tag == PDB_SymType::Function) {
const IPDBSession &session = symbol.getSession();
const IPDBRawSymbol &raw = symbol.getRawSymbol();
auto class_parent_id = raw.getClassParentId();
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;
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);
}
if (decl)
m_uid_to_decl[sym_id] = decl;
return decl;
}
}
// If we are here, then the symbol is not belonging to a class and is not
// contained in the cache. So create a declaration for it.
switch (symbol.getSymTag()) {
case PDB_SymType::Data: {
auto data = llvm::dyn_cast<PDBSymbolData>(&symbol);
assert(data);
auto decl_context = GetDeclContextContainingSymbol(symbol);
assert(decl_context);
// May be the current context is a class really, but we haven't found
// any class parent. This happens e.g. in the case of class static
// variables - they has two symbols, one is a child of the class when
// another is a child of the exe. So always complete the parent and use
// an existing declaration if possible.
if (auto parent_decl = llvm::dyn_cast_or_null<clang::TagDecl>(decl_context))
m_ast.GetCompleteDecl(parent_decl);
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(data->getName()));
// Check if the current context already contains the symbol with the name.
clang::Decl *decl =
GetDeclFromContextByName(m_ast.getASTContext(), *decl_context, name);
if (!decl) {
auto type = symbol_file->ResolveTypeUID(data->getTypeId());
if (!type)
return nullptr;
decl = m_ast.CreateVariableDeclaration(
decl_context, OptionalClangModuleID(), name.c_str(),
ClangUtil::GetQualType(type->GetLayoutCompilerType()));
}
m_uid_to_decl[sym_id] = decl;
return decl;
}
case PDB_SymType::Function: {
auto func = llvm::dyn_cast<PDBSymbolFunc>(&symbol);
assert(func);
auto decl_context = GetDeclContextContainingSymbol(symbol);
assert(decl_context);
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(func->getName()));
Type *type = symbol_file->ResolveTypeUID(sym_id);
if (!type)
return nullptr;
auto storage = func->isStatic() ? clang::StorageClass::SC_Static
: clang::StorageClass::SC_None;
auto decl = m_ast.CreateFunctionDeclaration(
decl_context, OptionalClangModuleID(), name,
type->GetForwardCompilerType(), storage, func->hasInlineAttribute());
std::vector<clang::ParmVarDecl *> params;
if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) {
if (std::unique_ptr<ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg>>
arg_enum = sig->findAllChildren<PDBSymbolTypeFunctionArg>()) {
while (std::unique_ptr<PDBSymbolTypeFunctionArg> arg =
arg_enum->getNext()) {
Type *arg_type = symbol_file->ResolveTypeUID(arg->getTypeId());
if (!arg_type)
continue;
clang::ParmVarDecl *param = m_ast.CreateParameterDeclaration(
decl, OptionalClangModuleID(), nullptr,
arg_type->GetForwardCompilerType(), clang::SC_None, true);
if (param)
params.push_back(param);
}
}
}
if (params.size())
m_ast.SetFunctionParameters(decl, params.data(), params.size());
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
Type *type = symbol_file->ResolveTypeUID(sym_id);
if (!type)
return nullptr;
return m_uid_to_decl.lookup(sym_id);
}
}
}
clang::DeclContext *
PDBASTParser::GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol) {
if (symbol.getSymTag() == PDB_SymType::Function) {
clang::DeclContext *result =
llvm::dyn_cast_or_null<clang::FunctionDecl>(GetDeclForSymbol(symbol));
if (result)
m_decl_context_to_uid[result] = symbol.getSymIndexId();
return result;
}
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return nullptr;
auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId());
if (!type)
return nullptr;
clang::DeclContext *result =
m_ast.GetDeclContextForType(type->GetForwardCompilerType());
if (result)
m_decl_context_to_uid[result] = symbol.getSymIndexId();
return result;
}
clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol(
const llvm::pdb::PDBSymbol &symbol) {
auto parent = GetClassOrFunctionParent(symbol);
while (parent) {
if (auto parent_context = GetDeclContextForSymbol(*parent))
return parent_context;
parent = GetClassOrFunctionParent(*parent);
}
// 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).
// TODO: Make clang to emit full names for variables in namespaces
// (as MSVC does)
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)
return m_ast.GetTranslationUnitDecl();
auto global = symbol_file->GetPDBSession().getGlobalScope();
if (!global)
return m_ast.GetTranslationUnitDecl();
bool has_type_or_function_parent = false;
clang::DeclContext *curr_context = m_ast.GetTranslationUnitDecl();
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 = std::string(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, OptionalClangModuleID());
m_parent_to_namespaces[curr_context].insert(namespace_decl);
m_namespaces.insert(namespace_decl);
curr_context = namespace_decl;
}
}
return curr_context;
}
void PDBASTParser::ParseDeclsForDeclContext(
const clang::DeclContext *decl_context) {
auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
if (!symbol_file)
return;
IPDBSession &session = symbol_file->GetPDBSession();
auto symbol_up =
session.getSymbolById(m_decl_context_to_uid.lookup(decl_context));
auto global_up = session.getGlobalScope();
PDBSymbol *symbol;
if (symbol_up)
symbol = symbol_up.get();
else if (global_up)
symbol = global_up.get();
else
return;
if (auto children = symbol->findAllChildren())
while (auto child = children->getNext())
GetDeclForSymbol(*child);
}
clang::NamespaceDecl *
PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent,
llvm::StringRef name) {
NamespacesSet *set;
if (parent) {
auto pit = m_parent_to_namespaces.find(parent);
if (pit == m_parent_to_namespaces.end())
return nullptr;
set = &pit->second;
} else {
set = &m_namespaces;
}
assert(set);
for (clang::NamespaceDecl *namespace_decl : *set)
if (namespace_decl->getName().equals(name))
return namespace_decl;
for (clang::NamespaceDecl *namespace_decl : *set)
if (namespace_decl->isAnonymousNamespace())
return FindNamespaceDecl(namespace_decl, name);
return nullptr;
}
bool PDBASTParser::AddEnumValue(CompilerType enum_type,
const PDBSymbolData &enum_value) {
Declaration decl;
Variant v = enum_value.getValue();
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(enum_value.getName()));
int64_t raw_value;
switch (v.Type) {
case PDB_VariantType::Int8:
raw_value = v.Value.Int8;
break;
case PDB_VariantType::Int16:
raw_value = v.Value.Int16;
break;
case PDB_VariantType::Int32:
raw_value = v.Value.Int32;
break;
case PDB_VariantType::Int64:
raw_value = v.Value.Int64;
break;
case PDB_VariantType::UInt8:
raw_value = v.Value.UInt8;
break;
case PDB_VariantType::UInt16:
raw_value = v.Value.UInt16;
break;
case PDB_VariantType::UInt32:
raw_value = v.Value.UInt32;
break;
case PDB_VariantType::UInt64:
raw_value = v.Value.UInt64;
break;
default:
return false;
}
CompilerType underlying_type = m_ast.GetEnumerationIntegerType(enum_type);
uint32_t byte_size = m_ast.getASTContext().getTypeSize(
ClangUtil::GetQualType(underlying_type));
auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType(
enum_type, decl, name.c_str(), raw_value, byte_size * 8);
if (!enum_constant_decl)
return false;
m_uid_to_decl[enum_value.getSymIndexId()] = enum_constant_decl;
return true;
}
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());
TypeSystemClang::BuildIndirectFields(compiler_type);
TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
clang::CXXRecordDecl *record_decl =
m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType());
if (!record_decl)
return static_cast<bool>(compiler_type);
GetClangASTImporter().SetRecordLayout(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) {
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 (TypeSystemClang::StartTagDeclarationDefinition(member_comp_type))
TypeSystemClang::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 = TypeSystemClang::AddFieldToRecordType(
record_type, member_name.c_str(), member_comp_type, access, bit_size);
if (!decl)
continue;
m_uid_to_decl[member->getSymIndexId()] = decl;
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: {
auto decl = TypeSystemClang::AddVariableToRecordType(
record_type, member_name.c_str(), member_comp_type, access);
if (!decl)
continue;
// Static constant members may be a const[expr] declaration.
// Query the symbol's value as the variable initializer if valid.
if (member_comp_type.IsConst()) {
auto value = member->getValue();
clang::QualType qual_type = decl->getType();
unsigned type_width = m_ast.getASTContext().getIntWidth(qual_type);
unsigned constant_width = value.getBitWidth();
if (qual_type->isIntegralOrEnumerationType()) {
if (type_width >= constant_width) {
TypeSystemClang::SetIntegerInitializerForVariable(
decl, value.toAPSInt().extOrTrunc(type_width));
} else {
LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST),
"Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
"which resolves to a wider constant value ({4} bits). "
"Ignoring constant.",
record_type.GetTypeName(), member_name,
member_comp_type.GetTypeName(), type_width,
constant_width);
}
} else {
switch (member_comp_type.GetBasicTypeEnumeration()) {
case lldb::eBasicTypeFloat:
case lldb::eBasicTypeDouble:
case lldb::eBasicTypeLongDouble:
if (type_width == constant_width) {
TypeSystemClang::SetFloatingInitializerForVariable(
decl, value.toAPFloat());
decl->setConstexpr(true);
} else {
LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST),
"Class '{0}' has a member '{1}' of type '{2}' ({3} "
"bits) which resolves to a constant value of mismatched "
"width ({4} bits). Ignoring constant.",
record_type.GetTypeName(), member_name,
member_comp_type.GetTypeName(), type_width,
constant_width);
}
break;
default:
break;
}
}
}
m_uid_to_decl[member->getSymIndexId()] = decl;
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<std::unique_ptr<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 (TypeSystemClang::StartTagDeclarationDefinition(base_comp_type))
TypeSystemClang::CompleteTagDeclarationDefinition(base_comp_type);
}
auto access = TranslateMemberAccess(base->getAccess());
auto is_virtual = base->isVirtualBaseClass();
std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
m_ast.CreateBaseClassSpecifier(base_comp_type.GetOpaqueQualType(),
access, is_virtual,
record_kind == clang::TTK_Class);
lldbassert(base_spec);
base_classes.push_back(std::move(base_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));
}
m_ast.TransferBaseClasses(record_type.GetOpaqueQualType(),
std::move(base_classes));
}
void PDBASTParser::AddRecordMethods(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
PDBFuncSymbolEnumerator &methods_enum) {
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;
}
clang::CXXMethodDecl *
PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file,
lldb_private::CompilerType &record_type,
const llvm::pdb::PDBSymbolFunc &method) const {
std::string name =
std::string(MSVCUndecoratedNameParser::DropScope(method.getName()));
Type *method_type = symbol_file.ResolveTypeUID(method.getSymIndexId());
// MSVC specific __vecDelDtor.
if (!method_type)
return nullptr;
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 (TypeSystemClang::StartTagDeclarationDefinition(method_comp_type))
TypeSystemClang::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());
}