Skip to content

Commit 6fbb8d8

Browse files
MrHateTeemperor
authored andcommitted
[lldb] common completion for process pids and process names
1. Added two common completions: `ProcessIDs` and `ProcessNames`, which are refactored from their original dedicated option completions; 2. Removed the dedicated option completion functions of `process attach` and `platform process attach`, so that they can use arg-type-bound common completions instead; 3. Bound `eArgTypePid` to the pid completion, `eArgTypeProcessName` to the process name completion in `CommandObject.cpp`; 4. Added a related test case. Reviewed By: teemperor Differential Revision: https://reviews.llvm.org/D80700 (cherry picked from commit 19311f5)
1 parent ef9f74a commit 6fbb8d8

File tree

7 files changed

+84
-95
lines changed

7 files changed

+84
-95
lines changed

lldb/include/lldb/Interpreter/CommandCompletions.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ class CommandCompletions {
4545
eThreadIndexCompletion = (1u << 17),
4646
eWatchPointIDCompletion = (1u << 18),
4747
eBreakpointNameCompletion = (1u << 19),
48+
eProcessIDCompletion = (1u << 20),
49+
eProcessNameCompletion = (1u << 21),
4850
// This item serves two purposes. It is the last element in the enum, so
4951
// you can add custom enums starting from here in your Option class. Also
5052
// if you & in this bit the base code will not process the option.
51-
eCustomCompletion = (1u << 20)
53+
eCustomCompletion = (1u << 22)
5254
};
5355

5456
static bool InvokeCommonCompletionCallbacks(
@@ -110,6 +112,12 @@ class CommandCompletions {
110112
CompletionRequest &request,
111113
SearchFilter *searcher);
112114

115+
static void ProcessIDs(CommandInterpreter &interpreter,
116+
CompletionRequest &request, SearchFilter *searcher);
117+
118+
static void ProcessNames(CommandInterpreter &interpreter,
119+
CompletionRequest &request, SearchFilter *searcher);
120+
113121
static void DisassemblyFlavors(CommandInterpreter &interpreter,
114122
CompletionRequest &request,
115123
SearchFilter *searcher);

lldb/source/Commands/CommandCompletions.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks(
7171
{eThreadIndexCompletion, CommandCompletions::ThreadIndexes},
7272
{eWatchPointIDCompletion, CommandCompletions::WatchPointIDs},
7373
{eBreakpointNameCompletion, CommandCompletions::BreakpointNames},
74+
{eProcessIDCompletion, CommandCompletions::ProcessIDs},
75+
{eProcessNameCompletion, CommandCompletions::ProcessNames},
7476
{eNoCompletion, nullptr} // This one has to be last in the list.
7577
};
7678

@@ -649,6 +651,33 @@ void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter,
649651
}
650652
}
651653

