1""" 2Test lldb-dap completions request 3""" 4 5 6import lldbdap_testcase 7import dap_server 8from lldbsuite.test import lldbutil 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11 12session_completion = { 13 "text": "session", 14 "label": "session -- Commands controlling LLDB session.", 15} 16settings_completion = { 17 "text": "settings", 18 "label": "settings -- Commands for managing LLDB settings.", 19} 20memory_completion = { 21 "text": "memory", 22 "label": "memory -- Commands for operating on memory in the current target process.", 23} 24command_var_completion = { 25 "text": "var", 26 "label": "var -- Show variables for the current stack frame. Defaults to all arguments and local variables in scope. Names of argument, local, file static and file global variables can be specified.", 27} 28variable_var_completion = { 29 "text": "var", 30 "label": "var -- vector<baz> &", 31} 32variable_var1_completion = {"text": "var1", "label": "var1 -- int &"} 33variable_var2_completion = {"text": "var2", "label": "var2 -- int &"} 34 35# Older version of libcxx produce slightly different typename strings for 36# templates like vector. 37@skipIf(compiler="clang", compiler_version=["<", "16.0"]) 38class TestDAP_completions(lldbdap_testcase.DAPTestCaseBase): 39 def verify_completions(self, actual_list, expected_list, not_expected_list=[]): 40 for expected_item in expected_list: 41 self.assertIn(expected_item, actual_list) 42 43 for not_expected_item in not_expected_list: 44 self.assertNotIn(not_expected_item, actual_list) 45 46 47 def setup_debugee(self): 48 program = self.getBuildArtifact("a.out") 49 self.build_and_launch(program) 50 51 source = "main.cpp" 52 breakpoint1_line = line_number(source, "// breakpoint 1") 53 breakpoint2_line = line_number(source, "// breakpoint 2") 54 55 self.set_source_breakpoints(source, [breakpoint1_line, breakpoint2_line]) 56 57 def test_command_completions(self): 58 """ 59 Tests completion requests for lldb commands, within "repl-mode=command" 60 """ 61 self.setup_debugee() 62 self.continue_to_next_stop() 63 64 res = self.dap_server.request_evaluate( 65 "`lldb-dap repl-mode command", context="repl" 66 ) 67 self.assertTrue(res["success"]) 68 69 # Provides completion for top-level commands 70 self.verify_completions( 71 self.dap_server.get_completions("se"), 72 [session_completion, settings_completion], 73 ) 74 75 # Provides completions for sub-commands 76 self.verify_completions( 77 self.dap_server.get_completions("memory "), 78 [ 79 { 80 "text": "read", 81 "label": "read -- Read from the memory of the current target process.", 82 }, 83 { 84 "text": "region", 85 "label": "region -- Get information on the memory region containing an address in the current target process.", 86 }, 87 ], 88 ) 89 90 # Provides completions for parameter values of commands 91 self.verify_completions( 92 self.dap_server.get_completions("`log enable "), 93 [{"text": "gdb-remote", "label": "gdb-remote"}], 94 ) 95 96 # Also works if the escape prefix is used 97 self.verify_completions( 98 self.dap_server.get_completions("`mem"), [memory_completion] 99 ) 100 101 self.verify_completions( 102 self.dap_server.get_completions("`"), 103 [session_completion, settings_completion, memory_completion], 104 ) 105 106 # Completes an incomplete quoted token 107 self.verify_completions( 108 self.dap_server.get_completions('setting "se'), 109 [ 110 { 111 "text": "set", 112 "label": "set -- Set the value of the specified debugger setting.", 113 } 114 ], 115 ) 116 117 # Completes an incomplete quoted token 118 self.verify_completions( 119 self.dap_server.get_completions("'mem"), 120 [memory_completion], 121 ) 122 123 # Completes expressions with quotes inside 124 self.verify_completions( 125 self.dap_server.get_completions('expr " "; typed'), 126 [{"text": "typedef", "label": "typedef"}], 127 ) 128 129 # Provides completions for commands, but not variables 130 self.verify_completions( 131 self.dap_server.get_completions("var"), 132 [command_var_completion], 133 [variable_var_completion], 134 ) 135 136 def test_variable_completions(self): 137 """ 138 Tests completion requests in "repl-mode=variable" 139 """ 140 self.setup_debugee() 141 self.continue_to_next_stop() 142 143 res = self.dap_server.request_evaluate( 144 "`lldb-dap repl-mode variable", context="repl" 145 ) 146 self.assertTrue(res["success"]) 147 148 # Provides completions for varibles, but not command 149 self.verify_completions( 150 self.dap_server.get_completions("var"), 151 [variable_var_completion], 152 [command_var_completion], 153 ) 154 155 # We stopped inside `fun`, so we shouldn't see variables from main 156 self.verify_completions( 157 self.dap_server.get_completions("var"), 158 [variable_var_completion], 159 [ 160 variable_var1_completion, 161 variable_var2_completion, 162 ], 163 ) 164 165 # We should see global keywords but not variables inside main 166 self.verify_completions( 167 self.dap_server.get_completions("str"), 168 [{"text": "struct", "label": "struct"}], 169 [{"text": "str1", "label": "str1 -- std::string &"}], 170 ) 171 172 self.continue_to_next_stop() 173 174 # We stopped in `main`, so we should see variables from main but 175 # not from the other function 176 self.verify_completions( 177 self.dap_server.get_completions("var"), 178 [ 179 variable_var1_completion, 180 variable_var2_completion, 181 ], 182 [ 183 variable_var_completion, 184 ], 185 ) 186 187 self.verify_completions( 188 self.dap_server.get_completions("str"), 189 [ 190 {"text": "struct", "label": "struct"}, 191 {"text": "str1", "label": "str1 -- string &"}, 192 ], 193 ) 194 195 # Completion also works for more complex expressions 196 self.verify_completions( 197 self.dap_server.get_completions("foo1.v"), 198 [{"text": "var1", "label": "foo1.var1 -- int"}], 199 ) 200 201 self.verify_completions( 202 self.dap_server.get_completions("foo1.my_bar_object.v"), 203 [{"text": "var1", "label": "foo1.my_bar_object.var1 -- int"}], 204 ) 205 206 self.verify_completions( 207 self.dap_server.get_completions("foo1.var1 + foo1.v"), 208 [{"text": "var1", "label": "foo1.var1 -- int"}], 209 ) 210 211 self.verify_completions( 212 self.dap_server.get_completions("foo1.var1 + v"), 213 [{"text": "var1", "label": "var1 -- int &"}], 214 ) 215 216 # should correctly handle spaces between objects and member operators 217 self.verify_completions( 218 self.dap_server.get_completions("foo1 .v"), 219 [{"text": "var1", "label": ".var1 -- int"}], 220 [{"text": "var2", "label": ".var2 -- int"}], 221 ) 222 223 self.verify_completions( 224 self.dap_server.get_completions("foo1 . v"), 225 [{"text": "var1", "label": "var1 -- int"}], 226 [{"text": "var2", "label": "var2 -- int"}], 227 ) 228 229 # Even in variable mode, we can still use the escape prefix 230 self.verify_completions( 231 self.dap_server.get_completions("`mem"), [memory_completion] 232 ) 233 234 def test_auto_completions(self): 235 """ 236 Tests completion requests in "repl-mode=auto" 237 """ 238 self.setup_debugee() 239 240 res = self.dap_server.request_evaluate( 241 "`lldb-dap repl-mode auto", context="repl" 242 ) 243 self.assertTrue(res["success"]) 244 245 self.continue_to_next_stop() 246 self.continue_to_next_stop() 247 248 # We are stopped inside `main`. Variables `var1` and `var2` are in scope. 249 # Make sure, we offer all completions 250 self.verify_completions( 251 self.dap_server.get_completions("va"), 252 [ 253 command_var_completion, 254 variable_var1_completion, 255 variable_var2_completion, 256 ], 257 ) 258 259 # If we are using the escape prefix, only commands are suggested, but no variables 260 self.verify_completions( 261 self.dap_server.get_completions("`va"), 262 [ 263 command_var_completion, 264 ], 265 [ 266 variable_var1_completion, 267 variable_var2_completion, 268 ], 269 ) 270