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