1 //===-- UdtRecordCompleterTests.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
14 using namespace lldb_private::npdb
;
18 using Member
= UdtRecordCompleter::Member
;
19 using MemberUP
= std::unique_ptr
<Member
>;
20 using Record
= UdtRecordCompleter::Record
;
24 WrappedMember(const Member
&obj
) : m_obj(obj
) {}
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
);
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
);
57 WrappedRecord(const Record
&obj
) : m_obj(obj
) {}
62 friend bool operator==(const WrappedRecord
&lhs
, const WrappedRecord
&rhs
) {
63 return lhs
.m_obj
.start_offset
== rhs
.m_obj
.start_offset
&&
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
);
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
);
83 class UdtRecordCompleterRecordTests
: public testing::Test
{
88 void SetKind(Member::Kind kind
) { record
.record
.kind
= kind
; }
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);
93 void ConstructRecord() { record
.ConstructRecord(); }
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) {
99 std::make_unique
<Member
>(name
, byte_offset
* 8, byte_size
* 8,
100 clang::QualType(), lldb::eAccessPublic
, 0);
102 field
->base_offset
= base_offset
;
103 member
->fields
.push_back(std::move(field
));
104 return member
->fields
.back().get();
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);
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
));
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);
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
));
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);
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
));
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);
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
));
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);
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
));