Index: lldb/include/lldb/Interpreter/CommandCompletions.h =================================================================== --- lldb/include/lldb/Interpreter/CommandCompletions.h +++ lldb/include/lldb/Interpreter/CommandCompletions.h @@ -36,11 +36,12 @@ eVariablePathCompletion = (1u << 8), eRegisterCompletion = (1u << 9), eBreakpointCompletion = (1u << 10), - eProcessPluginCompletion = (1u << 11), + eBreakpointNameCompletion = (1u << 11), + eProcessPluginCompletion = (1u << 12), // This item serves two purposes. It is the last element in the enum, so // you can add custom enums starting from here in your Option class. Also // if you & in this bit the base code will not process the option. - eCustomCompletion = (1u << 12) + eCustomCompletion = (1u << 13) }; static bool InvokeCommonCompletionCallbacks( @@ -91,6 +92,9 @@ static void Breakpoints(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + static void BreakpointNames(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + static void ProcessPluginNames(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); Index: lldb/source/Commands/CommandCompletions.cpp =================================================================== --- lldb/source/Commands/CommandCompletions.cpp +++ lldb/source/Commands/CommandCompletions.cpp @@ -58,6 +58,7 @@ {eVariablePathCompletion, CommandCompletions::VariablePath}, {eRegisterCompletion, CommandCompletions::Registers}, {eBreakpointCompletion, CommandCompletions::Breakpoints}, + {eBreakpointNameCompletion, CommandCompletions::BreakpointNames}, {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames}, {eNoCompletion, nullptr} // This one has to be last in the list. }; @@ -588,9 +589,23 @@ } } +void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget(); + if (!target) + return; + + std::vector name_list; + target->GetBreakpointNames(name_list); + + for (const std::string &name : name_list) + request.TryCompleteCurrentArg(name); +} + void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(), request); } \ No newline at end of file Index: lldb/source/Commands/CommandObjectBreakpoint.cpp =================================================================== --- lldb/source/Commands/CommandObjectBreakpoint.cpp +++ lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -2081,6 +2081,80 @@ return llvm::makeArrayRef(g_breakpoint_read_options); } + void HandleOptionArgumentCompletion( + CompletionRequest &request, OptionElementVector &opt_element_vector, + int opt_element_index, CommandInterpreter &interpreter) override { + int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; + int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; + + switch (GetDefinitions()[opt_defs_index].short_option) { + case 'f': + CommandCompletions::InvokeCommonCompletionCallbacks( + interpreter, CommandCompletions::eDiskFileCompletion, request, + nullptr); + break; + + case 'N': + llvm::Optional file_spec; + for (int arg_idx = 0; arg_idx < opt_arg_pos; arg_idx++) { + if (!strcmp("-f", + request.GetParsedLine().GetArgumentAtIndex(arg_idx))) { + file_spec.emplace( + request.GetParsedLine().GetArgumentAtIndex(arg_idx + 1)); + break; + } + } + if (!file_spec.hasValue()) + return; + + FileSystem::Instance().Resolve(file_spec.getValue()); + Status error; + StructuredData::ObjectSP input_data_sp = + StructuredData::ParseJSONFromFile(file_spec.getValue(), error); + if (!error.Success()) + return; + + StructuredData::Array *bkpt_array = input_data_sp->GetAsArray(); + if (!bkpt_array) + return; + + const size_t num_bkpts = bkpt_array->GetSize(); + for (size_t i = 0; i < num_bkpts; i++) { + StructuredData::ObjectSP bkpt_object_sp = + bkpt_array->GetItemAtIndex(i); + if (!bkpt_object_sp) + return; + + StructuredData::Dictionary *bkpt_dict = + bkpt_object_sp->GetAsDictionary(); + if (!bkpt_dict) + return; + + StructuredData::ObjectSP bkpt_data_sp = + bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); + if (!bkpt_data_sp) + return; + + bkpt_dict = bkpt_data_sp->GetAsDictionary(); + if (!bkpt_dict) + return; + + StructuredData::Array *names_array; + + if (!bkpt_dict->GetValueForKeyAsArray("Names", names_array)) + return; + + size_t num_names = names_array->GetSize(); + + for (size_t i = 0; i < num_names; i++) { + llvm::StringRef name; + if (names_array->GetItemAtIndexAsString(i, name)) + request.TryCompleteCurrentArg(name); + } + } + } + } + // Instance variables to hold the values for command options. std::string m_filename; Index: lldb/source/Interpreter/CommandObject.cpp =================================================================== --- lldb/source/Interpreter/CommandObject.cpp +++ lldb/source/Interpreter/CommandObject.cpp @@ -1041,7 +1041,7 @@ { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { nullptr, false }, "A Boolean value: 'true' or 'false'" }, { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, nullptr }, { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, nullptr }, - { eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eNoCompletion, { BreakpointNameHelpTextCallback, false }, nullptr }, + { eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eBreakpointNameCompletion, { BreakpointNameHelpTextCallback, false }, nullptr }, { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { nullptr, false }, "Number of bytes to use." }, { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { nullptr, false }, "Then name of a class from the debug information in the program." }, { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A debugger command (may be multiple words), without any options or arguments." }, Index: lldb/test/API/functionalities/completion/TestCompletion.py =================================================================== --- lldb/test/API/functionalities/completion/TestCompletion.py +++ lldb/test/API/functionalities/completion/TestCompletion.py @@ -536,3 +536,21 @@ ['1', '2']) + def test_complete_breakpoint_with_names(self): + self.build() + target = self.dbg.CreateTarget(self.getBuildArtifact('a.out')) + self.assertTrue(target, VALID_TARGET) + + # test breakpoint read dedicated + self.complete_from_to('breakpoint read -N ', 'breakpoint read -N ') + self.complete_from_to('breakpoint read -f breakpoints.json -N ', ['mm']) + self.complete_from_to('breakpoint read -f breakpoints.json -N n', 'breakpoint read -f breakpoints.json -N n') + self.complete_from_to('breakpoint read -f breakpoints_invalid.json -N ', 'breakpoint read -f breakpoints_invalid.json -N ') + + # test common breapoint name completion + bp1 = target.BreakpointCreateByName('main', 'a.out') + self.assertTrue(bp1) + self.assertEqual(bp1.GetNumLocations(), 1) + self.complete_from_to('breakpoint set -N n', 'breakpoint set -N n') + self.assertTrue(bp1.AddNameWithErrorHandling("nn")) + self.complete_from_to('breakpoint set -N ', 'breakpoint set -N nn') Index: lldb/test/API/functionalities/completion/breakpoints.json =================================================================== --- /dev/null +++ lldb/test/API/functionalities/completion/breakpoints.json @@ -0,0 +1,34 @@ +[ + { + "Breakpoint": { + "BKPTOptions": { + "AutoContinue": false, + "ConditionText": "", + "EnabledState": true, + "IgnoreCount": 0, + "OneShotState": false + }, + "BKPTResolver": { + "Options": { + "NameMask": [ + 56 + ], + "Offset": 0, + "SkipPrologue": true, + "SymbolNames": [ + "main" + ] + }, + "Type": "SymbolName" + }, + "Hardware": false, + "Names": [ + "mm" + ], + "SearchFilter": { + "Options": {}, + "Type": "Unconstrained" + } + } + } +] \ No newline at end of file Index: lldb/test/API/functionalities/completion/breakpoints_invalid.json =================================================================== --- /dev/null +++ lldb/test/API/functionalities/completion/breakpoints_invalid.json @@ -0,0 +1,6 @@ +[ + { + "Breakpoint": { + } + } +]