1#include "UdtRecordCompleter.h"
2
3#include "PdbAstBuilder.h"
4#include "PdbIndex.h"
5#include "PdbSymUid.h"
6#include "PdbUtil.h"
7
8#include "lldb/Symbol/ClangASTContext.h"
9#include "lldb/Symbol/ClangASTImporter.h"
10#include "lldb/Symbol/Type.h"
11#include "lldb/Utility/LLDBAssert.h"
12#include "lldb/lldb-enumerations.h"
13#include "lldb/lldb-forward.h"
14
15#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
16#include "llvm/DebugInfo/CodeView/TypeIndex.h"
17#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
18#include "llvm/DebugInfo/PDB/PDBTypes.h"
19
20using namespace llvm::codeview;
21using namespace llvm::pdb;
22using namespace lldb;
23using namespace lldb_private;
24using namespace lldb_private::npdb;
25
26using Error = llvm::Error;
27
28UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id,
29                                       CompilerType &derived_ct,
30                                       clang::TagDecl &tag_decl,
31                                       PdbAstBuilder &ast_builder,
32                                       TpiStream &tpi)
33    : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
34      m_ast_builder(ast_builder), m_tpi(tpi) {
35  CVType cvt = m_tpi.getType(m_id.index);
36  switch (cvt.kind()) {
37  case LF_ENUM:
38    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
39    break;
40  case LF_UNION:
41    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
42    break;
43  case LF_CLASS:
44  case LF_STRUCTURE:
45    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
46    break;
47  default:
48    llvm_unreachable("unreachable!");
49  }
50}
51
52clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
53    llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
54    llvm::Optional<uint64_t> vtable_idx) {
55  PdbTypeSymId type_id(ti);
56  clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
57
58  CVType udt_cvt = m_tpi.getType(ti);
59
60  std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
61      m_ast_builder.clang().CreateBaseClassSpecifier(
62          qt.getAsOpaquePtr(), TranslateMemberAccess(access),
63          vtable_idx.hasValue(), udt_cvt.kind() == LF_CLASS);
64  lldbassert(base_spec);
65
66  m_bases.push_back(
67      std::make_pair(vtable_idx.getValueOr(0), std::move(base_spec)));
68
69  return qt;
70}
71
72void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
73                                   MemberAccess access, MethodOptions options,
74                                   MemberAttributes attrs) {
75  clang::QualType method_qt =
76      m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
77  m_ast_builder.CompleteType(method_qt);
78
79  lldb::AccessType access_type = TranslateMemberAccess(access);
80  bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
81                       MethodOptions::CompilerGenerated;
82  m_ast_builder.clang().AddMethodToCXXRecordType(
83      m_derived_ct.GetOpaqueQualType(), name.data(), nullptr,
84      m_ast_builder.ToCompilerType(method_qt), access_type, attrs.isVirtual(),
85      attrs.isStatic(), false, false, false, is_artificial);
86}
87
88Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
89                                           BaseClassRecord &base) {
90  clang::QualType base_qt =
91      AddBaseClassForTypeIndex(base.Type, base.getAccess());
92
93  auto decl =
94      m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr());
95  lldbassert(decl);
96
97  auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
98  m_layout.base_offsets.insert(std::make_pair(decl, offset));
99
100  return llvm::Error::success();
101}
102
103Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
104                                           VirtualBaseClassRecord &base) {
105  AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex);
106
107  return Error::success();
108}
109
110Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
111                                           ListContinuationRecord &cont) {
112  return Error::success();
113}
114
115Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
116                                           VFPtrRecord &vfptr) {
117  return Error::success();
118}
119
120Error UdtRecordCompleter::visitKnownMember(
121    CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
122  clang::QualType member_type =
123      m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type));
124
125  m_ast_builder.CompleteType(member_type);
126
127  CompilerType member_ct = m_ast_builder.ToCompilerType(member_type);
128
129  lldb::AccessType access =
130      TranslateMemberAccess(static_data_member.getAccess());
131  ClangASTContext::AddVariableToRecordType(
132      m_derived_ct, static_data_member.Name, member_ct, access);
133
134  // FIXME: Add a PdbSymUid namespace for field list members and update
135  // the m_uid_to_decl map with this decl.
136  return Error::success();
137}
138
139Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
140                                           NestedTypeRecord &nested) {
141  return Error::success();
142}
143
144Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
145                                           DataMemberRecord &data_member) {
146
147  uint64_t offset = data_member.FieldOffset * 8;
148  uint32_t bitfield_width = 0;
149
150  TypeIndex ti(data_member.Type);
151  if (!ti.isSimple()) {
152    CVType cvt = m_tpi.getType(ti);
153    if (cvt.kind() == LF_BITFIELD) {
154      BitFieldRecord bfr;
155      llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
156      offset += bfr.BitOffset;
157      bitfield_width = bfr.BitSize;
158      ti = bfr.Type;
159    }
160  }
161
162  clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti));
163  m_ast_builder.CompleteType(member_qt);
164
165  lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
166
167  clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
168      m_derived_ct, data_member.Name, m_ast_builder.ToCompilerType(member_qt),
169      access, bitfield_width);
170  // FIXME: Add a PdbSymUid namespace for field list members and update
171  // the m_uid_to_decl map with this decl.
172
173  m_layout.field_offsets.insert(std::make_pair(decl, offset));
174
175  return Error::success();
176}
177
178Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
179                                           OneMethodRecord &one_method) {
180  AddMethod(one_method.Name, one_method.Type, one_method.getAccess(),
181            one_method.getOptions(), one_method.Attrs);
182
183  return Error::success();
184}
185
186Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
187                                           OverloadedMethodRecord &overloaded) {
188  TypeIndex method_list_idx = overloaded.MethodList;
189
190  CVType method_list_type = m_tpi.getType(method_list_idx);
191  assert(method_list_type.kind() == LF_METHODLIST);
192
193  MethodOverloadListRecord method_list;
194  llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
195      method_list_type, method_list));
196
197  for (const OneMethodRecord &method : method_list.Methods)
198    AddMethod(overloaded.Name, method.Type, method.getAccess(),
199              method.getOptions(), method.Attrs);
200
201  return Error::success();
202}
203
204Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
205                                           EnumeratorRecord &enumerator) {
206  Declaration decl;
207  llvm::StringRef name = DropNameScope(enumerator.getName());
208
209  m_ast_builder.clang().AddEnumerationValueToEnumerationType(
210      m_derived_ct, decl, name.str().c_str(), enumerator.Value);
211  return Error::success();
212}
213
214void UdtRecordCompleter::complete() {
215  // Ensure the correct order for virtual bases.
216  std::stable_sort(m_bases.begin(), m_bases.end(),
217                   [](const IndexedBase &lhs, const IndexedBase &rhs) {
218                     return lhs.first < rhs.first;
219                   });
220
221  std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
222  bases.reserve(m_bases.size());
223  for (auto &ib : m_bases)
224    bases.push_back(std::move(ib.second));
225
226  ClangASTContext &clang = m_ast_builder.clang();
227  clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases));
228
229  clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
230  ClangASTContext::BuildIndirectFields(m_derived_ct);
231  ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
232
233  if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
234    m_ast_builder.importer().SetRecordLayout(record_decl, m_layout);
235  }
236}
237