Coverage Report

Created: 2023-11-11 10:31

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