xref: /llvm-project/lldb/test/API/lang/rust/enum-structs/TestRustEnumStructs.py (revision a4c18137d84bc48df49ee0101bef465a955e62ac)
1"""Test that lldb recognizes enum structs emitted by Rust compiler """
2import logging
3
4import lldb
5from lldbsuite.test.decorators import *
6from lldbsuite.test.lldbtest import *
7from RustEnumValue import RustEnumValue
8
9
10class TestRustEnumStructs(TestBase):
11    def setUp(self):
12        TestBase.setUp(self)
13        src_dir = self.getSourceDir()
14        yaml_path = os.path.join(src_dir, "main.yaml")
15        obj_path = self.getBuildArtifact("main.o")
16        self.yaml2obj(yaml_path, obj_path)
17        self.dbg.CreateTarget(obj_path)
18
19    def getFromGlobal(self, name):
20        values = self.target().FindGlobalVariables(name, 1)
21        self.assertEqual(values.GetSize(), 1)
22        return RustEnumValue(values[0])
23
24    def test_clike_enums_are_represented_correctly(self):
25        # these type of enums are not using DW_TAG_variant_part.
26        all_values = [
27            self.target().FindFirstGlobalVariable("CLIKE_DEFAULT_A").GetValue(),
28            self.target().FindFirstGlobalVariable("CLIKE_DEFAULT_B").GetValue(),
29            self.target().FindFirstGlobalVariable("CLIKE_U8_A").GetValue(),
30            self.target().FindFirstGlobalVariable("CLIKE_U8_C").GetValue(),
31            self.target().FindFirstGlobalVariable("CLIKE_U32_A").GetValue(),
32            self.target().FindFirstGlobalVariable("CLIKE_U32_B").GetValue(),
33        ]
34        self.assertEqual(
35            all_values, ["A", "B", "VariantA", "VariantC", "VariantA", "VariantB"]
36        )
37
38    def test_enum_with_tuples_has_all_variants(self):
39        self.assertEqual(
40            self.getFromGlobal("ENUM_WITH_TUPLES_A").getAllVariantTypes(),
41            [
42                "main::EnumWithTuples::A:8",
43                "main::EnumWithTuples::B:8",
44                "main::EnumWithTuples::C:8",
45                "main::EnumWithTuples::D:8",
46                "main::EnumWithTuples::AA:8",
47                "main::EnumWithTuples::BB:8",
48                "main::EnumWithTuples::BC:8",
49                "main::EnumWithTuples::CC:8",
50            ],
51        )
52
53    def test_enum_with_tuples_values_are_correct_a(self):
54        # static ENUM_WITH_TUPLES_A: EnumWithTuples = EnumWithTuples::A(13);
55        self.assertEqual(
56            self.getFromGlobal("ENUM_WITH_TUPLES_A")
57            .getCurrentValue()
58            .GetChildAtIndex(0)
59            .GetData()
60            .GetUnsignedInt8(lldb.SBError(), 0),
61            13,
62        )
63
64    def test_enum_with_tuples_values_are_correct_aa(self):
65        # static ENUM_WITH_TUPLES_AA: EnumWithTuples = EnumWithTuples::AA(13, 37);
66        value = self.getFromGlobal("ENUM_WITH_TUPLES_AA").getCurrentValue()
67        self.assertEqual(
68            (
69                value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0),
70                value.GetChildAtIndex(1).GetData().GetUnsignedInt8(lldb.SBError(), 0),
71            ),
72            (13, 37),
73        )
74
75    def test_enum_with_tuples_values_are_correct_b(self):
76        # static ENUM_WITH_TUPLES_B: EnumWithTuples = EnumWithTuples::B(37);
77        self.assertEqual(
78            self.getFromGlobal("ENUM_WITH_TUPLES_B")
79            .getCurrentValue()
80            .GetChildAtIndex(0)
81            .GetData()
82            .GetUnsignedInt16(lldb.SBError(), 0),
83            37,
84        )
85
86    def test_enum_with_tuples_values_are_correct_bb(self):
87        # static ENUM_WITH_TUPLES_BB: EnumWithTuples = EnumWithTuples::BB(37, 5535);
88        value = self.getFromGlobal("ENUM_WITH_TUPLES_BB").getCurrentValue()
89        self.assertEqual(
90            (
91                value.GetChildAtIndex(0).GetData().GetUnsignedInt16(lldb.SBError(), 0),
92                value.GetChildAtIndex(1).GetData().GetUnsignedInt16(lldb.SBError(), 0),
93            ),
94            (37, 5535),
95        )
96
97    def test_enum_with_tuples_values_are_correct_bc(self):
98        # static ENUM_WITH_TUPLES_BC: EnumWithTuples = EnumWithTuples::BC(65000, 165000);
99        value = self.getFromGlobal("ENUM_WITH_TUPLES_BC").getCurrentValue()
100        self.assertEqual(
101            (
102                value.GetChildAtIndex(0).GetData().GetUnsignedInt16(lldb.SBError(), 0),
103                value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0),
104            ),
105            (65000, 165000),
106        )
107
108    def test_enum_with_tuples_values_are_correct_c(self):
109        # static ENUM_WITH_TUPLES_C: EnumWithTuples = EnumWithTuples::C(31337);
110        self.assertEqual(
111            self.getFromGlobal("ENUM_WITH_TUPLES_C")
112            .getCurrentValue()
113            .GetChildAtIndex(0)
114            .GetData()
115            .GetUnsignedInt32(lldb.SBError(), 0),
116            31337,
117        )
118
119    def test_enum_with_tuples_values_are_correct_cc(self):
120        # static ENUM_WITH_TUPLES_CC: EnumWithTuples = EnumWithTuples::CC(31337, 87236);
121        value = self.getFromGlobal("ENUM_WITH_TUPLES_CC").getCurrentValue()
122        self.assertEqual(
123            (
124                value.GetChildAtIndex(0).GetData().GetUnsignedInt32(lldb.SBError(), 0),
125                value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0),
126            ),
127            (31337, 87236),
128        )
129
130    def test_enum_with_tuples_values_are_correct_d(self):
131        # static ENUM_WITH_TUPLES_D: EnumWithTuples = EnumWithTuples::D(123456789012345678);
132        self.assertEqual(
133            self.getFromGlobal("ENUM_WITH_TUPLES_D")
134            .getCurrentValue()
135            .GetChildAtIndex(0)
136            .GetData()
137            .GetUnsignedInt64(lldb.SBError(), 0),
138            123456789012345678,
139        )
140
141    def test_mixed_enum_variants(self):
142        # static MIXED_ENUM_A: MixedEnum1 = MixedEnum1::A;
143        self.assertEqual(
144            self.getFromGlobal("MIXED_ENUM_A").getAllVariantTypes(),
145            [
146                "main::MixedEnum::A:64",
147                "main::MixedEnum::B:64",
148                "main::MixedEnum::C:64",
149                "main::MixedEnum::D:64",
150                "main::MixedEnum::E:64",
151            ],
152        )
153
154    def test_mixed_enum_a(self):
155        # static MIXED_ENUM_A: MixedEnum = MixedEnum::A;
156        value = self.getFromGlobal("MIXED_ENUM_A").getCurrentValue()
157        self.assertEqual(value.GetType().GetDisplayTypeName(), "main::MixedEnum::A")
158        self.assertEqual(value.GetValue(), None)
159
160    def test_mixed_enum_c(self):
161        # static MIXED_ENUM_C: MixedEnum = MixedEnum::C(254, -254);
162        value = self.getFromGlobal("MIXED_ENUM_C").getCurrentValue()
163        self.assertEqual(
164            (
165                value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0),
166                value.GetChildAtIndex(1).GetData().GetSignedInt32(lldb.SBError(), 0),
167            ),
168            (254, -254),
169        )
170
171    def test_mixed_enum_d_none(self):
172        # static MIXED_ENUM_D_NONE: MixedEnum = MixedEnum::D(None);
173        value = RustEnumValue(
174            self.getFromGlobal("MIXED_ENUM_D_NONE").getCurrentValue().GetChildAtIndex(0)
175        )
176        self.assertEqual(
177            value.getAllVariantTypes(),
178            [
179                "core::option::Option<main::Struct2>::None<main::Struct2>:32",
180                "core::option::Option<main::Struct2>::Some<main::Struct2>:32",
181            ],
182        )
183        self.assertEqual(value.getCurrentValue().GetValue(), None)
184        self.assertEqual(
185            value.getCurrentValue().GetType().GetDisplayTypeName(),
186            "core::option::Option<main::Struct2>::None<main::Struct2>",
187        )
188
189    def test_mixed_enum_d_some(self):
190        # static MIXED_ENUM_D_SOME: MixedEnum = MixedEnum::D(Some(Struct2 {
191        #     field: 123456,
192        #     inner: Struct1 { field: 123 },
193        # }));
194        variant_with_option = RustEnumValue(
195            self.getFromGlobal("MIXED_ENUM_D_SOME").getCurrentValue().GetChildAtIndex(0)
196        )
197
198        value_inside_option = variant_with_option.getCurrentValue().GetChildAtIndex(0)
199        self.assertEqual(
200            value_inside_option.GetChildMemberWithName("field")
201            .GetData()
202            .GetUnsignedInt32(lldb.SBError(), 0),
203            123456,
204        )
205
206        self.assertEqual(
207            value_inside_option.GetChildMemberWithName("inner")
208            .GetChildMemberWithName("field")
209            .GetData()
210            .GetSignedInt32(lldb.SBError(), 0),
211            123,
212        )
213        self.assertEqual(
214            value_inside_option.GetType().GetDisplayTypeName(), "main::Struct2"
215        )
216
217    def test_option_non_null_some_pointer(self):
218        type = self.target().FindFirstType(
219            "core::option::Option<core::ptr::non_null::NonNull<u64>>"
220        )
221        # this type is "optimized" by rust compiler so the discriminant isn't present on Some variant of option
222        data = [1337]
223        pointer_size = self.target().GetAddressByteSize()
224        byte_order = self.target().GetByteOrder()
225        value = RustEnumValue(
226            self.target().CreateValueFromData(
227                "adhoc_value",
228                lldb.SBData.CreateDataFromUInt64Array(byte_order, pointer_size, data),
229                type,
230            )
231        )
232        self.assertEqual(value.getFields(), ["$variant$0", "$variant$"])
233        self.assertEqual(
234            value.getCurrentValue()
235            .GetChildAtIndex(0)
236            .GetChildMemberWithName("pointer")
237            .GetValueAsUnsigned(),
238            1337,
239        )
240
241    def test_option_non_null_none(self):
242        type = self.target().FindFirstType(
243            "core::option::Option<core::ptr::non_null::NonNull<u64>>"
244        )
245        # this type is "optimized" by rust compiler so the discriminant isn't present on Some variant of option
246        # in this test case 0 is used to represent 'None'
247        data = [0]
248        pointer_size = self.target().GetAddressByteSize()
249        byte_order = self.target().GetByteOrder()
250        value = RustEnumValue(
251            self.target().CreateValueFromData(
252                "adhoc_value",
253                lldb.SBData.CreateDataFromUInt64Array(byte_order, pointer_size, data),
254                type,
255            )
256        )
257        self.assertEqual(value.getFields(), ["$variant$0", "$variant$"])
258        self.assertEqual(value.getCurrentValue().GetValue(), None)
259        self.assertEqual(
260            value.getCurrentValue().GetType().GetDisplayTypeName(),
261            "core::option::Option<core::ptr::non_null::NonNull<u64>>::None<core::ptr::non_null::NonNull<unsigned long> >",
262        )
263
264    def test_niche_layout_with_fields_2(self):
265        # static NICHE_W_FIELDS_2_A: NicheLayoutWithFields2 =
266        #           NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900);
267        value = self.getFromGlobal("NICHE_W_FIELDS_2_A").getCurrentValue()
268        self.assertEqual(
269            (
270                value.GetChildAtIndex(0)
271                .GetChildAtIndex(0)
272                .GetData()
273                .GetUnsignedInt32(lldb.SBError(), 0),
274                value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0),
275            ),
276            (800, 900),
277        )
278
279    def test_niche_layout_with_fields_3_a(self):
280        # static NICHE_W_FIELDS_3_A: NicheLayoutWithFields3 = NicheLayoutWithFields3::A(137, true);
281        value = self.getFromGlobal("NICHE_W_FIELDS_3_A").getCurrentValue()
282        self.assertEqual(
283            (
284                value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0),
285                value.GetChildAtIndex(1).GetData().GetUnsignedInt8(lldb.SBError(), 0),
286            ),
287            (137, 1),
288        )
289
290    def test_niche_layout_with_fields_3_c(self):
291        # static NICHE_W_FIELDS_3_C: NicheLayoutWithFields3 = NicheLayoutWithFields3::C(false);
292        value = self.getFromGlobal("NICHE_W_FIELDS_3_C").getCurrentValue()
293        self.assertEqual(
294            value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), 0
295        )
296