xref: /llvm-project/lldb/test/API/commands/expression/completion/TestExprCompletion.py (revision 88bf64097e453deca73c91ec7de1af7eebe296a9)
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