654+
void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter,
655+
CompletionRequest &request,
656+
SearchFilter *searcher) {
657+
lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
658+
if (!platform_sp)
659+
return;
660+
ProcessInstanceInfoList process_infos;
661+
ProcessInstanceInfoMatch match_info;
662+
platform_sp->FindProcesses(match_info, process_infos);
663+
for (const ProcessInstanceInfo &info : process_infos)
664+
request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()),
665+
info.GetNameAsStringRef());
666+
}
667+
668+
void CommandCompletions::ProcessNames(CommandInterpreter &interpreter,
669+
CompletionRequest &request,
670+
SearchFilter *searcher) {
671+
lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
672+
if (!platform_sp)
673+
return;
674+
ProcessInstanceInfoList process_infos;
675+
ProcessInstanceInfoMatch match_info;
676+
platform_sp->FindProcesses(match_info, process_infos);
677+
for (const ProcessInstanceInfo &info : process_infos)
678+
request.TryCompleteCurrentArg(info.GetNameAsStringRef());
679+
}
680+
652681
void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter,
653682
CompletionRequest &request,
654683
SearchFilter *searcher) {

lldb/source/Commands/CommandObjectPlatform.cpp

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,14 @@ class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
13311331

13321332
~CommandObjectPlatformProcessInfo() override = default;
13331333

1334+
void
1335+
HandleArgumentCompletion(CompletionRequest &request,
1336+
OptionElementVector &opt_element_vector) override {
1337+
CommandCompletions::InvokeCommonCompletionCallbacks(
1338+
GetCommandInterpreter(), CommandCompletions::eProcessIDCompletion,
1339+
request, nullptr);
1340+
}
1341+
13341342
protected:
13351343
bool DoExecute(Args &args, CommandReturnObject &result) override {
13361344
Target *target = GetDebugger().GetSelectedTarget().get();
@@ -1447,46 +1455,6 @@ class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
14471455
return llvm::makeArrayRef(g_platform_process_attach_options);
14481456
}
14491457

1450-
void HandleOptionArgumentCompletion(
1451-
CompletionRequest &request, OptionElementVector &opt_element_vector,
1452-
int opt_element_index, CommandInterpreter &interpreter) override {
1453-
int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
1454-
int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
1455-
1456-
// We are only completing the name option for now...
1457-
1458-
// Are we in the name?
1459-
if (GetDefinitions()[opt_defs_index].short_option != 'n')
1460-
return;
1461-
1462-
// Look to see if there is a -P argument provided, and if so use that
1463-
// plugin, otherwise use the default plugin.
1464-
1465-
const char *partial_name = nullptr;
1466-
partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos);
1467-
1468-
PlatformSP platform_sp(interpreter.GetPlatform(true));
1469-
if (!platform_sp)
1470-
return;
1471-
1472-
ProcessInstanceInfoList process_infos;
1473-
ProcessInstanceInfoMatch match_info;
1474-
if (partial_name) {
1475-
match_info.GetProcessInfo().GetExecutableFile().SetFile(
1476-
partial_name, FileSpec::Style::native);
1477-
match_info.SetNameMatchType(NameMatch::StartsWith);
1478-
}
1479-
platform_sp->FindProcesses(match_info, process_infos);
1480-
const uint32_t num_matches = process_infos.size();
1481-
if (num_matches == 0)
1482-
return;
1483-
1484-
for (uint32_t i = 0; i < num_matches; ++i) {
1485-
request.AddCompletion(process_infos[i].GetNameAsStringRef());
1486-
}
1487-
return;
1488-
}
1489-
14901458
// Options table: Required for subclasses of Options.
14911459

14921460
static OptionDefinition g_option_table[];

lldb/source/Commands/CommandObjectProcess.cpp

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -320,49 +320,6 @@ class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach {
320320
return llvm::makeArrayRef(g_process_attach_options);
321321
}
322322

323-
void HandleOptionArgumentCompletion(
324-
CompletionRequest &request, OptionElementVector &opt_element_vector,
325-
int opt_element_index, CommandInterpreter &interpreter) override {
326-
int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
327-
int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
328-
329-
switch (GetDefinitions()[opt_defs_index].short_option) {
330-
case 'n': {
331-
// Look to see if there is a -P argument provided, and if so use that
332-
// plugin, otherwise use the default plugin.
333-
334-
const char *partial_name = nullptr;
335-
partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos);
336-
337-
PlatformSP platform_sp(interpreter.GetPlatform(true));
338-
if (!platform_sp)
339-
return;
340-
ProcessInstanceInfoList process_infos;
341-
ProcessInstanceInfoMatch match_info;
342-
if (partial_name) {
343-
match_info.GetProcessInfo().GetExecutableFile().SetFile(
344-
partial_name, FileSpec::Style::native);
345-
match_info.SetNameMatchType(NameMatch::StartsWith);
346-
}
347-
platform_sp->FindProcesses(match_info, process_infos);
348-
const size_t num_matches = process_infos.size();
349-
if (num_matches == 0)
350-
return;
351-
for (size_t i = 0; i < num_matches; ++i) {
352-
request.AddCompletion(process_infos[i].GetNameAsStringRef());
353-
}
354-
} break;
355-
356-
case 'P':
357-
CommandCompletions::InvokeCommonCompletionCallbacks(
358-
interpreter, CommandCompletions::eProcessPluginCompletion, request,
359-
nullptr);
360-
break;
361-
}
362-
}
363-
364-
// Instance variables to hold the values for command options.
365-
366323
ProcessAttachInfo attach_info;
367324
};
368325

