1dda28197Spatrick //===-- CommandCompletions.cpp --------------------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9061da546Spatrick #include "llvm/ADT/SmallString.h" 10061da546Spatrick #include "llvm/ADT/StringSet.h" 11061da546Spatrick 12*be691f3bSpatrick #include "lldb/Breakpoint/Watchpoint.h" 13061da546Spatrick #include "lldb/Core/FileSpecList.h" 14061da546Spatrick #include "lldb/Core/Module.h" 15061da546Spatrick #include "lldb/Core/PluginManager.h" 16*be691f3bSpatrick #include "lldb/DataFormatters/DataVisualization.h" 17061da546Spatrick #include "lldb/Host/FileSystem.h" 18061da546Spatrick #include "lldb/Interpreter/CommandCompletions.h" 19061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h" 20061da546Spatrick #include "lldb/Interpreter/OptionValueProperties.h" 21061da546Spatrick #include "lldb/Symbol/CompileUnit.h" 22061da546Spatrick #include "lldb/Symbol/Variable.h" 23*be691f3bSpatrick #include "lldb/Target/Language.h" 24*be691f3bSpatrick #include "lldb/Target/Process.h" 25dda28197Spatrick #include "lldb/Target/RegisterContext.h" 26*be691f3bSpatrick #include "lldb/Target/Thread.h" 27061da546Spatrick #include "lldb/Utility/FileSpec.h" 28061da546Spatrick #include "lldb/Utility/StreamString.h" 29061da546Spatrick #include "lldb/Utility/TildeExpressionResolver.h" 30061da546Spatrick 31061da546Spatrick #include "llvm/Support/FileSystem.h" 32061da546Spatrick #include "llvm/Support/Path.h" 33061da546Spatrick 34061da546Spatrick using namespace lldb_private; 35061da546Spatrick 36dda28197Spatrick // This is the command completion callback that is used to complete the 37dda28197Spatrick // argument of the option it is bound to (in the OptionDefinition table 38dda28197Spatrick // below). 39dda28197Spatrick typedef void (*CompletionCallback)(CommandInterpreter &interpreter, 40dda28197Spatrick CompletionRequest &request, 41dda28197Spatrick // A search filter to limit the search... 42dda28197Spatrick lldb_private::SearchFilter *searcher); 43dda28197Spatrick 44dda28197Spatrick struct CommonCompletionElement { 45dda28197Spatrick uint32_t type; 46dda28197Spatrick CompletionCallback callback; 47dda28197Spatrick }; 48dda28197Spatrick 49dda28197Spatrick bool CommandCompletions::InvokeCommonCompletionCallbacks( 50dda28197Spatrick CommandInterpreter &interpreter, uint32_t completion_mask, 51dda28197Spatrick CompletionRequest &request, SearchFilter *searcher) { 52dda28197Spatrick bool handled = false; 53dda28197Spatrick 54dda28197Spatrick const CommonCompletionElement common_completions[] = { 55061da546Spatrick {eSourceFileCompletion, CommandCompletions::SourceFiles}, 56061da546Spatrick {eDiskFileCompletion, CommandCompletions::DiskFiles}, 57061da546Spatrick {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, 58061da546Spatrick {eSymbolCompletion, CommandCompletions::Symbols}, 59061da546Spatrick {eModuleCompletion, CommandCompletions::Modules}, 60*be691f3bSpatrick {eModuleUUIDCompletion, CommandCompletions::ModuleUUIDs}, 61061da546Spatrick {eSettingsNameCompletion, CommandCompletions::SettingsNames}, 62061da546Spatrick {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, 63061da546Spatrick {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, 64061da546Spatrick {eVariablePathCompletion, CommandCompletions::VariablePath}, 65dda28197Spatrick {eRegisterCompletion, CommandCompletions::Registers}, 66dda28197Spatrick {eBreakpointCompletion, CommandCompletions::Breakpoints}, 67dda28197Spatrick {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames}, 68*be691f3bSpatrick {eDisassemblyFlavorCompletion, CommandCompletions::DisassemblyFlavors}, 69*be691f3bSpatrick {eTypeLanguageCompletion, CommandCompletions::TypeLanguages}, 70*be691f3bSpatrick {eFrameIndexCompletion, CommandCompletions::FrameIndexes}, 71*be691f3bSpatrick {eStopHookIDCompletion, CommandCompletions::StopHookIDs}, 72*be691f3bSpatrick {eThreadIndexCompletion, CommandCompletions::ThreadIndexes}, 73*be691f3bSpatrick {eWatchPointIDCompletion, CommandCompletions::WatchPointIDs}, 74*be691f3bSpatrick {eBreakpointNameCompletion, CommandCompletions::BreakpointNames}, 75*be691f3bSpatrick {eProcessIDCompletion, CommandCompletions::ProcessIDs}, 76*be691f3bSpatrick {eProcessNameCompletion, CommandCompletions::ProcessNames}, 77*be691f3bSpatrick {eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles}, 78*be691f3bSpatrick {eRemoteDiskDirectoryCompletion, 79*be691f3bSpatrick CommandCompletions::RemoteDiskDirectories}, 80*be691f3bSpatrick {eTypeCategoryNameCompletion, CommandCompletions::TypeCategoryNames}, 81061da546Spatrick {eNoCompletion, nullptr} // This one has to be last in the list. 82061da546Spatrick }; 83061da546Spatrick 84061da546Spatrick for (int i = 0;; i++) { 85dda28197Spatrick if (common_completions[i].type == eNoCompletion) 86061da546Spatrick break; 87dda28197Spatrick else if ((common_completions[i].type & completion_mask) == 88dda28197Spatrick common_completions[i].type && 89dda28197Spatrick common_completions[i].callback != nullptr) { 90061da546Spatrick handled = true; 91dda28197Spatrick common_completions[i].callback(interpreter, request, searcher); 92061da546Spatrick } 93061da546Spatrick } 94061da546Spatrick return handled; 95061da546Spatrick } 96061da546Spatrick 97dda28197Spatrick namespace { 98dda28197Spatrick // The Completer class is a convenient base class for building searchers that 99dda28197Spatrick // go along with the SearchFilter passed to the standard Completer functions. 100dda28197Spatrick class Completer : public Searcher { 101dda28197Spatrick public: 102dda28197Spatrick Completer(CommandInterpreter &interpreter, CompletionRequest &request) 103dda28197Spatrick : m_interpreter(interpreter), m_request(request) {} 104dda28197Spatrick 105dda28197Spatrick ~Completer() override = default; 106dda28197Spatrick 107dda28197Spatrick CallbackReturn SearchCallback(SearchFilter &filter, SymbolContext &context, 108dda28197Spatrick Address *addr) override = 0; 109dda28197Spatrick 110dda28197Spatrick lldb::SearchDepth GetDepth() override = 0; 111dda28197Spatrick 112dda28197Spatrick virtual void DoCompletion(SearchFilter *filter) = 0; 113dda28197Spatrick 114dda28197Spatrick protected: 115dda28197Spatrick CommandInterpreter &m_interpreter; 116dda28197Spatrick CompletionRequest &m_request; 117dda28197Spatrick 118dda28197Spatrick private: 119dda28197Spatrick Completer(const Completer &) = delete; 120dda28197Spatrick const Completer &operator=(const Completer &) = delete; 121dda28197Spatrick }; 122dda28197Spatrick } // namespace 123dda28197Spatrick 124dda28197Spatrick // SourceFileCompleter implements the source file completer 125dda28197Spatrick namespace { 126dda28197Spatrick class SourceFileCompleter : public Completer { 127dda28197Spatrick public: 128dda28197Spatrick SourceFileCompleter(CommandInterpreter &interpreter, 129dda28197Spatrick CompletionRequest &request) 130dda28197Spatrick : Completer(interpreter, request), m_matching_files() { 131dda28197Spatrick FileSpec partial_spec(m_request.GetCursorArgumentPrefix()); 132dda28197Spatrick m_file_name = partial_spec.GetFilename().GetCString(); 133dda28197Spatrick m_dir_name = partial_spec.GetDirectory().GetCString(); 134dda28197Spatrick } 135dda28197Spatrick 136dda28197Spatrick lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthCompUnit; } 137dda28197Spatrick 138dda28197Spatrick Searcher::CallbackReturn SearchCallback(SearchFilter &filter, 139dda28197Spatrick SymbolContext &context, 140dda28197Spatrick Address *addr) override { 141dda28197Spatrick if (context.comp_unit != nullptr) { 142dda28197Spatrick const char *cur_file_name = 143dda28197Spatrick context.comp_unit->GetPrimaryFile().GetFilename().GetCString(); 144dda28197Spatrick const char *cur_dir_name = 145dda28197Spatrick context.comp_unit->GetPrimaryFile().GetDirectory().GetCString(); 146dda28197Spatrick 147dda28197Spatrick bool match = false; 148dda28197Spatrick if (m_file_name && cur_file_name && 149dda28197Spatrick strstr(cur_file_name, m_file_name) == cur_file_name) 150dda28197Spatrick match = true; 151dda28197Spatrick 152dda28197Spatrick if (match && m_dir_name && cur_dir_name && 153dda28197Spatrick strstr(cur_dir_name, m_dir_name) != cur_dir_name) 154dda28197Spatrick match = false; 155dda28197Spatrick 156dda28197Spatrick if (match) { 157dda28197Spatrick m_matching_files.AppendIfUnique(context.comp_unit->GetPrimaryFile()); 158dda28197Spatrick } 159dda28197Spatrick } 160dda28197Spatrick return Searcher::eCallbackReturnContinue; 161dda28197Spatrick } 162dda28197Spatrick 163dda28197Spatrick void DoCompletion(SearchFilter *filter) override { 164dda28197Spatrick filter->Search(*this); 165dda28197Spatrick // Now convert the filelist to completions: 166dda28197Spatrick for (size_t i = 0; i < m_matching_files.GetSize(); i++) { 167dda28197Spatrick m_request.AddCompletion( 168dda28197Spatrick m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString()); 169dda28197Spatrick } 170dda28197Spatrick } 171dda28197Spatrick 172dda28197Spatrick private: 173dda28197Spatrick FileSpecList m_matching_files; 174dda28197Spatrick const char *m_file_name; 175dda28197Spatrick const char *m_dir_name; 176dda28197Spatrick 177dda28197Spatrick SourceFileCompleter(const SourceFileCompleter &) = delete; 178dda28197Spatrick const SourceFileCompleter &operator=(const SourceFileCompleter &) = delete; 179dda28197Spatrick }; 180dda28197Spatrick } // namespace 181dda28197Spatrick 182dda28197Spatrick static bool regex_chars(const char comp) { 183dda28197Spatrick return llvm::StringRef("[](){}+.*|^$\\?").contains(comp); 184dda28197Spatrick } 185dda28197Spatrick 186dda28197Spatrick namespace { 187dda28197Spatrick class SymbolCompleter : public Completer { 188dda28197Spatrick 189dda28197Spatrick public: 190dda28197Spatrick SymbolCompleter(CommandInterpreter &interpreter, CompletionRequest &request) 191dda28197Spatrick : Completer(interpreter, request) { 192dda28197Spatrick std::string regex_str; 193dda28197Spatrick if (!m_request.GetCursorArgumentPrefix().empty()) { 194dda28197Spatrick regex_str.append("^"); 195dda28197Spatrick regex_str.append(std::string(m_request.GetCursorArgumentPrefix())); 196dda28197Spatrick } else { 197dda28197Spatrick // Match anything since the completion string is empty 198dda28197Spatrick regex_str.append("."); 199dda28197Spatrick } 200dda28197Spatrick std::string::iterator pos = 201dda28197Spatrick find_if(regex_str.begin() + 1, regex_str.end(), regex_chars); 202dda28197Spatrick while (pos < regex_str.end()) { 203dda28197Spatrick pos = regex_str.insert(pos, '\\'); 204dda28197Spatrick pos = find_if(pos + 2, regex_str.end(), regex_chars); 205dda28197Spatrick } 206dda28197Spatrick m_regex = RegularExpression(regex_str); 207dda28197Spatrick } 208dda28197Spatrick 209dda28197Spatrick lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } 210dda28197Spatrick 211dda28197Spatrick Searcher::CallbackReturn SearchCallback(SearchFilter &filter, 212dda28197Spatrick SymbolContext &context, 213dda28197Spatrick Address *addr) override { 214dda28197Spatrick if (context.module_sp) { 215dda28197Spatrick SymbolContextList sc_list; 216dda28197Spatrick const bool include_symbols = true; 217dda28197Spatrick const bool include_inlines = true; 218dda28197Spatrick context.module_sp->FindFunctions(m_regex, include_symbols, 219dda28197Spatrick include_inlines, sc_list); 220dda28197Spatrick 221dda28197Spatrick SymbolContext sc; 222dda28197Spatrick // Now add the functions & symbols to the list - only add if unique: 223dda28197Spatrick for (uint32_t i = 0; i < sc_list.GetSize(); i++) { 224dda28197Spatrick if (sc_list.GetContextAtIndex(i, sc)) { 225dda28197Spatrick ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled); 226dda28197Spatrick // Ensure that the function name matches the regex. This is more than 227dda28197Spatrick // a sanity check. It is possible that the demangled function name 228dda28197Spatrick // does not start with the prefix, for example when it's in an 229dda28197Spatrick // anonymous namespace. 230dda28197Spatrick if (!func_name.IsEmpty() && m_regex.Execute(func_name.GetStringRef())) 231dda28197Spatrick m_match_set.insert(func_name); 232dda28197Spatrick } 233dda28197Spatrick } 234dda28197Spatrick } 235dda28197Spatrick return Searcher::eCallbackReturnContinue; 236dda28197Spatrick } 237dda28197Spatrick 238dda28197Spatrick void DoCompletion(SearchFilter *filter) override { 239dda28197Spatrick filter->Search(*this); 240dda28197Spatrick collection::iterator pos = m_match_set.begin(), end = m_match_set.end(); 241dda28197Spatrick for (pos = m_match_set.begin(); pos != end; pos++) 242dda28197Spatrick m_request.AddCompletion((*pos).GetCString()); 243dda28197Spatrick } 244dda28197Spatrick 245dda28197Spatrick private: 246dda28197Spatrick RegularExpression m_regex; 247dda28197Spatrick typedef std::set<ConstString> collection; 248dda28197Spatrick collection m_match_set; 249dda28197Spatrick 250dda28197Spatrick SymbolCompleter(const SymbolCompleter &) = delete; 251dda28197Spatrick const SymbolCompleter &operator=(const SymbolCompleter &) = delete; 252dda28197Spatrick }; 253dda28197Spatrick } // namespace 254dda28197Spatrick 255dda28197Spatrick namespace { 256dda28197Spatrick class ModuleCompleter : public Completer { 257dda28197Spatrick public: 258dda28197Spatrick ModuleCompleter(CommandInterpreter &interpreter, CompletionRequest &request) 259dda28197Spatrick : Completer(interpreter, request) { 260dda28197Spatrick FileSpec partial_spec(m_request.GetCursorArgumentPrefix()); 261dda28197Spatrick m_file_name = partial_spec.GetFilename().GetCString(); 262dda28197Spatrick m_dir_name = partial_spec.GetDirectory().GetCString(); 263dda28197Spatrick } 264dda28197Spatrick 265dda28197Spatrick lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } 266dda28197Spatrick 267dda28197Spatrick Searcher::CallbackReturn SearchCallback(SearchFilter &filter, 268dda28197Spatrick SymbolContext &context, 269dda28197Spatrick Address *addr) override { 270dda28197Spatrick if (context.module_sp) { 271dda28197Spatrick const char *cur_file_name = 272dda28197Spatrick context.module_sp->GetFileSpec().GetFilename().GetCString(); 273dda28197Spatrick const char *cur_dir_name = 274dda28197Spatrick context.module_sp->GetFileSpec().GetDirectory().GetCString(); 275dda28197Spatrick 276dda28197Spatrick bool match = false; 277dda28197Spatrick if (m_file_name && cur_file_name && 278dda28197Spatrick strstr(cur_file_name, m_file_name) == cur_file_name) 279dda28197Spatrick match = true; 280dda28197Spatrick 281dda28197Spatrick if (match && m_dir_name && cur_dir_name && 282dda28197Spatrick strstr(cur_dir_name, m_dir_name) != cur_dir_name) 283dda28197Spatrick match = false; 284dda28197Spatrick 285dda28197Spatrick if (match) { 286dda28197Spatrick m_request.AddCompletion(cur_file_name); 287dda28197Spatrick } 288dda28197Spatrick } 289dda28197Spatrick return Searcher::eCallbackReturnContinue; 290dda28197Spatrick } 291dda28197Spatrick 292dda28197Spatrick void DoCompletion(SearchFilter *filter) override { filter->Search(*this); } 293dda28197Spatrick 294dda28197Spatrick private: 295dda28197Spatrick const char *m_file_name; 296dda28197Spatrick const char *m_dir_name; 297dda28197Spatrick 298dda28197Spatrick ModuleCompleter(const ModuleCompleter &) = delete; 299dda28197Spatrick const ModuleCompleter &operator=(const ModuleCompleter &) = delete; 300dda28197Spatrick }; 301dda28197Spatrick } // namespace 302dda28197Spatrick 303061da546Spatrick void CommandCompletions::SourceFiles(CommandInterpreter &interpreter, 304061da546Spatrick CompletionRequest &request, 305061da546Spatrick SearchFilter *searcher) { 306dda28197Spatrick SourceFileCompleter completer(interpreter, request); 307061da546Spatrick 308061da546Spatrick if (searcher == nullptr) { 309061da546Spatrick lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 310061da546Spatrick SearchFilterForUnconstrainedSearches null_searcher(target_sp); 311061da546Spatrick completer.DoCompletion(&null_searcher); 312061da546Spatrick } else { 313061da546Spatrick completer.DoCompletion(searcher); 314061da546Spatrick } 315061da546Spatrick } 316061da546Spatrick 317061da546Spatrick static void DiskFilesOrDirectories(const llvm::Twine &partial_name, 318061da546Spatrick bool only_directories, 319061da546Spatrick CompletionRequest &request, 320061da546Spatrick TildeExpressionResolver &Resolver) { 321061da546Spatrick llvm::SmallString<256> CompletionBuffer; 322061da546Spatrick llvm::SmallString<256> Storage; 323061da546Spatrick partial_name.toVector(CompletionBuffer); 324061da546Spatrick 325061da546Spatrick if (CompletionBuffer.size() >= PATH_MAX) 326061da546Spatrick return; 327061da546Spatrick 328061da546Spatrick namespace path = llvm::sys::path; 329061da546Spatrick 330061da546Spatrick llvm::StringRef SearchDir; 331061da546Spatrick llvm::StringRef PartialItem; 332061da546Spatrick 333061da546Spatrick if (CompletionBuffer.startswith("~")) { 334*be691f3bSpatrick llvm::StringRef Buffer = CompletionBuffer; 335061da546Spatrick size_t FirstSep = 336061da546Spatrick Buffer.find_if([](char c) { return path::is_separator(c); }); 337061da546Spatrick 338061da546Spatrick llvm::StringRef Username = Buffer.take_front(FirstSep); 339061da546Spatrick llvm::StringRef Remainder; 340061da546Spatrick if (FirstSep != llvm::StringRef::npos) 341061da546Spatrick Remainder = Buffer.drop_front(FirstSep + 1); 342061da546Spatrick 343061da546Spatrick llvm::SmallString<256> Resolved; 344061da546Spatrick if (!Resolver.ResolveExact(Username, Resolved)) { 345061da546Spatrick // We couldn't resolve it as a full username. If there were no slashes 346061da546Spatrick // then this might be a partial username. We try to resolve it as such 347061da546Spatrick // but after that, we're done regardless of any matches. 348061da546Spatrick if (FirstSep == llvm::StringRef::npos) { 349061da546Spatrick llvm::StringSet<> MatchSet; 350061da546Spatrick Resolver.ResolvePartial(Username, MatchSet); 351061da546Spatrick for (const auto &S : MatchSet) { 352061da546Spatrick Resolved = S.getKey(); 353061da546Spatrick path::append(Resolved, path::get_separator()); 354061da546Spatrick request.AddCompletion(Resolved, "", CompletionMode::Partial); 355061da546Spatrick } 356061da546Spatrick } 357061da546Spatrick return; 358061da546Spatrick } 359061da546Spatrick 360061da546Spatrick // If there was no trailing slash, then we're done as soon as we resolve 361061da546Spatrick // the expression to the correct directory. Otherwise we need to continue 362061da546Spatrick // looking for matches within that directory. 363061da546Spatrick if (FirstSep == llvm::StringRef::npos) { 364061da546Spatrick // Make sure it ends with a separator. 365061da546Spatrick path::append(CompletionBuffer, path::get_separator()); 366061da546Spatrick request.AddCompletion(CompletionBuffer, "", CompletionMode::Partial); 367061da546Spatrick return; 368061da546Spatrick } 369061da546Spatrick 370061da546Spatrick // We want to keep the form the user typed, so we special case this to 371061da546Spatrick // search in the fully resolved directory, but CompletionBuffer keeps the 372061da546Spatrick // unmodified form that the user typed. 373061da546Spatrick Storage = Resolved; 374061da546Spatrick llvm::StringRef RemainderDir = path::parent_path(Remainder); 375061da546Spatrick if (!RemainderDir.empty()) { 376061da546Spatrick // Append the remaining path to the resolved directory. 377061da546Spatrick Storage.append(path::get_separator()); 378061da546Spatrick Storage.append(RemainderDir); 379061da546Spatrick } 380061da546Spatrick SearchDir = Storage; 381061da546Spatrick } else { 382061da546Spatrick SearchDir = path::parent_path(CompletionBuffer); 383061da546Spatrick } 384061da546Spatrick 385061da546Spatrick size_t FullPrefixLen = CompletionBuffer.size(); 386061da546Spatrick 387061da546Spatrick PartialItem = path::filename(CompletionBuffer); 388061da546Spatrick 389061da546Spatrick // path::filename() will return "." when the passed path ends with a 390061da546Spatrick // directory separator. We have to filter those out, but only when the 391061da546Spatrick // "." doesn't come from the completion request itself. 392061da546Spatrick if (PartialItem == "." && path::is_separator(CompletionBuffer.back())) 393061da546Spatrick PartialItem = llvm::StringRef(); 394061da546Spatrick 395061da546Spatrick if (SearchDir.empty()) { 396061da546Spatrick llvm::sys::fs::current_path(Storage); 397061da546Spatrick SearchDir = Storage; 398061da546Spatrick } 399061da546Spatrick assert(!PartialItem.contains(path::get_separator())); 400061da546Spatrick 401061da546Spatrick // SearchDir now contains the directory to search in, and Prefix contains the 402061da546Spatrick // text we want to match against items in that directory. 403061da546Spatrick 404061da546Spatrick FileSystem &fs = FileSystem::Instance(); 405061da546Spatrick std::error_code EC; 406061da546Spatrick llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC); 407061da546Spatrick llvm::vfs::directory_iterator End; 408061da546Spatrick for (; Iter != End && !EC; Iter.increment(EC)) { 409061da546Spatrick auto &Entry = *Iter; 410061da546Spatrick llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path()); 411061da546Spatrick 412061da546Spatrick if (!Status) 413061da546Spatrick continue; 414061da546Spatrick 415061da546Spatrick auto Name = path::filename(Entry.path()); 416061da546Spatrick 417061da546Spatrick // Omit ".", ".." 418061da546Spatrick if (Name == "." || Name == ".." || !Name.startswith(PartialItem)) 419061da546Spatrick continue; 420061da546Spatrick 421061da546Spatrick bool is_dir = Status->isDirectory(); 422061da546Spatrick 423061da546Spatrick // If it's a symlink, then we treat it as a directory as long as the target 424061da546Spatrick // is a directory. 425061da546Spatrick if (Status->isSymlink()) { 426061da546Spatrick FileSpec symlink_filespec(Entry.path()); 427061da546Spatrick FileSpec resolved_filespec; 428061da546Spatrick auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec); 429061da546Spatrick if (error.Success()) 430061da546Spatrick is_dir = fs.IsDirectory(symlink_filespec); 431061da546Spatrick } 432061da546Spatrick 433061da546Spatrick if (only_directories && !is_dir) 434061da546Spatrick continue; 435061da546Spatrick 436061da546Spatrick // Shrink it back down so that it just has the original prefix the user 437061da546Spatrick // typed and remove the part of the name which is common to the located 438061da546Spatrick // item and what the user typed. 439061da546Spatrick CompletionBuffer.resize(FullPrefixLen); 440061da546Spatrick Name = Name.drop_front(PartialItem.size()); 441061da546Spatrick CompletionBuffer.append(Name); 442061da546Spatrick 443061da546Spatrick if (is_dir) { 444061da546Spatrick path::append(CompletionBuffer, path::get_separator()); 445061da546Spatrick } 446061da546Spatrick 447061da546Spatrick CompletionMode mode = 448061da546Spatrick is_dir ? CompletionMode::Partial : CompletionMode::Normal; 449061da546Spatrick request.AddCompletion(CompletionBuffer, "", mode); 450061da546Spatrick } 451061da546Spatrick } 452061da546Spatrick 453061da546Spatrick static void DiskFilesOrDirectories(const llvm::Twine &partial_name, 454061da546Spatrick bool only_directories, StringList &matches, 455061da546Spatrick TildeExpressionResolver &Resolver) { 456061da546Spatrick CompletionResult result; 457061da546Spatrick std::string partial_name_str = partial_name.str(); 458061da546Spatrick CompletionRequest request(partial_name_str, partial_name_str.size(), result); 459061da546Spatrick DiskFilesOrDirectories(partial_name, only_directories, request, Resolver); 460061da546Spatrick result.GetMatches(matches); 461061da546Spatrick } 462061da546Spatrick 463061da546Spatrick static void DiskFilesOrDirectories(CompletionRequest &request, 464061da546Spatrick bool only_directories) { 465061da546Spatrick StandardTildeExpressionResolver resolver; 466061da546Spatrick DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories, 467061da546Spatrick request, resolver); 468061da546Spatrick } 469061da546Spatrick 470061da546Spatrick void CommandCompletions::DiskFiles(CommandInterpreter &interpreter, 471061da546Spatrick CompletionRequest &request, 472061da546Spatrick SearchFilter *searcher) { 473061da546Spatrick DiskFilesOrDirectories(request, /*only_dirs*/ false); 474061da546Spatrick } 475061da546Spatrick 476061da546Spatrick void CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name, 477061da546Spatrick StringList &matches, 478061da546Spatrick TildeExpressionResolver &Resolver) { 479061da546Spatrick DiskFilesOrDirectories(partial_file_name, false, matches, Resolver); 480061da546Spatrick } 481061da546Spatrick 482061da546Spatrick void CommandCompletions::DiskDirectories(CommandInterpreter &interpreter, 483061da546Spatrick CompletionRequest &request, 484061da546Spatrick SearchFilter *searcher) { 485061da546Spatrick DiskFilesOrDirectories(request, /*only_dirs*/ true); 486061da546Spatrick } 487061da546Spatrick 488061da546Spatrick void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name, 489061da546Spatrick StringList &matches, 490061da546Spatrick TildeExpressionResolver &Resolver) { 491061da546Spatrick DiskFilesOrDirectories(partial_file_name, true, matches, Resolver); 492061da546Spatrick } 493061da546Spatrick 494*be691f3bSpatrick void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter, 495*be691f3bSpatrick CompletionRequest &request, 496*be691f3bSpatrick SearchFilter *searcher) { 497*be691f3bSpatrick lldb::PlatformSP platform_sp = 498*be691f3bSpatrick interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); 499*be691f3bSpatrick if (platform_sp) 500*be691f3bSpatrick platform_sp->AutoCompleteDiskFileOrDirectory(request, false); 501*be691f3bSpatrick } 502*be691f3bSpatrick 503*be691f3bSpatrick void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter, 504*be691f3bSpatrick CompletionRequest &request, 505*be691f3bSpatrick SearchFilter *searcher) { 506*be691f3bSpatrick lldb::PlatformSP platform_sp = 507*be691f3bSpatrick interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); 508*be691f3bSpatrick if (platform_sp) 509*be691f3bSpatrick platform_sp->AutoCompleteDiskFileOrDirectory(request, true); 510*be691f3bSpatrick } 511*be691f3bSpatrick 512061da546Spatrick void CommandCompletions::Modules(CommandInterpreter &interpreter, 513061da546Spatrick CompletionRequest &request, 514061da546Spatrick SearchFilter *searcher) { 515061da546Spatrick ModuleCompleter completer(interpreter, request); 516061da546Spatrick 517061da546Spatrick if (searcher == nullptr) { 518061da546Spatrick lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 519061da546Spatrick SearchFilterForUnconstrainedSearches null_searcher(target_sp); 520061da546Spatrick completer.DoCompletion(&null_searcher); 521061da546Spatrick } else { 522061da546Spatrick completer.DoCompletion(searcher); 523061da546Spatrick } 524061da546Spatrick } 525061da546Spatrick 526*be691f3bSpatrick void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter, 527*be691f3bSpatrick CompletionRequest &request, 528*be691f3bSpatrick SearchFilter *searcher) { 529*be691f3bSpatrick const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); 530*be691f3bSpatrick if (!exe_ctx.HasTargetScope()) 531*be691f3bSpatrick return; 532*be691f3bSpatrick 533*be691f3bSpatrick exe_ctx.GetTargetPtr()->GetImages().ForEach( 534*be691f3bSpatrick [&request](const lldb::ModuleSP &module) { 535*be691f3bSpatrick StreamString strm; 536*be691f3bSpatrick module->GetDescription(strm.AsRawOstream(), 537*be691f3bSpatrick lldb::eDescriptionLevelInitial); 538*be691f3bSpatrick request.TryCompleteCurrentArg(module->GetUUID().GetAsString(), 539*be691f3bSpatrick strm.GetString()); 540*be691f3bSpatrick return true; 541*be691f3bSpatrick }); 542*be691f3bSpatrick } 543*be691f3bSpatrick 544061da546Spatrick void CommandCompletions::Symbols(CommandInterpreter &interpreter, 545061da546Spatrick CompletionRequest &request, 546061da546Spatrick SearchFilter *searcher) { 547061da546Spatrick SymbolCompleter completer(interpreter, request); 548061da546Spatrick 549061da546Spatrick if (searcher == nullptr) { 550061da546Spatrick lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 551061da546Spatrick SearchFilterForUnconstrainedSearches null_searcher(target_sp); 552061da546Spatrick completer.DoCompletion(&null_searcher); 553061da546Spatrick } else { 554061da546Spatrick completer.DoCompletion(searcher); 555061da546Spatrick } 556061da546Spatrick } 557061da546Spatrick 558061da546Spatrick void CommandCompletions::SettingsNames(CommandInterpreter &interpreter, 559061da546Spatrick CompletionRequest &request, 560061da546Spatrick SearchFilter *searcher) { 561061da546Spatrick // Cache the full setting name list 562061da546Spatrick static StringList g_property_names; 563061da546Spatrick if (g_property_names.GetSize() == 0) { 564061da546Spatrick // Generate the full setting name list on demand 565061da546Spatrick lldb::OptionValuePropertiesSP properties_sp( 566061da546Spatrick interpreter.GetDebugger().GetValueProperties()); 567061da546Spatrick if (properties_sp) { 568061da546Spatrick StreamString strm; 569061da546Spatrick properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName); 570dda28197Spatrick const std::string &str = std::string(strm.GetString()); 571061da546Spatrick g_property_names.SplitIntoLines(str.c_str(), str.size()); 572061da546Spatrick } 573061da546Spatrick } 574061da546Spatrick 575061da546Spatrick for (const std::string &s : g_property_names) 576061da546Spatrick request.TryCompleteCurrentArg(s); 577061da546Spatrick } 578061da546Spatrick 579061da546Spatrick void CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter, 580061da546Spatrick CompletionRequest &request, 581061da546Spatrick SearchFilter *searcher) { 582061da546Spatrick PluginManager::AutoCompletePlatformName(request.GetCursorArgumentPrefix(), 583061da546Spatrick request); 584061da546Spatrick } 585061da546Spatrick 586061da546Spatrick void CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter, 587061da546Spatrick CompletionRequest &request, 588061da546Spatrick SearchFilter *searcher) { 589061da546Spatrick ArchSpec::AutoComplete(request); 590061da546Spatrick } 591061da546Spatrick 592061da546Spatrick void CommandCompletions::VariablePath(CommandInterpreter &interpreter, 593061da546Spatrick CompletionRequest &request, 594061da546Spatrick SearchFilter *searcher) { 595061da546Spatrick Variable::AutoComplete(interpreter.GetExecutionContext(), request); 596061da546Spatrick } 597061da546Spatrick 598dda28197Spatrick void CommandCompletions::Registers(CommandInterpreter &interpreter, 599dda28197Spatrick CompletionRequest &request, 600dda28197Spatrick SearchFilter *searcher) { 601dda28197Spatrick std::string reg_prefix = ""; 602dda28197Spatrick if (request.GetCursorArgumentPrefix().startswith("$")) 603dda28197Spatrick reg_prefix = "$"; 604061da546Spatrick 605dda28197Spatrick RegisterContext *reg_ctx = 606dda28197Spatrick interpreter.GetExecutionContext().GetRegisterContext(); 607dda28197Spatrick const size_t reg_num = reg_ctx->GetRegisterCount(); 608dda28197Spatrick for (size_t reg_idx = 0; reg_idx < reg_num; ++reg_idx) { 609dda28197Spatrick const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx); 610dda28197Spatrick request.TryCompleteCurrentArg(reg_prefix + reg_info->name, 611dda28197Spatrick reg_info->alt_name); 612061da546Spatrick } 613061da546Spatrick } 614061da546Spatrick 615dda28197Spatrick void CommandCompletions::Breakpoints(CommandInterpreter &interpreter, 616dda28197Spatrick CompletionRequest &request, 617dda28197Spatrick SearchFilter *searcher) { 618dda28197Spatrick lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget(); 619dda28197Spatrick if (!target) 620dda28197Spatrick return; 621061da546Spatrick 622dda28197Spatrick const BreakpointList &breakpoints = target->GetBreakpointList(); 623dda28197Spatrick 624dda28197Spatrick std::unique_lock<std::recursive_mutex> lock; 625dda28197Spatrick target->GetBreakpointList().GetListMutex(lock); 626dda28197Spatrick 627dda28197Spatrick size_t num_breakpoints = breakpoints.GetSize(); 628dda28197Spatrick if (num_breakpoints == 0) 629dda28197Spatrick return; 630dda28197Spatrick 631dda28197Spatrick for (size_t i = 0; i < num_breakpoints; ++i) { 632dda28197Spatrick lldb::BreakpointSP bp = breakpoints.GetBreakpointAtIndex(i); 633dda28197Spatrick 634dda28197Spatrick StreamString s; 635dda28197Spatrick bp->GetDescription(&s, lldb::eDescriptionLevelBrief); 636dda28197Spatrick llvm::StringRef bp_info = s.GetString(); 637dda28197Spatrick 638dda28197Spatrick const size_t colon_pos = bp_info.find_first_of(':'); 639dda28197Spatrick if (colon_pos != llvm::StringRef::npos) 640dda28197Spatrick bp_info = bp_info.drop_front(colon_pos + 2); 641dda28197Spatrick 642dda28197Spatrick request.TryCompleteCurrentArg(std::to_string(bp->GetID()), bp_info); 643dda28197Spatrick } 644061da546Spatrick } 645061da546Spatrick 646*be691f3bSpatrick void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter, 647*be691f3bSpatrick CompletionRequest &request, 648*be691f3bSpatrick SearchFilter *searcher) { 649*be691f3bSpatrick lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget(); 650*be691f3bSpatrick if (!target) 651*be691f3bSpatrick return; 652*be691f3bSpatrick 653*be691f3bSpatrick std::vector<std::string> name_list; 654*be691f3bSpatrick target->GetBreakpointNames(name_list); 655*be691f3bSpatrick 656*be691f3bSpatrick for (const std::string &name : name_list) 657*be691f3bSpatrick request.TryCompleteCurrentArg(name); 658*be691f3bSpatrick } 659*be691f3bSpatrick 660dda28197Spatrick void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter, 661dda28197Spatrick CompletionRequest &request, 662dda28197Spatrick SearchFilter *searcher) { 663dda28197Spatrick PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(), 664dda28197Spatrick request); 665061da546Spatrick } 666*be691f3bSpatrick void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter, 667*be691f3bSpatrick CompletionRequest &request, 668*be691f3bSpatrick SearchFilter *searcher) { 669*be691f3bSpatrick // Currently the only valid options for disassemble -F are default, and for 670*be691f3bSpatrick // Intel architectures, att and intel. 671*be691f3bSpatrick static const char *flavors[] = {"default", "att", "intel"}; 672*be691f3bSpatrick for (const char *flavor : flavors) { 673*be691f3bSpatrick request.TryCompleteCurrentArg(flavor); 674*be691f3bSpatrick } 675*be691f3bSpatrick } 676*be691f3bSpatrick 677*be691f3bSpatrick void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter, 678*be691f3bSpatrick CompletionRequest &request, 679*be691f3bSpatrick SearchFilter *searcher) { 680*be691f3bSpatrick lldb::PlatformSP platform_sp(interpreter.GetPlatform(true)); 681*be691f3bSpatrick if (!platform_sp) 682*be691f3bSpatrick return; 683*be691f3bSpatrick ProcessInstanceInfoList process_infos; 684*be691f3bSpatrick ProcessInstanceInfoMatch match_info; 685*be691f3bSpatrick platform_sp->FindProcesses(match_info, process_infos); 686*be691f3bSpatrick for (const ProcessInstanceInfo &info : process_infos) 687*be691f3bSpatrick request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()), 688*be691f3bSpatrick info.GetNameAsStringRef()); 689*be691f3bSpatrick } 690*be691f3bSpatrick 691*be691f3bSpatrick void CommandCompletions::ProcessNames(CommandInterpreter &interpreter, 692*be691f3bSpatrick CompletionRequest &request, 693*be691f3bSpatrick SearchFilter *searcher) { 694*be691f3bSpatrick lldb::PlatformSP platform_sp(interpreter.GetPlatform(true)); 695*be691f3bSpatrick if (!platform_sp) 696*be691f3bSpatrick return; 697*be691f3bSpatrick ProcessInstanceInfoList process_infos; 698*be691f3bSpatrick ProcessInstanceInfoMatch match_info; 699*be691f3bSpatrick platform_sp->FindProcesses(match_info, process_infos); 700*be691f3bSpatrick for (const ProcessInstanceInfo &info : process_infos) 701*be691f3bSpatrick request.TryCompleteCurrentArg(info.GetNameAsStringRef()); 702*be691f3bSpatrick } 703*be691f3bSpatrick 704*be691f3bSpatrick void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter, 705*be691f3bSpatrick CompletionRequest &request, 706*be691f3bSpatrick SearchFilter *searcher) { 707*be691f3bSpatrick for (int bit : 708*be691f3bSpatrick Language::GetLanguagesSupportingTypeSystems().bitvector.set_bits()) { 709*be691f3bSpatrick request.TryCompleteCurrentArg( 710*be691f3bSpatrick Language::GetNameForLanguageType(static_cast<lldb::LanguageType>(bit))); 711*be691f3bSpatrick } 712*be691f3bSpatrick } 713*be691f3bSpatrick 714*be691f3bSpatrick void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter, 715*be691f3bSpatrick CompletionRequest &request, 716*be691f3bSpatrick SearchFilter *searcher) { 717*be691f3bSpatrick const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); 718*be691f3bSpatrick if (!exe_ctx.HasProcessScope()) 719*be691f3bSpatrick return; 720*be691f3bSpatrick 721*be691f3bSpatrick lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP(); 722*be691f3bSpatrick const uint32_t frame_num = thread_sp->GetStackFrameCount(); 723*be691f3bSpatrick for (uint32_t i = 0; i < frame_num; ++i) { 724*be691f3bSpatrick lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); 725*be691f3bSpatrick StreamString strm; 726*be691f3bSpatrick frame_sp->Dump(&strm, false, true); 727*be691f3bSpatrick request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); 728*be691f3bSpatrick } 729*be691f3bSpatrick } 730*be691f3bSpatrick 731*be691f3bSpatrick void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter, 732*be691f3bSpatrick CompletionRequest &request, 733*be691f3bSpatrick SearchFilter *searcher) { 734*be691f3bSpatrick const lldb::TargetSP target_sp = 735*be691f3bSpatrick interpreter.GetExecutionContext().GetTargetSP(); 736*be691f3bSpatrick if (!target_sp) 737*be691f3bSpatrick return; 738*be691f3bSpatrick 739*be691f3bSpatrick const size_t num = target_sp->GetNumStopHooks(); 740*be691f3bSpatrick for (size_t idx = 0; idx < num; ++idx) { 741*be691f3bSpatrick StreamString strm; 742*be691f3bSpatrick // The value 11 is an offset to make the completion description looks 743*be691f3bSpatrick // neater. 744*be691f3bSpatrick strm.SetIndentLevel(11); 745*be691f3bSpatrick const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx); 746*be691f3bSpatrick stophook_sp->GetDescription(&strm, lldb::eDescriptionLevelInitial); 747*be691f3bSpatrick request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()), 748*be691f3bSpatrick strm.GetString()); 749*be691f3bSpatrick } 750*be691f3bSpatrick } 751*be691f3bSpatrick 752*be691f3bSpatrick void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter, 753*be691f3bSpatrick CompletionRequest &request, 754*be691f3bSpatrick SearchFilter *searcher) { 755*be691f3bSpatrick const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); 756*be691f3bSpatrick if (!exe_ctx.HasProcessScope()) 757*be691f3bSpatrick return; 758*be691f3bSpatrick 759*be691f3bSpatrick ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList(); 760*be691f3bSpatrick lldb::ThreadSP thread_sp; 761*be691f3bSpatrick for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) { 762*be691f3bSpatrick StreamString strm; 763*be691f3bSpatrick thread_sp->GetStatus(strm, 0, 1, 1, true); 764*be691f3bSpatrick request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()), 765*be691f3bSpatrick strm.GetString()); 766*be691f3bSpatrick } 767*be691f3bSpatrick } 768*be691f3bSpatrick 769*be691f3bSpatrick void CommandCompletions::WatchPointIDs(CommandInterpreter &interpreter, 770*be691f3bSpatrick CompletionRequest &request, 771*be691f3bSpatrick SearchFilter *searcher) { 772*be691f3bSpatrick const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); 773*be691f3bSpatrick if (!exe_ctx.HasTargetScope()) 774*be691f3bSpatrick return; 775*be691f3bSpatrick 776*be691f3bSpatrick const WatchpointList &wp_list = exe_ctx.GetTargetPtr()->GetWatchpointList(); 777*be691f3bSpatrick for (lldb::WatchpointSP wp_sp : wp_list.Watchpoints()) { 778*be691f3bSpatrick StreamString strm; 779*be691f3bSpatrick wp_sp->Dump(&strm); 780*be691f3bSpatrick request.TryCompleteCurrentArg(std::to_string(wp_sp->GetID()), 781*be691f3bSpatrick strm.GetString()); 782*be691f3bSpatrick } 783*be691f3bSpatrick } 784*be691f3bSpatrick 785*be691f3bSpatrick void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter, 786*be691f3bSpatrick CompletionRequest &request, 787*be691f3bSpatrick SearchFilter *searcher) { 788*be691f3bSpatrick DataVisualization::Categories::ForEach( 789*be691f3bSpatrick [&request](const lldb::TypeCategoryImplSP &category_sp) { 790*be691f3bSpatrick request.TryCompleteCurrentArg(category_sp->GetName(), 791*be691f3bSpatrick category_sp->GetDescription()); 792*be691f3bSpatrick return true; 793*be691f3bSpatrick }); 794*be691f3bSpatrick } 795