296 lines · cpp
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-exception6//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 14using namespace lldb_private::npdb;15using namespace llvm;16 17namespace {18using Member = UdtRecordCompleter::Member;19using MemberUP = std::unique_ptr<Member>;20using Record = UdtRecordCompleter::Record;21 22class WrappedMember {23public:24 WrappedMember(const Member &obj) : m_obj(obj) {}25 26private:27 const Member &m_obj;28 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 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 55class WrappedRecord {56public:57 WrappedRecord(const Record &obj) : m_obj(obj) {}58 59private:60 const Record &m_obj;61 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 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 83class UdtRecordCompleterRecordTests : public testing::Test {84protected:85 Record record;86 87public: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);92 }93 void ConstructRecord() { record.ConstructRecord(); }94};95Member *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 * 8;103 member->fields.push_back(std::move(field));104 return member->fields.back().get();105}106} // namespace107 108TEST_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 CollectMember("m5", 8, 8);115 CollectMember("m6", 16, 4);116 CollectMember("m7", 16, 8);117 ConstructRecord();118 119 // struct {120 // union {121 // m1;122 // m2;123 // m3;124 // m4;125 // };126 // m5;127 // union {128 // m6;129 // m7;130 // };131 // };132 Record record;133 record.start_offset = 0;134 Member *u = AddField(&record.record, "", 0, 0, Member::Union);135 AddField(u, "m1", 0, 4, Member::Field);136 AddField(u, "m2", 0, 4, Member::Field);137 AddField(u, "m3", 0, 1, Member::Field);138 AddField(u, "m4", 0, 8, Member::Field);139 AddField(&record.record, "m5", 8, 8, Member::Field);140 Member *u2 = AddField(&record.record, "", 16, 0, Member::Union);141 AddField(u2, "m6", 16, 4, Member::Field);142 AddField(u2, "m7", 16, 8, Member::Field);143 EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));144}145 146TEST_F(UdtRecordCompleterRecordTests, TestAnonymousUnionInUnion) {147 SetKind(Member::Kind::Union);148 CollectMember("m1", 0, 4);149 CollectMember("m2", 0, 4);150 CollectMember("m3", 0, 1);151 CollectMember("m4", 0, 8);152 ConstructRecord();153 154 // union {155 // m1;156 // m2;157 // m3;158 // m4;159 // };160 Record record;161 record.start_offset = 0;162 AddField(&record.record, "m1", 0, 4, Member::Field);163 AddField(&record.record, "m2", 0, 4, Member::Field);164 AddField(&record.record, "m3", 0, 1, Member::Field);165 AddField(&record.record, "m4", 0, 8, Member::Field);166 EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));167}168 169TEST_F(UdtRecordCompleterRecordTests, TestAnonymousStructInUnion) {170 SetKind(Member::Kind::Union);171 CollectMember("m1", 0, 4);172 CollectMember("m2", 4, 4);173 CollectMember("m3", 8, 1);174 ConstructRecord();175 176 // union {177 // struct {178 // m1;179 // m2;180 // m3;181 // };182 // };183 Record record;184 record.start_offset = 0;185 Member *s = AddField(&record.record, "", 0, 0, Member::Kind::Struct);186 AddField(s, "m1", 0, 4, Member::Field);187 AddField(s, "m2", 4, 4, Member::Field);188 AddField(s, "m3", 8, 1, Member::Field);189 EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));190}191 192TEST_F(UdtRecordCompleterRecordTests, TestNestedUnionStructInStruct) {193 SetKind(Member::Kind::Struct);194 CollectMember("m1", 0, 4);195 CollectMember("m2", 0, 2);196 CollectMember("m3", 0, 2);197 CollectMember("m4", 2, 4);198 CollectMember("m5", 3, 2);199 ConstructRecord();200 201 // struct {202 // union {203 // m1;204 // struct {205 // m2;206 // m5;207 // };208 // struct {209 // m3;210 // m4;211 // };212 // };213 // };214 Record record;215 record.start_offset = 0;216 Member *u = AddField(&record.record, "", 0, 0, Member::Union);217 AddField(u, "m1", 0, 4, Member::Field);218 Member *s1 = AddField(u, "", 0, 0, Member::Struct);219 Member *s2 = AddField(u, "", 0, 0, Member::Struct);220 AddField(s1, "m2", 0, 2, Member::Field);221 AddField(s1, "m5", 3, 2, Member::Field);222 AddField(s2, "m3", 0, 2, Member::Field);223 AddField(s2, "m4", 2, 4, Member::Field);224 EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));225}226 227TEST_F(UdtRecordCompleterRecordTests, TestNestedUnionStructInUnion) {228 SetKind(Member::Kind::Union);229 CollectMember("m1", 0, 4);230 CollectMember("m2", 0, 2);231 CollectMember("m3", 0, 2);232 CollectMember("m4", 2, 4);233 CollectMember("m5", 3, 2);234 ConstructRecord();235 236 // union {237 // m1;238 // struct {239 // m2;240 // m5;241 // };242 // struct {243 // m3;244 // m4;245 // };246 // };247 Record record;248 record.start_offset = 0;249 AddField(&record.record, "m1", 0, 4, Member::Field);250 Member *s1 = AddField(&record.record, "", 0, 0, Member::Struct);251 Member *s2 = AddField(&record.record, "", 0, 0, Member::Struct);252 AddField(s1, "m2", 0, 2, Member::Field);253 AddField(s1, "m5", 3, 2, Member::Field);254 AddField(s2, "m3", 0, 2, Member::Field);255 AddField(s2, "m4", 2, 4, Member::Field);256 EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));257}258 259TEST_F(UdtRecordCompleterRecordTests, TestNestedStructInUnionInStructInUnion) {260 SetKind(Member::Kind::Union);261 CollectMember("m1", 0, 4);262 CollectMember("m2", 0, 2);263 CollectMember("m3", 0, 2);264 CollectMember("m4", 2, 4);265 CollectMember("m5", 6, 2);266 CollectMember("m6", 6, 2);267 CollectMember("m7", 8, 2);268 ConstructRecord();269 270 // union {271 // m1;272 // m2;273 // struct {274 // m3;275 // m4;276 // union {277 // m5;278 // m6;279 // };280 // m7;281 // };282 // };283 Record record;284 record.start_offset = 0;285 AddField(&record.record, "m1", 0, 4, Member::Field);286 AddField(&record.record, "m2", 0, 2, Member::Field);287 Member *s = AddField(&record.record, "", 0, 0, Member::Struct);288 AddField(s, "m3", 0, 2, Member::Field);289 AddField(s, "m4", 2, 4, Member::Field);290 Member *u = AddField(s, "", 6, 0, Member::Union);291 AddField(u, "m5", 6, 2, Member::Field);292 AddField(u, "m6", 6, 2, Member::Field);293 AddField(s, "m7", 8, 2, Member::Field);294 EXPECT_EQ(WrappedRecord(this->record), WrappedRecord(record));295}296