"""
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()"
)
self.complete_from_to("expr myVec.__f", "expr myVec.__func()")
self.complete_from_to("expr myVec._F", "expr myVec._Func()")
self.complete_from_to("expr myVec.__m", "expr myVec.__mem")
self.complete_from_to("expr myVec._M", "expr myVec._Mem")
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.assertEqual(
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),
)