xref: /llvm-project/lldb/unittests/SymbolFile/NativePDB/UdtRecordCompleterTests.cpp (revision 3ff3af3086da5df10d3991914262cef724156977)
1 //===-- UdtRecordCompleterTests.cpp ---------------------------------------===//
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 #include "Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 
14 using namespace lldb_private::npdb;
15 using namespace llvm;
16 
17 namespace {
18 using Member = UdtRecordCompleter::Member;
19 using MemberUP = std::unique_ptr<Member>;
20 using Record = UdtRecordCompleter::Record;
21 
22 class WrappedMember {
23 public:
WrappedMember(const Member & obj)24   WrappedMember(const Member &obj) : m_obj(obj) {}
25 
26 private:
27   const Member &m_obj;
28 
operator ==(const WrappedMember & lhs,const WrappedMember & rhs)29   friend bool operator==(const WrappedMember &lhs, const WrappedMember &rhs) {
30     return lhs.m_obj.kind == rhs.m_obj.kind &&
31            lhs.m_obj.name == rhs.m_obj.name &&
32            lhs.m_obj.bit_offset == rhs.m_obj.bit_offset &&
33            lhs.m_obj.bit_size == rhs.m_obj.bit_size &&
34            lhs.m_obj.base_offset == rhs.m_obj.base_offset &&
35            std::equal(lhs.m_obj.fields.begin(), lhs.m_obj.fields.end(),
36                       rhs.m_obj.fields.begin(), rhs.m_obj.fields.end(),
37                       [](const MemberUP &lhs, const MemberUP &rhs) {
38                         return WrappedMember(*lhs) == WrappedMember(*rhs);
39                       });
40   }
41 
operator <<(llvm::raw_ostream & os,const WrappedMember & w)42   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
43                                        const WrappedMember &w) {
44     os << llvm::formatv("Member{.kind={0}, .name=\"{1}\", .bit_offset={2}, "
45                         ".bit_size={3}, .base_offset={4}, .fields=[",
46                         w.m_obj.kind, w.m_obj.name, w.m_obj.bit_offset,
47                         w.m_obj.bit_size, w.m_obj.base_offset);
48     llvm::ListSeparator sep;
49     for (auto &f : w.m_obj.fields)
50       os << sep << WrappedMember(*f);
51     return os << "]}";
52   }
53 };
54 
55 class WrappedRecord {
56 public:
WrappedRecord(const Record & obj)57   WrappedRecord(const Record &obj) : m_obj(obj) {}
58 
59 private:
60   const Record &m_obj;
61 
operator ==(const WrappedRecord & lhs,const WrappedRecord & rhs)62   friend bool operator==(const WrappedRecord &lhs, const WrappedRecord &rhs) {
63     return lhs.m_obj.start_offset == rhs.m_obj.start_offset &&
64            std::equal(
65                lhs.m_obj.record.fields.begin(), lhs.m_obj.record.fields.end(),
66                rhs.m_obj.record.fields.begin(), rhs.m_obj.record.fields.end(),
67                [](const MemberUP &lhs, const MemberUP &rhs) {
68                  return WrappedMember(*lhs) == WrappedMember(*rhs);
69                });
70   }
71 
operator <<(llvm::raw_ostream & os,const WrappedRecord & w)72   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
73                                        const WrappedRecord &w) {
74     os << llvm::formatv("Record{.start_offset={0}, .record.fields=[",
75                         w.m_obj.start_offset);
76     llvm::ListSeparator sep;
77     for (const MemberUP &f : w.m_obj.record.fields)
78       os << sep << WrappedMember(*f);
79     return os << "]}";
80   }
81 };
82 
83 class UdtRecordCompleterRecordTests : public testing::Test {
84 protected:
85   Record record;
86 
87 public:
SetKind(Member::Kind kind)88   void SetKind(Member::Kind kind) { record.record.kind = kind; }
CollectMember(StringRef name,uint64_t byte_offset,uint64_t byte_size)89   void CollectMember(StringRef name, uint64_t byte_offset, uint64_t byte_size) {
90     record.CollectMember(name, byte_offset * 8, byte_size * 8,
91                          clang::QualType(), lldb::eAccessPublic, 0);
92   }
ConstructRecord()93   void ConstructRecord() { record.ConstructRecord(); }
94 };
AddField(Member * member,StringRef name,uint64_t byte_offset,uint64_t byte_size,Member::Kind kind,uint64_t base_offset=0)95 Member *AddField(Member *member, StringRef name, uint64_t byte_offset,
96                  uint64_t byte_size, Member::Kind kind,
97                  uint64_t base_offset = 0) {
98   auto field =
99       std::make_unique<Member>(name, byte_offset * 8, byte_size * 8,
100                                clang::QualType(), lldb::eAccessPublic, 0);
101   field->kind = kind;
102   field->base_offset = base_offset;
103   member->fields.push_back(std::move(field));
104   return member->fields.back().get();
105 }
106 } // namespace
107 
TEST_F(UdtRecordCompleterRecordTests,TestAnonymousUnionInStruct)108 TEST_F(UdtRecordCompleterRecordTests, TestAnonymousUnionInStruct) {
109   SetKind(Member::Kind::Struct);
110   CollectMember("m1", 0, 4);
111   CollectMember("m2", 0, 4);
112   CollectMember("m3", 0, 1);
113   CollectMember("m4", 0, 8);
114   ConstructRecord();
115 
116   // struct {
117   //   union {
118   //       m1;
119   //       m2;
120   //       m3;
121   //       m4;
122   //   };
123   // };
124   Record record;
125   record.start_offset = 0;
126   Member *u = AddField(&record.record, "", 0, 0, Member::Union);
127   AddField(u, "m1", 0, 4, Member::Field);
128   AddField(u, "m2", 0, 4, Member::Field);
129   AddField(u, "m3", 0, 1, Member::Field);
130   AddField(u, "m4", 0, 8, Member::Field);
131   EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));
132 }
133 
TEST_F(UdtRecordCompleterRecordTests,TestAnonymousUnionInUnion)134 TEST_F(UdtRecordCompleterRecordTests, TestAnonymousUnionInUnion) {
135   SetKind(Member::Kind::Union);
136   CollectMember("m1", 0, 4);
137   CollectMember("m2", 0, 4);
138   CollectMember("m3", 0, 1);
139   CollectMember("m4", 0, 8);
140   ConstructRecord();
141 
142   // union {
143   //   m1;
144   //   m2;
145   //   m3;
146   //   m4;
147   // };
148   Record record;
149   record.start_offset = 0;
150   AddField(&record.record, "m1", 0, 4, Member::Field);
151   AddField(&record.record, "m2", 0, 4, Member::Field);
152   AddField(&record.record, "m3", 0, 1, Member::Field);
153   AddField(&record.record, "m4", 0, 8, Member::Field);
154   EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));
155 }
156 
TEST_F(UdtRecordCompleterRecordTests,TestAnonymousStructInUnion)157 TEST_F(UdtRecordCompleterRecordTests, TestAnonymousStructInUnion) {
158   SetKind(Member::Kind::Union);
159   CollectMember("m1", 0, 4);
160   CollectMember("m2", 4, 4);
161   CollectMember("m3", 8, 1);
162   ConstructRecord();
163 
164   // union {
165   //   struct {
166   //     m1;
167   //     m2;
168   //     m3;
169   //   };
170   // };
171   Record record;
172   record.start_offset = 0;
173   Member *s = AddField(&record.record, "", 0, 0, Member::Kind::Struct);
174   AddField(s, "m1", 0, 4, Member::Field);
175   AddField(s, "m2", 4, 4, Member::Field);
176   AddField(s, "m3", 8, 1, Member::Field);
177   EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));
178 }
179 
TEST_F(UdtRecordCompleterRecordTests,TestNestedUnionStructInStruct)180 TEST_F(UdtRecordCompleterRecordTests, TestNestedUnionStructInStruct) {
181   SetKind(Member::Kind::Struct);
182   CollectMember("m1", 0, 4);
183   CollectMember("m2", 0, 2);
184   CollectMember("m3", 0, 2);
185   CollectMember("m4", 2, 4);
186   CollectMember("m5", 3, 2);
187   ConstructRecord();
188 
189   // struct {
190   //   union {
191   //       m1;
192   //       struct {
193   //           m2;
194   //           m5;
195   //       };
196   //       struct {
197   //           m3;
198   //           m4;
199   //       };
200   //   };
201   // };
202   Record record;
203   record.start_offset = 0;
204   Member *u = AddField(&record.record, "", 0, 0, Member::Union);
205   AddField(u, "m1", 0, 4, Member::Field);
206   Member *s1 = AddField(u, "", 0, 0, Member::Struct);
207   Member *s2 = AddField(u, "", 0, 0, Member::Struct);
208   AddField(s1, "m2", 0, 2, Member::Field);
209   AddField(s1, "m5", 3, 2, Member::Field);
210   AddField(s2, "m3", 0, 2, Member::Field);
211   AddField(s2, "m4", 2, 4, Member::Field);
212   EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));
213 }
214 
TEST_F(UdtRecordCompleterRecordTests,TestNestedUnionStructInUnion)215 TEST_F(UdtRecordCompleterRecordTests, TestNestedUnionStructInUnion) {
216   SetKind(Member::Kind::Union);
217   CollectMember("m1", 0, 4);
218   CollectMember("m2", 0, 2);
219   CollectMember("m3", 0, 2);
220   CollectMember("m4", 2, 4);
221   CollectMember("m5", 3, 2);
222   ConstructRecord();
223 
224   // union {
225   //   m1;
226   //   struct {
227   //       m2;
228   //       m5;
229   //   };
230   //   struct {
231   //       m3;
232   //       m4;
233   //   };
234   // };
235   Record record;
236   record.start_offset = 0;
237   AddField(&record.record, "m1", 0, 4, Member::Field);
238   Member *s1 = AddField(&record.record, "", 0, 0, Member::Struct);
239   Member *s2 = AddField(&record.record, "", 0, 0, Member::Struct);
240   AddField(s1, "m2", 0, 2, Member::Field);
241   AddField(s1, "m5", 3, 2, Member::Field);
242   AddField(s2, "m3", 0, 2, Member::Field);
243   AddField(s2, "m4", 2, 4, Member::Field);
244   EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));
245 }
246