""" Test the lldb command line completion mechanism for the 'expr' command. """ import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbplatform from lldbsuite.test import lldbutil class CommandLineExprCompletionTestCase(TestBase): NO_DEBUG_INFO_TESTCASE = True def test_expr_completion(self): self.build() self.main_source = "main.cpp" self.main_source_spec = lldb.SBFileSpec(self.main_source) self.createTestTarget() # Try the completion before we have a context to complete on. self.assume_no_completions("expr some_expr") self.assume_no_completions("expr ") self.assume_no_completions("expr f") (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "// Break here", self.main_source_spec ) # Completing member functions self.complete_from_to( "expr some_expr.FooNoArgs", "expr some_expr.FooNoArgsBar()" ) self.complete_from_to( "expr some_expr.FooWithArgs", "expr some_expr.FooWithArgsBar(" ) self.complete_from_to( "expr some_expr.FooWithMultipleArgs", "expr some_expr.FooWithMultipleArgsBar(", ) self.complete_from_to( "expr some_expr.FooUnderscore", "expr some_expr.FooUnderscoreBar_()" ) self.complete_from_to( "expr some_expr.FooNumbers", "expr some_expr.FooNumbersBar1()" ) self.complete_from_to( "expr some_expr.StaticMemberMethod", "expr some_expr.StaticMemberMethodBar()", ) # Completing static functions self.complete_from_to( "expr Expr::StaticMemberMethod", "expr Expr::StaticMemberMethodBar()" ) # Completing member variables self.complete_from_to( "expr some_expr.MemberVariab", "expr some_expr.MemberVariableBar" ) # Multiple completions self.completions_contain( "expr some_expr.", [ "some_expr.FooNumbersBar1()", "some_expr.FooUnderscoreBar_()", "some_expr.FooWithArgsBar(", "some_expr.MemberVariableBar", ], ) self.completions_contain( "expr some_expr.Foo", [ "some_expr.FooNumbersBar1()", "some_expr.FooUnderscoreBar_()", "some_expr.FooWithArgsBar(", ], ) self.completions_contain( "expr ", ["static_cast", "reinterpret_cast", "dynamic_cast"] ) self.completions_contain( "expr 1 + ", ["static_cast", "reinterpret_cast", "dynamic_cast"] ) # Completion expr without spaces # This is a bit awkward looking for the user, but that's how # the completion API works at the moment. self.completions_contain("expr 1+", ["1+some_expr", "1+static_cast"]) # Test with spaces self.complete_from_to( "expr some_expr .FooNoArgs", "expr some_expr .FooNoArgsBar()" ) self.complete_from_to( "expr some_expr .FooNoArgs", "expr some_expr .FooNoArgsBar()" ) self.complete_from_to( "expr some_expr .FooNoArgs", "expr some_expr .FooNoArgsBar()" ) self.complete_from_to( "expr some_expr. FooNoArgs", "expr some_expr. FooNoArgsBar()" ) self.complete_from_to( "expr some_expr . FooNoArgs", "expr some_expr . FooNoArgsBar()" ) self.complete_from_to( "expr Expr :: StaticMemberMethod", "expr Expr :: StaticMemberMethodBar()" ) self.complete_from_to( "expr Expr ::StaticMemberMethod", "expr Expr ::StaticMemberMethodBar()" ) self.complete_from_to( "expr Expr:: StaticMemberMethod", "expr Expr:: StaticMemberMethodBar()" ) # Test that string literals don't break our parsing logic. self.complete_from_to( 'expr const char *cstr = "some_e"; char c = *cst', 'expr const char *cstr = "some_e"; char c = *cstr', ) self.complete_from_to( 'expr const char *cstr = "some_e" ; char c = *cst', 'expr const char *cstr = "some_e" ; char c = *cstr', ) # Requesting completions inside an incomplete string doesn't provide any # completions. self.complete_from_to( 'expr const char *cstr = "some_e', 'expr const char *cstr = "some_e' ) # Completing inside double dash should do nothing self.assume_no_completions("expr -i0 -- some_expr.", 10) self.assume_no_completions("expr -i0 -- some_expr.", 11) # Test with expr arguments self.complete_from_to( "expr -i0 -- some_expr .FooNoArgs", "expr -i0 -- some_expr .FooNoArgsBar()" ) self.complete_from_to( "expr -i0 -- some_expr .FooNoArgs", "expr -i0 -- some_expr .FooNoArgsBar()", ) # Addrof and deref self.complete_from_to( "expr (*(&some_expr)).FooNoArgs", "expr (*(&some_expr)).FooNoArgsBar()" ) self.complete_from_to( "expr (*(&some_expr)) .FooNoArgs", "expr (*(&some_expr)) .FooNoArgsBar()" ) self.complete_from_to( "expr (* (&some_expr)) .FooNoArgs", "expr (* (&some_expr)) .FooNoArgsBar()" ) self.complete_from_to( "expr (* (& some_expr)) .FooNoArgs", "expr (* (& some_expr)) .FooNoArgsBar()", ) # Addrof and deref (part 2) self.complete_from_to( "expr (&some_expr)->FooNoArgs", "expr (&some_expr)->FooNoArgsBar()" ) self.complete_from_to( "expr (&some_expr) ->FooNoArgs", "expr (&some_expr) ->FooNoArgsBar()" ) self.complete_from_to( "expr (&some_expr) -> FooNoArgs", "expr (&some_expr) -> FooNoArgsBar()" ) self.complete_from_to( "expr (&some_expr)-> FooNoArgs", "expr (&some_expr)-> FooNoArgsBar()" ) # Builtin arg self.complete_from_to("expr static_ca", "expr static_cast") # From other files self.complete_from_to( "expr fwd_decl_ptr->Hidden", "expr fwd_decl_ptr->HiddenMember" ) # Types self.complete_from_to("expr LongClassNa", "expr LongClassName") self.complete_from_to( "expr LongNamespaceName::NestedCla", "expr LongNamespaceName::NestedClass" ) # Namespaces self.complete_from_to("expr LongNamespaceNa", "expr LongNamespaceName::") # Multiple arguments self.complete_from_to( "expr &some_expr + &some_e", "expr &some_expr + &some_expr" ) self.complete_from_to( "expr SomeLongVarNameWithCapitals + SomeLongVarName", "expr SomeLongVarNameWithCapitals + SomeLongVarNameWithCapitals", ) self.complete_from_to( "expr SomeIntVar + SomeIntV", "expr SomeIntVar + SomeIntVar" ) # Multiple statements self.complete_from_to( "expr long LocalVariable = 0; LocalVaria", "expr long LocalVariable = 0; LocalVariable", ) # Custom Decls self.complete_from_to( "expr auto l = [](int LeftHandSide, int bx){ return LeftHandS", "expr auto l = [](int LeftHandSide, int bx){ return LeftHandSide", ) self.complete_from_to( "expr struct LocalStruct { long MemberName; } ; LocalStruct S; S.Mem", "expr struct LocalStruct { long MemberName; } ; LocalStruct S; S.MemberName", ) # Completing function call arguments self.complete_from_to( "expr some_expr.FooWithArgsBar(some_exp", "expr some_expr.FooWithArgsBar(some_expr", ) self.complete_from_to( "expr some_expr.FooWithArgsBar(SomeIntV", "expr some_expr.FooWithArgsBar(SomeIntVar", ) self.complete_from_to( "expr some_expr.FooWithMultipleArgsBar(SomeIntVar, SomeIntVa", "expr some_expr.FooWithMultipleArgsBar(SomeIntVar, SomeIntVar", ) # Function return values self.complete_from_to( "expr some_expr.Self().FooNoArgs", "expr some_expr.Self().FooNoArgsBar()" ) self.complete_from_to( "expr some_expr.Self() .FooNoArgs", "expr some_expr.Self() .FooNoArgsBar()" ) self.complete_from_to( "expr some_expr.Self(). FooNoArgs", "expr some_expr.Self(). FooNoArgsBar()" ) def test_expr_completion_with_descriptions(self): self.build() self.main_source = "main.cpp" self.main_source_spec = lldb.SBFileSpec(self.main_source) self.createTestTarget() (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "// Break here", self.main_source_spec ) self.check_completion_with_desc( "expr ", [ # builtin types have no description. ["int", ""], ["float", ""], # VarDecls have their type as description. ["some_expr", "Expr &"], ], enforce_order=True, ) self.check_completion_with_desc( "expr some_expr.", [ # Functions have their signature as description. ["some_expr.~Expr()", "inline ~Expr()"], ["some_expr.operator=(", "inline Expr &operator=(const Expr &)"], # FieldDecls have their type as description. ["some_expr.MemberVariableBar", "int"], [ "some_expr.StaticMemberMethodBar()", "static int StaticMemberMethodBar()", ], ["some_expr.Self()", "Expr &Self()"], ["some_expr.FooNoArgsBar()", "int FooNoArgsBar()"], ["some_expr.FooWithArgsBar(", "int FooWithArgsBar(int)"], ["some_expr.FooNumbersBar1()", "int FooNumbersBar1()"], ["some_expr.FooUnderscoreBar_()", "int FooUnderscoreBar_()"], [ "some_expr.FooWithMultipleArgsBar(", "int FooWithMultipleArgsBar(int, int)", ], ], enforce_order=True, ) def assume_no_completions(self, str_input, cursor_pos=None): interp = self.dbg.GetCommandInterpreter() match_strings = lldb.SBStringList() if cursor_pos is None: cursor_pos = len(str_input) num_matches = interp.HandleCompletion( str_input, cursor_pos, 0, -1, match_strings ) available_completions = [] for m in match_strings: available_completions.append(m) self.assertEquals( num_matches, 0, "Got matches, but didn't expect any: " + str(available_completions), ) def completions_contain(self, str_input, items): interp = self.dbg.GetCommandInterpreter() match_strings = lldb.SBStringList() num_matches = interp.HandleCompletion( str_input, len(str_input), 0, -1, match_strings ) common_match = match_strings.GetStringAtIndex(0) for item in items: found = False for m in match_strings: if m == item: found = True if not found: # Transform match_strings to a python list with strings available_completions = [] for m in match_strings: available_completions.append(m) self.assertTrue( found, "Couldn't find completion " + item + " in completions " + str(available_completions), )