375 lines · python
1"""2Test the lldb command line completion mechanism for the 'expr' command.3"""4 5 6import lldb7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbplatform10from lldbsuite.test import lldbutil11 12 13class CommandLineExprCompletionTestCase(TestBase):14 NO_DEBUG_INFO_TESTCASE = True15 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_spec29 )30 31 # Completing member functions32 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 functions54 self.complete_from_to(55 "expr Expr::StaticMemberMethod", "expr Expr::StaticMemberMethodBar()"56 )57 58 # Completing member variables59 self.complete_from_to(60 "expr some_expr.MemberVariab", "expr some_expr.MemberVariableBar"61 )62 63 # Multiple completions64 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 spaces92 # This is a bit awkward looking for the user, but that's how93 # the completion API works at the moment.94 self.completions_contain("expr 1+", ["1+some_expr", "1+static_cast"])95 96 # Test with spaces97 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 any132 # 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 nothing138 self.assume_no_completions("expr -i0 -- some_expr.", 10)139 self.assume_no_completions("expr -i0 -- some_expr.", 11)140 141 # Test with expr arguments142 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 deref151 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 arg180 self.complete_from_to("expr static_ca", "expr static_cast")181 182 # From other files183 self.complete_from_to(184 "expr fwd_decl_ptr->Hidden", "expr fwd_decl_ptr->HiddenMember"185 )186 187 # Types188 self.complete_from_to("expr LongClassNa", "expr LongClassName")189 self.complete_from_to(190 "expr LongNamespaceName::NestedCla", "expr LongNamespaceName::NestedClass"191 )192 193 # Namespaces194 self.complete_from_to("expr LongNamespaceNa", "expr LongNamespaceName::")195 196 # Multiple arguments197 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 statements209 self.complete_from_to(210 "expr long LocalVariable = 0; LocalVaria",211 "expr long LocalVariable = 0; LocalVariable",212 )213 214 # Custom Decls215 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 arguments225 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 values239 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_spec262 )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 test_expr_completion_max_results(self):301 self.build()302 self.main_source = "main.cpp"303 self.main_source_spec = lldb.SBFileSpec(self.main_source)304 self.createTestTarget()305 306 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(307 self, "// Break here", self.main_source_spec308 )309 310 expected_completions = [311 "some_expr.~Expr()",312 "some_expr.operator=(", # Copy operator313 "some_expr.operator=(", # Move operator314 "some_expr.MemberVariableBar",315 "some_expr.StaticMemberMethodBar()",316 "some_expr.Self()",317 "some_expr.FooNoArgsBar()",318 "some_expr.FooWithArgsBar(",319 "some_expr.FooNumbersBar1()",320 "some_expr.FooUnderscoreBar_()",321 "some_expr.FooWithMultipleArgsBar(",322 ]323 324 for i in range(1, len(expected_completions)):325 self.completions_match(326 "expr some_expr.",327 expected_completions[:i],328 max_completions=i,329 )330 331 def assume_no_completions(self, str_input, cursor_pos=None):332 interp = self.dbg.GetCommandInterpreter()333 match_strings = lldb.SBStringList()334 if cursor_pos is None:335 cursor_pos = len(str_input)336 num_matches = interp.HandleCompletion(337 str_input, cursor_pos, 0, -1, match_strings338 )339 340 available_completions = []341 for m in match_strings:342 available_completions.append(m)343 344 self.assertEqual(345 num_matches,346 0,347 "Got matches, but didn't expect any: " + str(available_completions),348 )349 350 def completions_contain(self, str_input, items):351 interp = self.dbg.GetCommandInterpreter()352 match_strings = lldb.SBStringList()353 num_matches = interp.HandleCompletion(354 str_input, len(str_input), 0, -1, match_strings355 )356 common_match = match_strings.GetStringAtIndex(0)357 358 for item in items:359 found = False360 for m in match_strings:361 if m == item:362 found = True363 if not found:364 # Transform match_strings to a python list with strings365 available_completions = []366 for m in match_strings:367 available_completions.append(m)368 self.assertTrue(369 found,370 "Couldn't find completion "371 + item372 + " in completions "373 + str(available_completions),374 )375