1 //===-- UdtRecordCompleter.h ------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
10 #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
11 
12 #include "PdbAstBuilder.h"
13 #include "PdbSymUid.h"
14 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
15 #include "llvm/DebugInfo/CodeView/CVRecord.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
17 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
18 #include <optional>
19 
20 namespace clang {
21 class CXXBaseSpecifier;
22 class QualType;
23 class TagDecl;
24 } // namespace clang
25 
26 namespace llvm {
27 namespace pdb {
28 class TpiStream;
29 class GlobalsStream;
30 }
31 } // namespace llvm
32 
33 namespace lldb_private {
34 class Type;
35 class CompilerType;
36 namespace npdb {
37 class PdbAstBuilder;
38 class PdbIndex;
39 
40 class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
41   using IndexedBase =
42       std::pair<uint64_t, std::unique_ptr<clang::CXXBaseSpecifier>>;
43 
44   union UdtTagRecord {
45     UdtTagRecord() {}
46     llvm::codeview::UnionRecord ur;
47     llvm::codeview::ClassRecord cr;
48     llvm::codeview::EnumRecord er;
49   } m_cvr;
50 
51   PdbTypeSymId m_id;
52   CompilerType &m_derived_ct;
53   clang::TagDecl &m_tag_decl;
54   PdbAstBuilder &m_ast_builder;
55   PdbIndex &m_index;
56   std::vector<IndexedBase> m_bases;
57   ClangASTImporter::LayoutInfo m_layout;
58   llvm::DenseMap<clang::Decl *, DeclStatus> &m_decl_to_status;
59   llvm::DenseMap<lldb::opaque_compiler_type_t,
60                  llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
61       &m_cxx_record_map;
62 
63 public:
64   UdtRecordCompleter(
65       PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
66       PdbAstBuilder &ast_builder, PdbIndex &index,
67       llvm::DenseMap<clang::Decl *, DeclStatus> &decl_to_status,
68       llvm::DenseMap<lldb::opaque_compiler_type_t,
69                      llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>,
70                                     8>> &cxx_record_map);
71 
72 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
73   llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR,            \
74                                llvm::codeview::Name##Record &Record) override;
75 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
76 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
77 
78   struct Member;
79   using MemberUP = std::unique_ptr<Member>;
80 
81   struct Member {
82     enum Kind { Field, Struct, Union } kind;
83     // Following are only used for field.
84     llvm::StringRef name;
85     uint64_t bit_offset;
86     uint64_t bit_size;
87     clang::QualType qt;
88     lldb::AccessType access;
89     uint32_t bitfield_width;
90     // Following are Only used for struct or union.
91     uint64_t base_offset;
92     llvm::SmallVector<MemberUP, 1> fields;
93 
94     Member() = default;
95     Member(Kind kind)
96         : kind(kind), name(), bit_offset(0), bit_size(0), qt(),
97           access(lldb::eAccessPublic), bitfield_width(0), base_offset(0) {}
98     Member(llvm::StringRef name, uint64_t bit_offset, uint64_t bit_size,
99            clang::QualType qt, lldb::AccessType access, uint32_t bitfield_width)
100         : kind(Field), name(name), bit_offset(bit_offset), bit_size(bit_size),
101           qt(qt), access(access), bitfield_width(bitfield_width),
102           base_offset(0) {}
103     void ConvertToStruct() {
104       kind = Struct;
105       base_offset = bit_offset;
106       fields.push_back(std::make_unique<Member>(name, bit_offset, bit_size, qt,
107                                                 access, bitfield_width));
108       name = llvm::StringRef();
109       qt = clang::QualType();
110       access = lldb::eAccessPublic;
111       bit_offset = bit_size = bitfield_width = 0;
112     }
113   };
114 
115   struct Record {
116     // Top level record.
117     Member record;
118     uint64_t start_offset = UINT64_MAX;
119     std::map<uint64_t, llvm::SmallVector<MemberUP, 1>> fields_map;
120     void CollectMember(llvm::StringRef name, uint64_t offset,
121                        uint64_t field_size, clang::QualType qt,
122                        lldb::AccessType access, uint64_t bitfield_width);
123     void ConstructRecord();
124   };
125   void complete();
126 
127 private:
128   Record m_record;
129   clang::QualType AddBaseClassForTypeIndex(
130       llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
131       std::optional<uint64_t> vtable_idx = std::optional<uint64_t>());
132   void AddMethod(llvm::StringRef name, llvm::codeview::TypeIndex type_idx,
133                  llvm::codeview::MemberAccess access,
134                  llvm::codeview::MethodOptions options,
135                  llvm::codeview::MemberAttributes attrs);
136   void FinishRecord();
137   uint64_t AddMember(TypeSystemClang &clang, Member *field, uint64_t bit_offset,
138                      CompilerType parent_ct,
139                      ClangASTImporter::LayoutInfo &parent_layout,
140                      clang::DeclContext *decl_ctx);
141 };
142 
143 } // namespace npdb
144 } // namespace lldb_private
145 
146 #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
147