338 lines
12 KiB
Python
338 lines
12 KiB
Python
"""
|
|
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),
|
|
)
|