lldb/source/Interpreter/CommandObject.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,9 +1078,9 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = {
10781078
{ eArgTypePath, "path", CommandCompletions::eDiskFileCompletion, { nullptr, false }, "Path." },
10791079
{ eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as an octal number (e.g. 755)." },
10801080
{ eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as a string value (e.g. rw-r-xr--)." },
1081-
{ eArgTypePid, "pid", CommandCompletions::eNoCompletion, { nullptr, false }, "The process ID number." },
1081+
{ eArgTypePid, "pid", CommandCompletions::eProcessIDCompletion, { nullptr, false }, "The process ID number." },
10821082
{ eArgTypePlugin, "plugin", CommandCompletions::eProcessPluginCompletion, { nullptr, false }, "Help text goes here." },
1083-
{ eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of the process." },
1083+
{ eArgTypeProcessName, "process-name", CommandCompletions::eProcessNameCompletion, { nullptr, false }, "The name of the process." },
10841084
{ eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python class." },
10851085
{ eArgTypePythonFunction, "python-function", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python function." },
10861086
{ eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { nullptr, false }, "Source code written in Python." },

lldb/test/API/functionalities/completion/TestCompletion.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66

77
import os
8+
from multiprocessing import Process
9+
import psutil
810
import lldb
911
from lldbsuite.test.decorators import *
1012
from lldbsuite.test.lldbtest import *
@@ -117,6 +119,27 @@ def test_process_plugin_completion(self):
117119
self.complete_from_to('process ' + subcommand + ' mac',
118120
'process ' + subcommand + ' mach-o-core')
119121

122+
@skipIfRemote
123+
def test_common_completion_process_pid_and_name(self):
124+
# The LLDB process itself and the process already attached to are both
125+
# ignored by the process discovery mechanism, thus we need a process known
126+
# to us here.
127+
self.build()
128+
server = self.spawnSubprocess(
129+
self.getBuildArtifact("a.out"),
130+
["-x"], # Arg "-x" makes the subprocess wait for input thus it won't be terminated too early
131+
install_remote=False)
132+
self.assertIsNotNone(server)
133+
pid = server.pid
134+
135+
self.complete_from_to('process attach -p ', [str(pid)])
136+
self.complete_from_to('platform process attach -p ', [str(pid)])
137+
self.complete_from_to('platform process info ', [str(pid)])
138+
139+
pname = psutil.Process(pid).name() # FIXME: psutil doesn't work for remote
140+
self.complete_from_to('process attach -n ', [str(pname)])
141+
self.complete_from_to('platform process attach -n ', [str(pname)])
142+
120143
def test_process_signal(self):
121144
# The tab completion for "process signal" won't work without a running process.
122145
self.complete_from_to('process signal ',
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <iostream>
2+
13
class Foo
24
{
35
public:
@@ -11,14 +13,16 @@ namespace { int Quux (void) { return 0; } }
1113

1214
struct Container { int MemberVar; };
1315

14-
int main()
15-
{
16-
Foo fooo;
17-
Foo *ptr_fooo = &fooo;
18-
fooo.Bar(1, 2);
16+
int main(int argc, char *argv[]) {
17+
if (argc > 1 && std::string(argv[1]) == "-x")
18+
std::cin.get();
19+
20+
Foo fooo;
21+
Foo *ptr_fooo = &fooo;
22+
fooo.Bar(1, 2);
1923

20-
Container container;
21-
Container *ptr_container = &container;
22-
int q = Quux();
23-
return container.MemberVar = 3; // Break here
24+
Container container;
25+
Container *ptr_container = &container;
26+
int q = Quux();
27+
return container.MemberVar = 3; // Break here
2428
}

0 commit comments

Comments
 (0)