1//===-- CommandCompletions.cpp --------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ADT/SmallString.h"
10#include "llvm/ADT/StringSet.h"
11
12#include "lldb/Breakpoint/Watchpoint.h"
13#include "lldb/Core/Module.h"
14#include "lldb/Core/PluginManager.h"
15#include "lldb/DataFormatters/DataVisualization.h"
16#include "lldb/Host/FileSystem.h"
17#include "lldb/Interpreter/CommandCompletions.h"
18#include "lldb/Interpreter/CommandInterpreter.h"
19#include "lldb/Interpreter/CommandObject.h"
20#include "lldb/Interpreter/CommandObjectMultiword.h"
21#include "lldb/Interpreter/OptionValueProperties.h"
22#include "lldb/Symbol/CompileUnit.h"
23#include "lldb/Symbol/Variable.h"
24#include "lldb/Target/Language.h"
25#include "lldb/Target/Process.h"
26#include "lldb/Target/RegisterContext.h"
27#include "lldb/Target/Thread.h"
28#include "lldb/Utility/FileSpec.h"
29#include "lldb/Utility/FileSpecList.h"
30#include "lldb/Utility/StreamString.h"
31#include "lldb/Utility/TildeExpressionResolver.h"
32
33#include "llvm/Support/FileSystem.h"
34#include "llvm/Support/Path.h"
35
36using namespace lldb_private;
37
38// This is the command completion callback that is used to complete the
39// argument of the option it is bound to (in the OptionDefinition table
40// below).
41typedef void (*CompletionCallback)(CommandInterpreter &interpreter,
42                                   CompletionRequest &request,
43                                   // A search filter to limit the search...
44                                   lldb_private::SearchFilter *searcher);
45
46struct CommonCompletionElement {
47  uint64_t type;
48  CompletionCallback callback;
49};
50
51bool CommandCompletions::InvokeCommonCompletionCallbacks(
52    CommandInterpreter &interpreter, uint32_t completion_mask,
53    CompletionRequest &request, SearchFilter *searcher) {
54  bool handled = false;
55
56  const CommonCompletionElement common_completions[] = {
57      {lldb::eNoCompletion, nullptr},
58      {lldb::eSourceFileCompletion, CommandCompletions::SourceFiles},
59      {lldb::eDiskFileCompletion, CommandCompletions::DiskFiles},
60      {lldb::eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
61      {lldb::eSymbolCompletion, CommandCompletions::Symbols},
62      {lldb::eModuleCompletion, CommandCompletions::Modules},
63      {lldb::eModuleUUIDCompletion, CommandCompletions::ModuleUUIDs},
64      {lldb::eSettingsNameCompletion, CommandCompletions::SettingsNames},
65      {lldb::ePlatformPluginCompletion,
66       CommandCompletions::PlatformPluginNames},
67      {lldb::eArchitectureCompletion, CommandCompletions::ArchitectureNames},
68      {lldb::eVariablePathCompletion, CommandCompletions::VariablePath},
69      {lldb::eRegisterCompletion, CommandCompletions::Registers},
70      {lldb::eBreakpointCompletion, CommandCompletions::Breakpoints},
71      {lldb::eProcessPluginCompletion, CommandCompletions::ProcessPluginNames},
72      {lldb::eDisassemblyFlavorCompletion,
73       CommandCompletions::DisassemblyFlavors},
74      {lldb::eTypeLanguageCompletion, CommandCompletions::TypeLanguages},
75      {lldb::eFrameIndexCompletion, CommandCompletions::FrameIndexes},
76      {lldb::eStopHookIDCompletion, CommandCompletions::StopHookIDs},
77      {lldb::eThreadIndexCompletion, CommandCompletions::ThreadIndexes},
78      {lldb::eWatchpointIDCompletion, CommandCompletions::WatchPointIDs},
79      {lldb::eBreakpointNameCompletion, CommandCompletions::BreakpointNames},
80      {lldb::eProcessIDCompletion, CommandCompletions::ProcessIDs},
81      {lldb::eProcessNameCompletion, CommandCompletions::ProcessNames},
82      {lldb::eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles},
83      {lldb::eRemoteDiskDirectoryCompletion,
84       CommandCompletions::RemoteDiskDirectories},
85      {lldb::eTypeCategoryNameCompletion,
86       CommandCompletions::TypeCategoryNames},
87      {lldb::eThreadIDCompletion, CommandCompletions::ThreadIDs},
88      {lldb::eTerminatorCompletion,
89       nullptr} // This one has to be last in the list.
90  };
91
92  for (int i = 0;; i++) {
93    if (common_completions[i].type == lldb::eTerminatorCompletion)
94      break;
95    else if ((common_completions[i].type & completion_mask) ==
96                 common_completions[i].type &&
97             common_completions[i].callback != nullptr) {
98      handled = true;
99      common_completions[i].callback(interpreter, request, searcher);
100    }
101  }
102  return handled;
103}
104
105namespace {
106// The Completer class is a convenient base class for building searchers that
107// go along with the SearchFilter passed to the standard Completer functions.
108class Completer : public Searcher {
109public:
110  Completer(CommandInterpreter &interpreter, CompletionRequest &request)
111      : m_interpreter(interpreter), m_request(request) {}
112
113  ~Completer() override = default;
114
115  CallbackReturn SearchCallback(SearchFilter &filter, SymbolContext &context,
116                                Address *addr) override = 0;
117
118  lldb::SearchDepth GetDepth() override = 0;
119
120  virtual void DoCompletion(SearchFilter *filter) = 0;
121
122protected:
123  CommandInterpreter &m_interpreter;
124  CompletionRequest &m_request;
125
126private:
127  Completer(const Completer &) = delete;
128  const Completer &operator=(const Completer &) = delete;
129};
130} // namespace
131
132// SourceFileCompleter implements the source file completer
133namespace {
134class SourceFileCompleter : public Completer {
135public:
136  SourceFileCompleter(CommandInterpreter &interpreter,
137                      CompletionRequest &request)
138      : Completer(interpreter, request) {
139    FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
140    m_file_name = partial_spec.GetFilename().GetCString();
141    m_dir_name = partial_spec.GetDirectory().GetCString();
142  }
143
144  lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthCompUnit; }
145
146  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
147                                          SymbolContext &context,
148                                          Address *addr) override {
149    if (context.comp_unit != nullptr) {
150      const char *cur_file_name =
151          context.comp_unit->GetPrimaryFile().GetFilename().GetCString();
152      const char *cur_dir_name =
153          context.comp_unit->GetPrimaryFile().GetDirectory().GetCString();
154
155      bool match = false;
156      if (m_file_name && cur_file_name &&
157          strstr(cur_file_name, m_file_name) == cur_file_name)
158        match = true;
159
160      if (match && m_dir_name && cur_dir_name &&
161          strstr(cur_dir_name, m_dir_name) != cur_dir_name)
162        match = false;
163
164      if (match) {
165        m_matching_files.AppendIfUnique(context.comp_unit->GetPrimaryFile());
166      }
167    }
168    return Searcher::eCallbackReturnContinue;
169  }
170
171  void DoCompletion(SearchFilter *filter) override {
172    filter->Search(*this);
173    // Now convert the filelist to completions:
174    for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
175      m_request.AddCompletion(
176          m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
177    }
178  }
179
180private:
181  FileSpecList m_matching_files;
182  const char *m_file_name;
183  const char *m_dir_name;
184
185  SourceFileCompleter(const SourceFileCompleter &) = delete;
186  const SourceFileCompleter &operator=(const SourceFileCompleter &) = delete;
187};
188} // namespace
189
190static bool regex_chars(const char comp) {
191  return llvm::StringRef("[](){}+.*|^$\\?").contains(comp);
192}
193
194namespace {
195class SymbolCompleter : public Completer {
196
197public:
198  SymbolCompleter(CommandInterpreter &interpreter, CompletionRequest &request)
199      : Completer(interpreter, request) {
200    std::string regex_str;
201    if (!m_request.GetCursorArgumentPrefix().empty()) {
202      regex_str.append("^");
203      regex_str.append(std::string(m_request.GetCursorArgumentPrefix()));
204    } else {
205      // Match anything since the completion string is empty
206      regex_str.append(".");
207    }
208    std::string::iterator pos =
209        find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
210    while (pos < regex_str.end()) {
211      pos = regex_str.insert(pos, '\\');
212      pos = find_if(pos + 2, regex_str.end(), regex_chars);
213    }
214    m_regex = RegularExpression(regex_str);
215  }
216
217  lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; }
218
219  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
220                                          SymbolContext &context,
221                                          Address *addr) override {
222    if (context.module_sp) {
223      SymbolContextList sc_list;
224      ModuleFunctionSearchOptions function_options;
225      function_options.include_symbols = true;
226      function_options.include_inlines = true;
227      context.module_sp->FindFunctions(m_regex, function_options, sc_list);
228
229      // Now add the functions & symbols to the list - only add if unique:
230      for (const SymbolContext &sc : sc_list) {
231        ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
232        // Ensure that the function name matches the regex. This is more than
233        // a sanity check. It is possible that the demangled function name
234        // does not start with the prefix, for example when it's in an
235        // anonymous namespace.
236        if (!func_name.IsEmpty() && m_regex.Execute(func_name.GetStringRef()))
237          m_match_set.insert(func_name);
238      }
239    }
240    return Searcher::eCallbackReturnContinue;
241  }
242
243  void DoCompletion(SearchFilter *filter) override {
244    filter->Search(*this);
245    collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
246    for (pos = m_match_set.begin(); pos != end; pos++)
247      m_request.AddCompletion((*pos).GetCString());
248  }
249
250private:
251  RegularExpression m_regex;
252  typedef std::set<ConstString> collection;
253  collection m_match_set;
254
255  SymbolCompleter(const SymbolCompleter &) = delete;
256  const SymbolCompleter &operator=(const SymbolCompleter &) = delete;
257};
258} // namespace
259
260namespace {
261class ModuleCompleter : public Completer {
262public:
263  ModuleCompleter(CommandInterpreter &interpreter, CompletionRequest &request)
264      : Completer(interpreter, request) {
265    FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
266    m_file_name = partial_spec.GetFilename().GetCString();
267    m_dir_name = partial_spec.GetDirectory().GetCString();
268  }
269
270  lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; }
271
272  Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
273                                          SymbolContext &context,
274                                          Address *addr) override {
275    if (context.module_sp) {
276      const char *cur_file_name =
277          context.module_sp->GetFileSpec().GetFilename().GetCString();
278      const char *cur_dir_name =
279          context.module_sp->GetFileSpec().GetDirectory().GetCString();
280
281      bool match = false;
282      if (m_file_name && cur_file_name &&
283          strstr(cur_file_name, m_file_name) == cur_file_name)
284        match = true;
285
286      if (match && m_dir_name && cur_dir_name &&
287          strstr(cur_dir_name, m_dir_name) != cur_dir_name)
288        match = false;
289
290      if (match) {
291        m_request.AddCompletion(cur_file_name);
292      }
293    }
294    return Searcher::eCallbackReturnContinue;
295  }
296
297  void DoCompletion(SearchFilter *filter) override { filter->Search(*this); }
298
299private:
300  const char *m_file_name;
301  const char *m_dir_name;
302
303  ModuleCompleter(const ModuleCompleter &) = delete;
304  const ModuleCompleter &operator=(const ModuleCompleter &) = delete;
305};
306} // namespace
307
308void CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
309                                     CompletionRequest &request,
310                                     SearchFilter *searcher) {
311  SourceFileCompleter completer(interpreter, request);
312
313  if (searcher == nullptr) {
314    lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
315    SearchFilterForUnconstrainedSearches null_searcher(target_sp);
316    completer.DoCompletion(&null_searcher);
317  } else {
318    completer.DoCompletion(searcher);
319  }
320}
321
322static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
323                                   bool only_directories,
324                                   CompletionRequest &request,
325                                   TildeExpressionResolver &Resolver) {
326  llvm::SmallString<256> CompletionBuffer;
327  llvm::SmallString<256> Storage;
328  partial_name.toVector(CompletionBuffer);
329
330  if (CompletionBuffer.size() >= PATH_MAX)
331    return;
332
333  namespace path = llvm::sys::path;
334
335  llvm::StringRef SearchDir;
336  llvm::StringRef PartialItem;
337
338  if (CompletionBuffer.starts_with("~")) {
339    llvm::StringRef Buffer = CompletionBuffer;
340    size_t FirstSep =
341        Buffer.find_if([](char c) { return path::is_separator(c); });
342
343    llvm::StringRef Username = Buffer.take_front(FirstSep);
344    llvm::StringRef Remainder;
345    if (FirstSep != llvm::StringRef::npos)
346      Remainder = Buffer.drop_front(FirstSep + 1);
347
348    llvm::SmallString<256> Resolved;
349    if (!Resolver.ResolveExact(Username, Resolved)) {
350      // We couldn't resolve it as a full username.  If there were no slashes
351      // then this might be a partial username.   We try to resolve it as such
352      // but after that, we're done regardless of any matches.
353      if (FirstSep == llvm::StringRef::npos) {
354        llvm::StringSet<> MatchSet;
355        Resolver.ResolvePartial(Username, MatchSet);
356        for (const auto &S : MatchSet) {
357          Resolved = S.getKey();
358          path::append(Resolved, path::get_separator());
359          request.AddCompletion(Resolved, "", CompletionMode::Partial);
360        }
361      }
362      return;
363    }
364
365    // If there was no trailing slash, then we're done as soon as we resolve
366    // the expression to the correct directory.  Otherwise we need to continue
367    // looking for matches within that directory.
368    if (FirstSep == llvm::StringRef::npos) {
369      // Make sure it ends with a separator.
370      path::append(CompletionBuffer, path::get_separator());
371      request.AddCompletion(CompletionBuffer, "", CompletionMode::Partial);
372      return;
373    }
374
375    // We want to keep the form the user typed, so we special case this to
376    // search in the fully resolved directory, but CompletionBuffer keeps the
377    // unmodified form that the user typed.
378    Storage = Resolved;
379    llvm::StringRef RemainderDir = path::parent_path(Remainder);
380    if (!RemainderDir.empty()) {
381      // Append the remaining path to the resolved directory.
382      Storage.append(path::get_separator());
383      Storage.append(RemainderDir);
384    }
385    SearchDir = Storage;
386  } else if (CompletionBuffer == path::root_directory(CompletionBuffer)) {
387    SearchDir = CompletionBuffer;
388  } else {
389    SearchDir = path::parent_path(CompletionBuffer);
390  }
391
392  size_t FullPrefixLen = CompletionBuffer.size();
393
394  PartialItem = path::filename(CompletionBuffer);
395
396  // path::filename() will return "." when the passed path ends with a
397  // directory separator or the separator when passed the disk root directory.
398  // We have to filter those out, but only when the "." doesn't come from the
399  // completion request itself.
400  if ((PartialItem == "." || PartialItem == path::get_separator()) &&
401      path::is_separator(CompletionBuffer.back()))
402    PartialItem = llvm::StringRef();
403
404  if (SearchDir.empty()) {
405    llvm::sys::fs::current_path(Storage);
406    SearchDir = Storage;
407  }
408  assert(!PartialItem.contains(path::get_separator()));
409
410  // SearchDir now contains the directory to search in, and Prefix contains the
411  // text we want to match against items in that directory.
412
413  FileSystem &fs = FileSystem::Instance();
414  std::error_code EC;
415  llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC);
416  llvm::vfs::directory_iterator End;
417  for (; Iter != End && !EC; Iter.increment(EC)) {
418    auto &Entry = *Iter;
419    llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path());
420
421    if (!Status)
422      continue;
423
424    auto Name = path::filename(Entry.path());
425
426    // Omit ".", ".."
427    if (Name == "." || Name == ".." || !Name.starts_with(PartialItem))
428      continue;
429
430    bool is_dir = Status->isDirectory();
431
432    // If it's a symlink, then we treat it as a directory as long as the target
433    // is a directory.
434    if (Status->isSymlink()) {
435      FileSpec symlink_filespec(Entry.path());
436      FileSpec resolved_filespec;
437      auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec);
438      if (error.Success())
439        is_dir = fs.IsDirectory(symlink_filespec);
440    }
441
442    if (only_directories && !is_dir)
443      continue;
444
445    // Shrink it back down so that it just has the original prefix the user
446    // typed and remove the part of the name which is common to the located
447    // item and what the user typed.
448    CompletionBuffer.resize(FullPrefixLen);
449    Name = Name.drop_front(PartialItem.size());
450    CompletionBuffer.append(Name);
451
452    if (is_dir) {
453      path::append(CompletionBuffer, path::get_separator());
454    }
455
456    CompletionMode mode =
457        is_dir ? CompletionMode::Partial : CompletionMode::Normal;
458    request.AddCompletion(CompletionBuffer, "", mode);
459  }
460}
461
462static void DiskFilesOrDirectories(const llvm::Twine &partial_name,
463                                   bool only_directories, StringList &matches,
464                                   TildeExpressionResolver &Resolver) {
465  CompletionResult result;
466  std::string partial_name_str = partial_name.str();
467  CompletionRequest request(partial_name_str, partial_name_str.size(), result);
468  DiskFilesOrDirectories(partial_name, only_directories, request, Resolver);
469  result.GetMatches(matches);
470}
471
472static void DiskFilesOrDirectories(CompletionRequest &request,
473                                   bool only_directories) {
474  StandardTildeExpressionResolver resolver;
475  DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories,
476                         request, resolver);
477}
478
479void CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
480                                   CompletionRequest &request,
481                                   SearchFilter *searcher) {
482  DiskFilesOrDirectories(request, /*only_dirs*/ false);
483}
484
485void CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name,
486                                   StringList &matches,
487                                   TildeExpressionResolver &Resolver) {
488  DiskFilesOrDirectories(partial_file_name, false, matches, Resolver);
489}
490
491void CommandCompletions::DiskDirectories(CommandInterpreter &interpreter,
492                                         CompletionRequest &request,
493                                         SearchFilter *searcher) {
494  DiskFilesOrDirectories(request, /*only_dirs*/ true);
495}
496
497void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
498                                         StringList &matches,
499                                         TildeExpressionResolver &Resolver) {
500  DiskFilesOrDirectories(partial_file_name, true, matches, Resolver);
501}
502
503void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter,
504                                         CompletionRequest &request,
505                                         SearchFilter *searcher) {
506  lldb::PlatformSP platform_sp =
507      interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
508  if (platform_sp)
509    platform_sp->AutoCompleteDiskFileOrDirectory(request, false);
510}
511
512void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter,
513                                               CompletionRequest &request,
514                                               SearchFilter *searcher) {
515  lldb::PlatformSP platform_sp =
516      interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
517  if (platform_sp)
518    platform_sp->AutoCompleteDiskFileOrDirectory(request, true);
519}
520
521void CommandCompletions::Modules(CommandInterpreter &interpreter,
522                                 CompletionRequest &request,
523                                 SearchFilter *searcher) {
524  ModuleCompleter completer(interpreter, request);
525
526  if (searcher == nullptr) {
527    lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
528    SearchFilterForUnconstrainedSearches null_searcher(target_sp);
529    completer.DoCompletion(&null_searcher);
530  } else {
531    completer.DoCompletion(searcher);
532  }
533}
534
535void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter,
536                                     CompletionRequest &request,
537                                     SearchFilter *searcher) {
538  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
539  if (!exe_ctx.HasTargetScope())
540    return;
541
542  exe_ctx.GetTargetPtr()->GetImages().ForEach(
543      [&request](const lldb::ModuleSP &module) {
544        StreamString strm;
545        module->GetDescription(strm.AsRawOstream(),
546                               lldb::eDescriptionLevelInitial);
547        request.TryCompleteCurrentArg(module->GetUUID().GetAsString(),
548                                      strm.GetString());
549        return true;
550      });
551}
552
553void CommandCompletions::Symbols(CommandInterpreter &interpreter,
554                                 CompletionRequest &request,
555                                 SearchFilter *searcher) {
556  SymbolCompleter completer(interpreter, request);
557
558  if (searcher == nullptr) {
559    lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
560    SearchFilterForUnconstrainedSearches null_searcher(target_sp);
561    completer.DoCompletion(&null_searcher);
562  } else {
563    completer.DoCompletion(searcher);
564  }
565}
566
567void CommandCompletions::SettingsNames(CommandInterpreter &interpreter,
568                                       CompletionRequest &request,
569                                       SearchFilter *searcher) {
570  // Cache the full setting name list
571  static StringList g_property_names;
572  if (g_property_names.GetSize() == 0) {
573    // Generate the full setting name list on demand
574    lldb::OptionValuePropertiesSP properties_sp(
575        interpreter.GetDebugger().GetValueProperties());
576    if (properties_sp) {
577      StreamString strm;
578      properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
579      const std::string &str = std::string(strm.GetString());
580      g_property_names.SplitIntoLines(str.c_str(), str.size());
581    }
582  }
583
584  for (const std::string &s : g_property_names)
585    request.TryCompleteCurrentArg(s);
586}
587
588void CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter,
589                                             CompletionRequest &request,
590                                             SearchFilter *searcher) {
591  PluginManager::AutoCompletePlatformName(request.GetCursorArgumentPrefix(),
592                                          request);
593}
594
595void CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter,
596                                           CompletionRequest &request,
597                                           SearchFilter *searcher) {
598  ArchSpec::AutoComplete(request);
599}
600
601void CommandCompletions::VariablePath(CommandInterpreter &interpreter,
602                                      CompletionRequest &request,
603                                      SearchFilter *searcher) {
604  Variable::AutoComplete(interpreter.GetExecutionContext(), request);
605}
606
607void CommandCompletions::Registers(CommandInterpreter &interpreter,
608                                   CompletionRequest &request,
609                                   SearchFilter *searcher) {
610  std::string reg_prefix;
611  if (request.GetCursorArgumentPrefix().starts_with("$"))
612    reg_prefix = "$";
613
614  RegisterContext *reg_ctx =
615      interpreter.GetExecutionContext().GetRegisterContext();
616  if (!reg_ctx)
617    return;
618
619  const size_t reg_num = reg_ctx->GetRegisterCount();
620  for (size_t reg_idx = 0; reg_idx < reg_num; ++reg_idx) {
621    const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx);
622    request.TryCompleteCurrentArg(reg_prefix + reg_info->name,
623                                  reg_info->alt_name);
624  }
625}
626
627void CommandCompletions::Breakpoints(CommandInterpreter &interpreter,
628                                     CompletionRequest &request,
629                                     SearchFilter *searcher) {
630  lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget();
631  if (!target)
632    return;
633
634  const BreakpointList &breakpoints = target->GetBreakpointList();
635
636  std::unique_lock<std::recursive_mutex> lock;
637  target->GetBreakpointList().GetListMutex(lock);
638
639  size_t num_breakpoints = breakpoints.GetSize();
640  if (num_breakpoints == 0)
641    return;
642
643  for (size_t i = 0; i < num_breakpoints; ++i) {
644    lldb::BreakpointSP bp = breakpoints.GetBreakpointAtIndex(i);
645
646    StreamString s;
647    bp->GetDescription(&s, lldb::eDescriptionLevelBrief);
648    llvm::StringRef bp_info = s.GetString();
649
650    const size_t colon_pos = bp_info.find_first_of(':');
651    if (colon_pos != llvm::StringRef::npos)
652      bp_info = bp_info.drop_front(colon_pos + 2);
653
654    request.TryCompleteCurrentArg(std::to_string(bp->GetID()), bp_info);
655  }
656}
657
658void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter,
659                                         CompletionRequest &request,
660                                         SearchFilter *searcher) {
661  lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget();
662  if (!target)
663    return;
664
665  std::vector<std::string> name_list;
666  target->GetBreakpointNames(name_list);
667
668  for (const std::string &name : name_list)
669    request.TryCompleteCurrentArg(name);
670}
671
672void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter,
673                                            CompletionRequest &request,
674                                            SearchFilter *searcher) {
675  PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(),
676                                         request);
677}
678void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter,
679                                            CompletionRequest &request,
680                                            SearchFilter *searcher) {
681  // Currently the only valid options for disassemble -F are default, and for
682  // Intel architectures, att and intel.
683  static const char *flavors[] = {"default", "att", "intel"};
684  for (const char *flavor : flavors) {
685    request.TryCompleteCurrentArg(flavor);
686  }
687}
688
689void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter,
690                                    CompletionRequest &request,
691                                    SearchFilter *searcher) {
692  lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
693  if (!platform_sp)
694    return;
695  ProcessInstanceInfoList process_infos;
696  ProcessInstanceInfoMatch match_info;
697  platform_sp->FindProcesses(match_info, process_infos);
698  for (const ProcessInstanceInfo &info : process_infos)
699    request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()),
700                                  info.GetNameAsStringRef());
701}
702
703void CommandCompletions::ProcessNames(CommandInterpreter &interpreter,
704                                      CompletionRequest &request,
705                                      SearchFilter *searcher) {
706  lldb::PlatformSP platform_sp(interpreter.GetPlatform(true));
707  if (!platform_sp)
708    return;
709  ProcessInstanceInfoList process_infos;
710  ProcessInstanceInfoMatch match_info;
711  platform_sp->FindProcesses(match_info, process_infos);
712  for (const ProcessInstanceInfo &info : process_infos)
713    request.TryCompleteCurrentArg(info.GetNameAsStringRef());
714}
715
716void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter,
717                                       CompletionRequest &request,
718                                       SearchFilter *searcher) {
719  for (int bit :
720       Language::GetLanguagesSupportingTypeSystems().bitvector.set_bits()) {
721    request.TryCompleteCurrentArg(
722        Language::GetNameForLanguageType(static_cast<lldb::LanguageType>(bit)));
723  }
724}
725
726void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter,
727                                      CompletionRequest &request,
728                                      SearchFilter *searcher) {
729  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
730  if (!exe_ctx.HasProcessScope())
731    return;
732
733  lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP();
734  Debugger &dbg = interpreter.GetDebugger();
735  const uint32_t frame_num = thread_sp->GetStackFrameCount();
736  for (uint32_t i = 0; i < frame_num; ++i) {
737    lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
738    StreamString strm;
739    // Dumping frames can be slow, allow interruption.
740    if (INTERRUPT_REQUESTED(dbg, "Interrupted in frame completion"))
741      break;
742    frame_sp->Dump(&strm, false, true);
743    request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
744  }
745}
746
747void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter,
748                                     CompletionRequest &request,
749                                     SearchFilter *searcher) {
750  const lldb::TargetSP target_sp =
751      interpreter.GetExecutionContext().GetTargetSP();
752  if (!target_sp)
753    return;
754
755  const size_t num = target_sp->GetNumStopHooks();
756  for (size_t idx = 0; idx < num; ++idx) {
757    StreamString strm;
758    // The value 11 is an offset to make the completion description looks
759    // neater.
760    strm.SetIndentLevel(11);
761    const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx);
762    stophook_sp->GetDescription(strm, lldb::eDescriptionLevelInitial);
763    request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()),
764                                  strm.GetString());
765  }
766}
767
768void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter,
769                                       CompletionRequest &request,
770                                       SearchFilter *searcher) {
771  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
772  if (!exe_ctx.HasProcessScope())
773    return;
774
775  ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList();
776  lldb::ThreadSP thread_sp;
777  for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) {
778    StreamString strm;
779    thread_sp->GetStatus(strm, 0, 1, 1, true);
780    request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()),
781                                  strm.GetString());
782  }
783}
784
785void CommandCompletions::WatchPointIDs(CommandInterpreter &interpreter,
786                                       CompletionRequest &request,
787                                       SearchFilter *searcher) {
788  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
789  if (!exe_ctx.HasTargetScope())
790    return;
791
792  const WatchpointList &wp_list = exe_ctx.GetTargetPtr()->GetWatchpointList();
793  for (lldb::WatchpointSP wp_sp : wp_list.Watchpoints()) {
794    StreamString strm;
795    wp_sp->Dump(&strm);
796    request.TryCompleteCurrentArg(std::to_string(wp_sp->GetID()),
797                                  strm.GetString());
798  }
799}
800
801void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter,
802                                           CompletionRequest &request,
803                                           SearchFilter *searcher) {
804  DataVisualization::Categories::ForEach(
805      [&request](const lldb::TypeCategoryImplSP &category_sp) {
806        request.TryCompleteCurrentArg(category_sp->GetName(),
807                                      category_sp->GetDescription());
808        return true;
809      });
810}
811
812void CommandCompletions::ThreadIDs(CommandInterpreter &interpreter,
813                                   CompletionRequest &request,
814                                   SearchFilter *searcher) {
815  const ExecutionContext &exe_ctx = interpreter.GetExecutionContext();
816  if (!exe_ctx.HasProcessScope())
817    return;
818
819  ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList();
820  lldb::ThreadSP thread_sp;
821  for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) {
822    StreamString strm;
823    thread_sp->GetStatus(strm, 0, 1, 1, true);
824    request.TryCompleteCurrentArg(std::to_string(thread_sp->GetID()),
825                                  strm.GetString());
826  }
827}
828
829void CommandCompletions::CompleteModifiableCmdPathArgs(
830    CommandInterpreter &interpreter, CompletionRequest &request,
831    OptionElementVector &opt_element_vector) {
832  // The only arguments constitute a command path, however, there might be
833  // options interspersed among the arguments, and we need to skip those.  Do that
834  // by copying the args vector, and just dropping all the option bits:
835  Args args = request.GetParsedLine();
836  std::vector<size_t> to_delete;
837  for (auto &elem : opt_element_vector) {
838    to_delete.push_back(elem.opt_pos);
839    if (elem.opt_arg_pos != 0)
840      to_delete.push_back(elem.opt_arg_pos);
841  }
842  sort(to_delete.begin(), to_delete.end(), std::greater<size_t>());
843  for (size_t idx : to_delete)
844    args.DeleteArgumentAtIndex(idx);
845
846  // At this point, we should only have args, so now lookup the command up to
847  // the cursor element.
848
849  // There's nothing here but options.  It doesn't seem very useful here to
850  // dump all the commands, so just return.
851  size_t num_args = args.GetArgumentCount();
852  if (num_args == 0)
853    return;
854
855  // There's just one argument, so we should complete its name:
856  StringList matches;
857  if (num_args == 1) {
858    interpreter.GetUserCommandObject(args.GetArgumentAtIndex(0), &matches,
859                                     nullptr);
860    request.AddCompletions(matches);
861    return;
862  }
863
864  // There was more than one path element, lets find the containing command:
865  Status error;
866  CommandObjectMultiword *mwc =
867      interpreter.VerifyUserMultiwordCmdPath(args, true, error);
868
869  // Something was wrong somewhere along the path, but I don't think there's
870  // a good way to go back and fill in the missing elements:
871  if (error.Fail())
872    return;
873
874  // This should never happen.  We already handled the case of one argument
875  // above, and we can only get Success & nullptr back if there's a one-word
876  // leaf.
877  assert(mwc != nullptr);
878
879  mwc->GetSubcommandObject(args.GetArgumentAtIndex(num_args - 1), &matches);
880  if (matches.GetSize() == 0)
881    return;
882
883  request.AddCompletions(matches);
884}
885