1""" 2Test lldb data formatter subsystem for std::span 3""" 4 5import lldb 6from lldbsuite.test.decorators import * 7from lldbsuite.test.lldbtest import * 8from lldbsuite.test import lldbutil 9 10 11class LibcxxSpanDataFormatterTestCase(TestBase): 12 def findVariable(self, name): 13 var = self.frame().FindVariable(name) 14 self.assertTrue(var.IsValid()) 15 return var 16 17 def check_size(self, var_name, size): 18 var = self.findVariable(var_name) 19 self.assertEqual(var.GetNumChildren(), size) 20 21 def check_numbers(self, var_name): 22 """Helper to check that data formatter sees contents of std::span correctly""" 23 24 expectedSize = 5 25 self.check_size(var_name, expectedSize) 26 27 self.expect_expr( 28 var_name, 29 result_type=f"std::span<int, {expectedSize}>", 30 result_summary=f"size={expectedSize}", 31 result_children=[ 32 ValueCheck(name="[0]", value="1"), 33 ValueCheck(name="[1]", value="12"), 34 ValueCheck(name="[2]", value="123"), 35 ValueCheck(name="[3]", value="1234"), 36 ValueCheck(name="[4]", value="12345"), 37 ], 38 ) 39 40 # check access-by-index 41 self.expect_var_path(f"{var_name}[0]", type="int", value="1") 42 self.expect_var_path(f"{var_name}[1]", type="int", value="12") 43 self.expect_var_path(f"{var_name}[2]", type="int", value="123") 44 self.expect_var_path(f"{var_name}[3]", type="int", value="1234") 45 self.expect_var_path(f"{var_name}[4]", type="int", value="12345") 46 47 @add_test_categories(["libc++"]) 48 @skipIf(compiler="clang", compiler_version=["<", "11.0"]) 49 def test_with_run_command(self): 50 """Test that std::span variables are formatted correctly when printed.""" 51 self.build() 52 (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 53 self, "break here", lldb.SBFileSpec("main.cpp", False) 54 ) 55 56 lldbutil.continue_to_breakpoint(process, bkpt) 57 58 # std::span of std::array with extents known at compile-time 59 self.check_numbers("numbers_span") 60 61 # check access to synthetic children for static spans 62 self.runCmd( 63 'type summary add --summary-string "item 0 is ${var[0]}" -x "std::span<" span' 64 ) 65 self.expect_expr( 66 "numbers_span", 67 result_type="std::span<int, 5>", 68 result_summary="item 0 is 1", 69 ) 70 71 self.runCmd( 72 'type summary add --summary-string "item 0 is ${svar[0]}" -x "std::span<" span' 73 ) 74 self.expect_expr( 75 "numbers_span", 76 result_type="std::span<int, 5>", 77 result_summary="item 0 is 1", 78 ) 79 80 self.runCmd("type summary delete span") 81 82 # New span with strings 83 lldbutil.continue_to_breakpoint(process, bkpt) 84 85 expectedStringSpanChildren = [ 86 ValueCheck(name="[0]", summary='"smart"'), 87 ValueCheck(name="[1]", summary='"!!!"'), 88 ] 89 90 self.expect_var_path( 91 "strings_span", summary="size=2", children=expectedStringSpanChildren 92 ) 93 94 # check access to synthetic children for dynamic spans 95 self.runCmd( 96 'type summary add --summary-string "item 0 is ${var[0]}" dynamic_string_span' 97 ) 98 self.expect_var_path("strings_span", summary='item 0 is "smart"') 99 100 self.runCmd( 101 'type summary add --summary-string "item 0 is ${svar[0]}" dynamic_string_span' 102 ) 103 self.expect_var_path("strings_span", summary='item 0 is "smart"') 104 105 self.runCmd("type summary delete dynamic_string_span") 106 107 # test summaries based on synthetic children 108 self.runCmd( 109 'type summary add --summary-string "span has ${svar%#} items" -e dynamic_string_span' 110 ) 111 112 self.expect_var_path("strings_span", summary="span has 2 items") 113 114 self.expect_var_path( 115 "strings_span", 116 summary="span has 2 items", 117 children=expectedStringSpanChildren, 118 ) 119 120 # check access-by-index 121 self.expect_var_path("strings_span[0]", summary='"smart"') 122 self.expect_var_path("strings_span[1]", summary='"!!!"') 123 124 # Newly inserted value not visible to span 125 lldbutil.continue_to_breakpoint(process, bkpt) 126 127 self.expect_expr( 128 "strings_span", 129 result_summary="span has 2 items", 130 result_children=expectedStringSpanChildren, 131 ) 132 133 self.runCmd("type summary delete dynamic_string_span") 134 135 lldbutil.continue_to_breakpoint(process, bkpt) 136 137 # Empty spans 138 self.expect_expr( 139 "static_zero_span", result_type="std::span<int, 0>", result_summary="size=0" 140 ) 141 self.check_size("static_zero_span", 0) 142 143 self.expect_expr("dynamic_zero_span", result_summary="size=0") 144 self.check_size("dynamic_zero_span", 0) 145 146 # Nested spans 147 self.expect_expr( 148 "nested", 149 result_summary="size=2", 150 result_children=[ 151 ValueCheck( 152 name="[0]", summary="size=2", children=expectedStringSpanChildren 153 ), 154 ValueCheck( 155 name="[1]", summary="size=2", children=expectedStringSpanChildren 156 ), 157 ], 158 ) 159 self.check_size("nested", 2) 160 161 @add_test_categories(["libc++"]) 162 @skipIf(compiler="clang", compiler_version=["<", "11.0"]) 163 def test_ref_and_ptr(self): 164 """Test that std::span is correctly formatted when passed by ref and ptr""" 165 self.build() 166 (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 167 self, "Stop here to check by ref", lldb.SBFileSpec("main.cpp", False) 168 ) 169 170 # The reference should display the same was as the value did 171 self.check_numbers("ref") 172 173 # The pointer should just show the right number of elements: 174 175 ptrAddr = self.findVariable("ptr").GetValue() 176 self.expect_expr( 177 "ptr", result_type="std::span<int, 5> *", result_summary=f"{ptrAddr} size=5" 178 ) 179