1""" 2Test the lldb command line completion mechanism for the 'expr' command. 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbplatform 10from lldbsuite.test import lldbutil 11 12 13class CommandLineExprCompletionTestCase(TestBase): 14 NO_DEBUG_INFO_TESTCASE = True 15 16 def test_expr_completion(self): 17 self.build() 18 self.main_source = "main.cpp" 19 self.main_source_spec = lldb.SBFileSpec(self.main_source) 20 self.createTestTarget() 21 22 # Try the completion before we have a context to complete on. 23 self.assume_no_completions("expr some_expr") 24 self.assume_no_completions("expr ") 25 self.assume_no_completions("expr f") 26 27 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 28 self, "// Break here", self.main_source_spec 29 ) 30 31 # Completing member functions 32 self.complete_from_to( 33 "expr some_expr.FooNoArgs", "expr some_expr.FooNoArgsBar()" 34 ) 35 self.complete_from_to( 36 "expr some_expr.FooWithArgs", "expr some_expr.FooWithArgsBar(" 37 ) 38 self.complete_from_to( 39 "expr some_expr.FooWithMultipleArgs", 40 "expr some_expr.FooWithMultipleArgsBar(", 41 ) 42 self.complete_from_to( 43 "expr some_expr.FooUnderscore", "expr some_expr.FooUnderscoreBar_()" 44 ) 45 self.complete_from_to( 46 "expr some_expr.FooNumbers", "expr some_expr.FooNumbersBar1()" 47 ) 48 self.complete_from_to( 49 "expr some_expr.StaticMemberMethod", 50 "expr some_expr.StaticMemberMethodBar()", 51 ) 52 53 # Completing static functions 54 self.complete_from_to( 55 "expr Expr::StaticMemberMethod", "expr Expr::StaticMemberMethodBar()" 56 ) 57 58 # Completing member variables 59 self.complete_from_to( 60 "expr some_expr.MemberVariab", "expr some_expr.MemberVariableBar" 61 ) 62 63 # Multiple completions 64 self.completions_contain( 65 "expr some_expr.", 66 [ 67 "some_expr.FooNumbersBar1()", 68 "some_expr.FooUnderscoreBar_()", 69 "some_expr.FooWithArgsBar(", 70 "some_expr.MemberVariableBar", 71 ], 72 ) 73 74 self.completions_contain( 75 "expr some_expr.Foo", 76 [ 77 "some_expr.FooNumbersBar1()", 78 "some_expr.FooUnderscoreBar_()", 79 "some_expr.FooWithArgsBar(", 80 ], 81 ) 82 83 self.completions_contain( 84 "expr ", ["static_cast", "reinterpret_cast", "dynamic_cast"] 85 ) 86 87 self.completions_contain( 88 "expr 1 + ", ["static_cast", "reinterpret_cast", "dynamic_cast"] 89 ) 90 91 # Completion expr without spaces 92 # This is a bit awkward looking for the user, but that's how 93 # the completion API works at the moment. 94 self.completions_contain("expr 1+", ["1+some_expr", "1+static_cast"]) 95 96 # Test with spaces 97 self.complete_from_to( 98 "expr some_expr .FooNoArgs", "expr some_expr .FooNoArgsBar()" 99 ) 100 self.complete_from_to( 101 "expr some_expr .FooNoArgs", "expr some_expr .FooNoArgsBar()" 102 ) 103 self.complete_from_to( 104 "expr some_expr .FooNoArgs", "expr some_expr .FooNoArgsBar()" 105 ) 106 self.complete_from_to( 107 "expr some_expr. FooNoArgs", "expr some_expr. FooNoArgsBar()" 108 ) 109 self.complete_from_to( 110 "expr some_expr . FooNoArgs", "expr some_expr . FooNoArgsBar()" 111 ) 112 self.complete_from_to( 113 "expr Expr :: StaticMemberMethod", "expr Expr :: StaticMemberMethodBar()" 114 ) 115 self.complete_from_to( 116 "expr Expr ::StaticMemberMethod", "expr Expr ::StaticMemberMethodBar()" 117 ) 118 self.complete_from_to( 119 "expr Expr:: StaticMemberMethod", "expr Expr:: StaticMemberMethodBar()" 120 ) 121 122 # Test that string literals don't break our parsing logic. 123 self.complete_from_to( 124 'expr const char *cstr = "some_e"; char c = *cst', 125 'expr const char *cstr = "some_e"; char c = *cstr', 126 ) 127 self.complete_from_to( 128 'expr const char *cstr = "some_e" ; char c = *cst', 129 'expr const char *cstr = "some_e" ; char c = *cstr', 130 ) 131 # Requesting completions inside an incomplete string doesn't provide any 132 # completions. 133 self.complete_from_to( 134 'expr const char *cstr = "some_e', 'expr const char *cstr = "some_e' 135 ) 136 137 # Completing inside double dash should do nothing 138 self.assume_no_completions("expr -i0 -- some_expr.", 10) 139 self.assume_no_completions("expr -i0 -- some_expr.", 11) 140 141 # Test with expr arguments 142 self.complete_from_to( 143 "expr -i0 -- some_expr .FooNoArgs", "expr -i0 -- some_expr .FooNoArgsBar()" 144 ) 145 self.complete_from_to( 146 "expr -i0 -- some_expr .FooNoArgs", 147 "expr -i0 -- some_expr .FooNoArgsBar()", 148 ) 149 150 # Addrof and deref 151 self.complete_from_to( 152 "expr (*(&some_expr)).FooNoArgs", "expr (*(&some_expr)).FooNoArgsBar()" 153 ) 154 self.complete_from_to( 155 "expr (*(&some_expr)) .FooNoArgs", "expr (*(&some_expr)) .FooNoArgsBar()" 156 ) 157 self.complete_from_to( 158 "expr (* (&some_expr)) .FooNoArgs", "expr (* (&some_expr)) .FooNoArgsBar()" 159 ) 160 self.complete_from_to( 161 "expr (* (& some_expr)) .FooNoArgs", 162 "expr (* (& some_expr)) .FooNoArgsBar()", 163 ) 164 165 # Addrof and deref (part 2) 166 self.complete_from_to( 167 "expr (&some_expr)->FooNoArgs", "expr (&some_expr)->FooNoArgsBar()" 168 ) 169 self.complete_from_to( 170 "expr (&some_expr) ->FooNoArgs", "expr (&some_expr) ->FooNoArgsBar()" 171 ) 172 self.complete_from_to( 173 "expr (&some_expr) -> FooNoArgs", "expr (&some_expr) -> FooNoArgsBar()" 174 ) 175 self.complete_from_to( 176 "expr (&some_expr)-> FooNoArgs", "expr (&some_expr)-> FooNoArgsBar()" 177 ) 178 179 # Builtin arg 180 self.complete_from_to("expr static_ca", "expr static_cast") 181 182 # From other files 183 self.complete_from_to( 184 "expr fwd_decl_ptr->Hidden", "expr fwd_decl_ptr->HiddenMember" 185 ) 186 187 # Types 188 self.complete_from_to("expr LongClassNa", "expr LongClassName") 189 self.complete_from_to( 190 "expr LongNamespaceName::NestedCla", "expr LongNamespaceName::NestedClass" 191 ) 192 193 # Namespaces 194 self.complete_from_to("expr LongNamespaceNa", "expr LongNamespaceName::") 195 196 # Multiple arguments 197 self.complete_from_to( 198 "expr &some_expr + &some_e", "expr &some_expr + &some_expr" 199 ) 200 self.complete_from_to( 201 "expr SomeLongVarNameWithCapitals + SomeLongVarName", 202 "expr SomeLongVarNameWithCapitals + SomeLongVarNameWithCapitals", 203 ) 204 self.complete_from_to( 205 "expr SomeIntVar + SomeIntV", "expr SomeIntVar + SomeIntVar" 206 ) 207 208 # Multiple statements 209 self.complete_from_to( 210 "expr long LocalVariable = 0; LocalVaria", 211 "expr long LocalVariable = 0; LocalVariable", 212 ) 213 214 # Custom Decls 215 self.complete_from_to( 216 "expr auto l = [](int LeftHandSide, int bx){ return LeftHandS", 217 "expr auto l = [](int LeftHandSide, int bx){ return LeftHandSide", 218 ) 219 self.complete_from_to( 220 "expr struct LocalStruct { long MemberName; } ; LocalStruct S; S.Mem", 221 "expr struct LocalStruct { long MemberName; } ; LocalStruct S; S.MemberName", 222 ) 223 224 # Completing function call arguments 225 self.complete_from_to( 226 "expr some_expr.FooWithArgsBar(some_exp", 227 "expr some_expr.FooWithArgsBar(some_expr", 228 ) 229 self.complete_from_to( 230 "expr some_expr.FooWithArgsBar(SomeIntV", 231 "expr some_expr.FooWithArgsBar(SomeIntVar", 232 ) 233 self.complete_from_to( 234 "expr some_expr.FooWithMultipleArgsBar(SomeIntVar, SomeIntVa", 235 "expr some_expr.FooWithMultipleArgsBar(SomeIntVar, SomeIntVar", 236 ) 237 238 # Function return values 239 self.complete_from_to( 240 "expr some_expr.Self().FooNoArgs", "expr some_expr.Self().FooNoArgsBar()" 241 ) 242 self.complete_from_to( 243 "expr some_expr.Self() .FooNoArgs", "expr some_expr.Self() .FooNoArgsBar()" 244 ) 245 self.complete_from_to( 246 "expr some_expr.Self(). FooNoArgs", "expr some_expr.Self(). FooNoArgsBar()" 247 ) 248 249 self.complete_from_to("expr myVec.__f", "expr myVec.__func()") 250 self.complete_from_to("expr myVec._F", "expr myVec._Func()") 251 self.complete_from_to("expr myVec.__m", "expr myVec.__mem") 252 self.complete_from_to("expr myVec._M", "expr myVec._Mem") 253 254 def test_expr_completion_with_descriptions(self): 255 self.build() 256 self.main_source = "main.cpp" 257 self.main_source_spec = lldb.SBFileSpec(self.main_source) 258 self.createTestTarget() 259 260 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 261 self, "// Break here", self.main_source_spec 262 ) 263 264 self.check_completion_with_desc( 265 "expr ", 266 [ 267 # builtin types have no description. 268 ["int", ""], 269 ["float", ""], 270 # VarDecls have their type as description. 271 ["some_expr", "Expr &"], 272 ], 273 enforce_order=True, 274 ) 275 self.check_completion_with_desc( 276 "expr some_expr.", 277 [ 278 # Functions have their signature as description. 279 ["some_expr.~Expr()", "inline ~Expr()"], 280 ["some_expr.operator=(", "inline Expr &operator=(const Expr &)"], 281 # FieldDecls have their type as description. 282 ["some_expr.MemberVariableBar", "int"], 283 [ 284 "some_expr.StaticMemberMethodBar()", 285 "static int StaticMemberMethodBar()", 286 ], 287 ["some_expr.Self()", "Expr &Self()"], 288 ["some_expr.FooNoArgsBar()", "int FooNoArgsBar()"], 289 ["some_expr.FooWithArgsBar(", "int FooWithArgsBar(int)"], 290 ["some_expr.FooNumbersBar1()", "int FooNumbersBar1()"], 291 ["some_expr.FooUnderscoreBar_()", "int FooUnderscoreBar_()"], 292 [ 293 "some_expr.FooWithMultipleArgsBar(", 294 "int FooWithMultipleArgsBar(int, int)", 295 ], 296 ], 297 enforce_order=True, 298 ) 299 300 def assume_no_completions(self, str_input, cursor_pos=None): 301 interp = self.dbg.GetCommandInterpreter() 302 match_strings = lldb.SBStringList() 303 if cursor_pos is None: 304 cursor_pos = len(str_input) 305 num_matches = interp.HandleCompletion( 306 str_input, cursor_pos, 0, -1, match_strings 307 ) 308 309 available_completions = [] 310 for m in match_strings: 311 available_completions.append(m) 312 313 self.assertEqual( 314 num_matches, 315 0, 316 "Got matches, but didn't expect any: " + str(available_completions), 317 ) 318 319 def completions_contain(self, str_input, items): 320 interp = self.dbg.GetCommandInterpreter() 321 match_strings = lldb.SBStringList() 322 num_matches = interp.HandleCompletion( 323 str_input, len(str_input), 0, -1, match_strings 324 ) 325 common_match = match_strings.GetStringAtIndex(0) 326 327 for item in items: 328 found = False 329 for m in match_strings: 330 if m == item: 331 found = True 332 if not found: 333 # Transform match_strings to a python list with strings 334 available_completions = [] 335 for m in match_strings: 336 available_completions.append(m) 337 self.assertTrue( 338 found, 339 "Couldn't find completion " 340 + item 341 + " in completions " 342 + str(available_completions), 343 ) 344