blob: 1cff39c37345b219f0bf16a4148a8cc3e803cc71 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8
Jim Ingham558ce122010-06-30 05:02:46 +00009#include <sys/stat.h>
Greg Claytonfd184262011-02-05 02:27:52 +000010#if defined(__APPLE__) || defined(__linux__)
Jim Ingham7cc478b2010-07-02 00:45:55 +000011#include <pwd.h>
Greg Claytonfd184262011-02-05 02:27:52 +000012#endif
Jim Ingham558ce122010-06-30 05:02:46 +000013
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000014#include "llvm/ADT/SmallString.h"
Zachary Turner2cc5a182017-03-13 00:41:01 +000015#include "llvm/ADT/StringSet.h"
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +000016
Greg Clayton9b62fd22011-02-01 05:15:22 +000017#include "lldb/Core/FileSpecList.h"
Greg Clayton1f746072012-08-29 21:13:06 +000018#include "lldb/Core/Module.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000019#include "lldb/Core/PluginManager.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000020#include "lldb/Host/FileSystem.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000021#include "lldb/Interpreter/CommandCompletions.h"
22#include "lldb/Interpreter/CommandInterpreter.h"
Zachary Turner633a29c2015-03-04 01:58:01 +000023#include "lldb/Interpreter/OptionValueProperties.h"
Greg Clayton1f746072012-08-29 21:13:06 +000024#include "lldb/Symbol/CompileUnit.h"
Greg Claytonf21fead2013-05-14 23:43:18 +000025#include "lldb/Symbol/Variable.h"
Greg Clayton9b62fd22011-02-01 05:15:22 +000026#include "lldb/Target/Target.h"
Pavel Labath145d95c2018-04-17 18:53:35 +000027#include "lldb/Utility/Args.h"
Zachary Turner5713a052017-03-22 18:40:07 +000028#include "lldb/Utility/FileSpec.h"
Zachary Turner2f3df612017-04-06 21:28:29 +000029#include "lldb/Utility/StreamString.h"
Zachary Turner2cc5a182017-03-13 00:41:01 +000030#include "lldb/Utility/TildeExpressionResolver.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000031
Zachary Turner190fadc2016-03-22 17:58:09 +000032#include "llvm/ADT/SmallString.h"
Zachary Turner7d86ee52017-03-08 17:56:08 +000033#include "llvm/Support/FileSystem.h"
Zachary Turner2cc5a182017-03-13 00:41:01 +000034#include "llvm/Support/Path.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000035
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036using namespace lldb_private;
37
38CommandCompletions::CommonCompletionElement
Kate Stoneb9c1b512016-09-06 20:57:50 +000039 CommandCompletions::g_common_completions[] = {
40 {eCustomCompletion, nullptr},
41 {eSourceFileCompletion, CommandCompletions::SourceFiles},
42 {eDiskFileCompletion, CommandCompletions::DiskFiles},
43 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
44 {eSymbolCompletion, CommandCompletions::Symbols},
45 {eModuleCompletion, CommandCompletions::Modules},
46 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
47 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
48 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
49 {eVariablePathCompletion, CommandCompletions::VariablePath},
50 {eNoCompletion, nullptr} // This one has to be last in the list.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000051};
52
Kate Stoneb9c1b512016-09-06 20:57:50 +000053bool CommandCompletions::InvokeCommonCompletionCallbacks(
54 CommandInterpreter &interpreter, uint32_t completion_mask,
Raphael Isemanna2e76c02018-07-13 18:28:14 +000055 CompletionRequest &request, SearchFilter *searcher) {
Kate Stoneb9c1b512016-09-06 20:57:50 +000056 bool handled = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 if (completion_mask & eCustomCompletion)
59 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000060
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 for (int i = 0;; i++) {
62 if (g_common_completions[i].type == eNoCompletion)
63 break;
64 else if ((g_common_completions[i].type & completion_mask) ==
65 g_common_completions[i].type &&
66 g_common_completions[i].callback != nullptr) {
67 handled = true;
Raphael Isemanna2e76c02018-07-13 18:28:14 +000068 g_common_completions[i].callback(interpreter, request, searcher);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 }
71 return handled;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000072}
73
Kate Stoneb9c1b512016-09-06 20:57:50 +000074int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +000075 CompletionRequest &request,
76 SearchFilter *searcher) {
77 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +000078 // Find some way to switch "include support files..."
Raphael Isemanna2e76c02018-07-13 18:28:14 +000079 SourceFileCompleter completer(interpreter, false, request);
Kate Stoneb9c1b512016-09-06 20:57:50 +000080
81 if (searcher == nullptr) {
82 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
83 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
84 completer.DoCompletion(&null_searcher);
85 } else {
86 completer.DoCompletion(searcher);
87 }
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +000088 return request.GetNumberOfMatches();
Jim Ingham558ce122010-06-30 05:02:46 +000089}
90
Zachary Turner2cc5a182017-03-13 00:41:01 +000091static int DiskFilesOrDirectories(const llvm::Twine &partial_name,
Raphael Isemanna2e76c02018-07-13 18:28:14 +000092 bool only_directories, StringList &matches,
Zachary Turner2cc5a182017-03-13 00:41:01 +000093 TildeExpressionResolver &Resolver) {
94 matches.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +000095
Zachary Turner2cc5a182017-03-13 00:41:01 +000096 llvm::SmallString<256> CompletionBuffer;
97 llvm::SmallString<256> Storage;
98 partial_name.toVector(CompletionBuffer);
Kate Stoneb9c1b512016-09-06 20:57:50 +000099
Zachary Turner2cc5a182017-03-13 00:41:01 +0000100 if (CompletionBuffer.size() >= PATH_MAX)
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000101 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000102
Zachary Turner2cc5a182017-03-13 00:41:01 +0000103 namespace path = llvm::sys::path;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000104
Zachary Turner2cc5a182017-03-13 00:41:01 +0000105 llvm::StringRef SearchDir;
106 llvm::StringRef PartialItem;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107
Zachary Turner2cc5a182017-03-13 00:41:01 +0000108 if (CompletionBuffer.startswith("~")) {
109 llvm::StringRef Buffer(CompletionBuffer);
Zachary Turner5c5091f2017-03-16 22:28:04 +0000110 size_t FirstSep =
111 Buffer.find_if([](char c) { return path::is_separator(c); });
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112
Zachary Turner2cc5a182017-03-13 00:41:01 +0000113 llvm::StringRef Username = Buffer.take_front(FirstSep);
114 llvm::StringRef Remainder;
115 if (FirstSep != llvm::StringRef::npos)
116 Remainder = Buffer.drop_front(FirstSep + 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117
Stella Stamenovab3f44ad2018-12-10 17:23:28 +0000118 llvm::SmallString<256> Resolved;
Zachary Turner2cc5a182017-03-13 00:41:01 +0000119 if (!Resolver.ResolveExact(Username, Resolved)) {
120 // We couldn't resolve it as a full username. If there were no slashes
121 // then this might be a partial username. We try to resolve it as such
122 // but after that, we're done regardless of any matches.
123 if (FirstSep == llvm::StringRef::npos) {
124 llvm::StringSet<> MatchSet;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000125 Resolver.ResolvePartial(Username, MatchSet);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000126 for (const auto &S : MatchSet) {
127 Resolved = S.getKey();
128 path::append(Resolved, path::get_separator());
129 matches.AppendString(Resolved);
130 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131 }
Zachary Turner0734e6a2017-03-12 20:01:37 +0000132 return matches.GetSize();
Zachary Turner2cc5a182017-03-13 00:41:01 +0000133 }
134
Adrian Prantl05097242018-04-30 16:49:04 +0000135 // If there was no trailing slash, then we're done as soon as we resolve
136 // the expression to the correct directory. Otherwise we need to continue
Zachary Turner2cc5a182017-03-13 00:41:01 +0000137 // looking for matches within that directory.
138 if (FirstSep == llvm::StringRef::npos) {
139 // Make sure it ends with a separator.
140 path::append(CompletionBuffer, path::get_separator());
Zachary Turner2cc5a182017-03-13 00:41:01 +0000141 matches.AppendString(CompletionBuffer);
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000142 return matches.GetSize();
Zachary Turner2cc5a182017-03-13 00:41:01 +0000143 }
144
145 // We want to keep the form the user typed, so we special case this to
146 // search in the fully resolved directory, but CompletionBuffer keeps the
147 // unmodified form that the user typed.
148 Storage = Resolved;
Pavel Labath88ec2e42018-06-29 10:27:18 +0000149 llvm::StringRef RemainderDir = path::parent_path(Remainder);
Raphael Isemann4621e0b2018-06-18 20:11:38 +0000150 if (!RemainderDir.empty()) {
151 // Append the remaining path to the resolved directory.
152 Storage.append(path::get_separator());
153 Storage.append(RemainderDir);
154 }
Raphael Isemann17843882018-01-22 09:17:16 +0000155 SearchDir = Storage;
Zachary Turner2cc5a182017-03-13 00:41:01 +0000156 } else {
157 SearchDir = path::parent_path(CompletionBuffer);
Zachary Turnerd5bd3a12017-03-12 18:18:50 +0000158 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000159
Zachary Turner2cc5a182017-03-13 00:41:01 +0000160 size_t FullPrefixLen = CompletionBuffer.size();
Zachary Turner0734e6a2017-03-12 20:01:37 +0000161
Zachary Turner2cc5a182017-03-13 00:41:01 +0000162 PartialItem = path::filename(CompletionBuffer);
Frederic Riss78a10a72018-08-31 23:03:28 +0000163
164 // path::filename() will return "." when the passed path ends with a
165 // directory separator. We have to filter those out, but only when the
166 // "." doesn't come from the completion request itself.
167 if (PartialItem == "." && path::is_separator(CompletionBuffer.back()))
Zachary Turner2cc5a182017-03-13 00:41:01 +0000168 PartialItem = llvm::StringRef();
Zachary Turner0734e6a2017-03-12 20:01:37 +0000169
Zachary Turner426d1372017-04-15 02:44:53 +0000170 if (SearchDir.empty()) {
171 llvm::sys::fs::current_path(Storage);
172 SearchDir = Storage;
173 }
Zachary Turner2cc5a182017-03-13 00:41:01 +0000174 assert(!PartialItem.contains(path::get_separator()));
Zachary Turner0734e6a2017-03-12 20:01:37 +0000175
Zachary Turner2cc5a182017-03-13 00:41:01 +0000176 // SearchDir now contains the directory to search in, and Prefix contains the
177 // text we want to match against items in that directory.
178
Jonas Devlieghereedaf2bc2018-12-04 17:58:21 +0000179 FileSystem &fs = FileSystem::Instance();
Zachary Turner2cc5a182017-03-13 00:41:01 +0000180 std::error_code EC;
Jonas Devlieghereedaf2bc2018-12-04 17:58:21 +0000181 llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC);
182 llvm::vfs::directory_iterator End;
Zachary Turner2cc5a182017-03-13 00:41:01 +0000183 for (; Iter != End && !EC; Iter.increment(EC)) {
184 auto &Entry = *Iter;
Jonas Devlieghereedaf2bc2018-12-04 17:58:21 +0000185 llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path());
186
187 if (!Status)
188 continue;
Zachary Turner2cc5a182017-03-13 00:41:01 +0000189
190 auto Name = path::filename(Entry.path());
191
192 // Omit ".", ".."
193 if (Name == "." || Name == ".." || !Name.startswith(PartialItem))
194 continue;
195
Jonas Devlieghereedaf2bc2018-12-04 17:58:21 +0000196 bool is_dir = Status->isDirectory();
Zachary Turner2cc5a182017-03-13 00:41:01 +0000197
198 // If it's a symlink, then we treat it as a directory as long as the target
199 // is a directory.
Jonas Devlieghereedaf2bc2018-12-04 17:58:21 +0000200 if (Status->isSymlink()) {
201 FileSpec symlink_filespec(Entry.path());
202 FileSpec resolved_filespec;
203 auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec);
204 if (error.Success())
205 is_dir = fs.IsDirectory(symlink_filespec);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000206 }
Jonas Devlieghereedaf2bc2018-12-04 17:58:21 +0000207
Zachary Turner2cc5a182017-03-13 00:41:01 +0000208 if (only_directories && !is_dir)
209 continue;
210
211 // Shrink it back down so that it just has the original prefix the user
212 // typed and remove the part of the name which is common to the located
213 // item and what the user typed.
214 CompletionBuffer.resize(FullPrefixLen);
215 Name = Name.drop_front(PartialItem.size());
216 CompletionBuffer.append(Name);
217
218 if (is_dir) {
Zachary Turner2cc5a182017-03-13 00:41:01 +0000219 path::append(CompletionBuffer, path::get_separator());
220 }
221
222 matches.AppendString(CompletionBuffer);
223 }
Zachary Turner0734e6a2017-03-12 20:01:37 +0000224
Kate Stoneb9c1b512016-09-06 20:57:50 +0000225 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000226}
227
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000228static int DiskFilesOrDirectories(CompletionRequest &request,
229 bool only_directories) {
230 request.SetWordComplete(false);
Jonas Devlieghere72787ac2018-11-09 01:59:28 +0000231 StandardTildeExpressionResolver resolver;
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000232 StringList matches;
233 DiskFilesOrDirectories(request.GetCursorArgumentPrefix(), only_directories,
234 matches, resolver);
235 request.AddCompletions(matches);
236 return request.GetNumberOfMatches();
237}
238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000240 CompletionRequest &request,
241 SearchFilter *searcher) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000242 return DiskFilesOrDirectories(request, /*only_dirs*/ false);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000243}
244
245int CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name,
246 StringList &matches,
247 TildeExpressionResolver &Resolver) {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000248 return DiskFilesOrDirectories(partial_file_name, false, matches, Resolver);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000249}
250
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000251int CommandCompletions::DiskDirectories(CommandInterpreter &interpreter,
252 CompletionRequest &request,
253 SearchFilter *searcher) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000254 return DiskFilesOrDirectories(request, /*only_dirs*/ true);
Zachary Turner2cc5a182017-03-13 00:41:01 +0000255}
256
257int CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
258 StringList &matches,
259 TildeExpressionResolver &Resolver) {
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000260 return DiskFilesOrDirectories(partial_file_name, true, matches, Resolver);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000261}
262
263int CommandCompletions::Modules(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000264 CompletionRequest &request,
265 SearchFilter *searcher) {
266 request.SetWordComplete(true);
267 ModuleCompleter completer(interpreter, request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268
269 if (searcher == nullptr) {
270 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
271 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
272 completer.DoCompletion(&null_searcher);
273 } else {
274 completer.DoCompletion(searcher);
275 }
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000276 return request.GetNumberOfMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277}
278
279int CommandCompletions::Symbols(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000280 CompletionRequest &request,
281 SearchFilter *searcher) {
282 request.SetWordComplete(true);
283 SymbolCompleter completer(interpreter, request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284
285 if (searcher == nullptr) {
286 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
287 SearchFilterForUnconstrainedSearches null_searcher(target_sp);
288 completer.DoCompletion(&null_searcher);
289 } else {
290 completer.DoCompletion(searcher);
291 }
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000292 return request.GetNumberOfMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000293}
294
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000295int CommandCompletions::SettingsNames(CommandInterpreter &interpreter,
296 CompletionRequest &request,
297 SearchFilter *searcher) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298 // Cache the full setting name list
299 static StringList g_property_names;
300 if (g_property_names.GetSize() == 0) {
301 // Generate the full setting name list on demand
302 lldb::OptionValuePropertiesSP properties_sp(
303 interpreter.GetDebugger().GetValueProperties());
304 if (properties_sp) {
305 StreamString strm;
306 properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
307 const std::string &str = strm.GetString();
308 g_property_names.SplitIntoLines(str.c_str(), str.size());
309 }
310 }
311
Raphael Isemannb8639f52019-08-19 08:15:46 +0000312 bool exact_match = false;
313
314 for (const std::string &s : g_property_names) {
315 if (llvm::StringRef(s).startswith(request.GetCursorArgumentPrefix())) {
316 if (request.GetCursorArgumentPrefix() == s)
317 exact_match = true;
318 request.AddCompletion(s);
319 }
320 }
321
322 request.SetWordComplete(exact_match);
323
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000324 return request.GetNumberOfMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325}
326
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000327int CommandCompletions::PlatformPluginNames(CommandInterpreter &interpreter,
328 CompletionRequest &request,
329 SearchFilter *searcher) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000330 StringList new_matches;
331 std::size_t num_matches = PluginManager::AutoCompletePlatformName(
332 request.GetCursorArgumentPrefix(), new_matches);
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000333 request.SetWordComplete(num_matches == 1);
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000334 request.AddCompletions(new_matches);
335 return request.GetNumberOfMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000336}
337
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000338int CommandCompletions::ArchitectureNames(CommandInterpreter &interpreter,
339 CompletionRequest &request,
340 SearchFilter *searcher) {
341 const uint32_t num_matches = ArchSpec::AutoComplete(request);
342 request.SetWordComplete(num_matches == 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000343 return num_matches;
344}
345
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000346int CommandCompletions::VariablePath(CommandInterpreter &interpreter,
347 CompletionRequest &request,
348 SearchFilter *searcher) {
349 return Variable::AutoComplete(interpreter.GetExecutionContext(), request);
Greg Claytonf21fead2013-05-14 23:43:18 +0000350}
351
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000352CommandCompletions::Completer::Completer(CommandInterpreter &interpreter,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000353 CompletionRequest &request)
354 : m_interpreter(interpreter), m_request(request) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000355
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000356CommandCompletions::Completer::~Completer() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000357
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000358// SourceFileCompleter
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000359
Kate Stoneb9c1b512016-09-06 20:57:50 +0000360CommandCompletions::SourceFileCompleter::SourceFileCompleter(
361 CommandInterpreter &interpreter, bool include_support_files,
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000362 CompletionRequest &request)
363 : CommandCompletions::Completer(interpreter, request),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000364 m_include_support_files(include_support_files), m_matching_files() {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000365 FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366 m_file_name = partial_spec.GetFilename().GetCString();
367 m_dir_name = partial_spec.GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000368}
369
Jim Ingham4911d362018-09-07 18:43:04 +0000370lldb::SearchDepth CommandCompletions::SourceFileCompleter::GetDepth() {
371 return lldb::eSearchDepthCompUnit;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000372}
373
374Searcher::CallbackReturn
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000375CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter,
376 SymbolContext &context,
377 Address *addr,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000378 bool complete) {
379 if (context.comp_unit != nullptr) {
380 if (m_include_support_files) {
381 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
382 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) {
383 const FileSpec &sfile_spec =
384 supporting_files.GetFileSpecAtIndex(sfiles);
385 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
386 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
387 bool match = false;
388 if (m_file_name && sfile_file_name &&
389 strstr(sfile_file_name, m_file_name) == sfile_file_name)
390 match = true;
391 if (match && m_dir_name && sfile_dir_name &&
392 strstr(sfile_dir_name, m_dir_name) != sfile_dir_name)
393 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000394
Kate Stoneb9c1b512016-09-06 20:57:50 +0000395 if (match) {
396 m_matching_files.AppendIfUnique(sfile_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000397 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000398 }
399 } else {
400 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
401 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000402
Kate Stoneb9c1b512016-09-06 20:57:50 +0000403 bool match = false;
404 if (m_file_name && cur_file_name &&
405 strstr(cur_file_name, m_file_name) == cur_file_name)
406 match = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000407
Kate Stoneb9c1b512016-09-06 20:57:50 +0000408 if (match && m_dir_name && cur_dir_name &&
409 strstr(cur_dir_name, m_dir_name) != cur_dir_name)
410 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000411
Kate Stoneb9c1b512016-09-06 20:57:50 +0000412 if (match) {
413 m_matching_files.AppendIfUnique(context.comp_unit);
414 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000415 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000416 }
417 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000418}
419
420size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000421CommandCompletions::SourceFileCompleter::DoCompletion(SearchFilter *filter) {
422 filter->Search(*this);
423 // Now convert the filelist to completions:
424 for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000425 m_request.AddCompletion(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000426 m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
427 }
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000428 return m_request.GetNumberOfMatches();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000429}
430
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000431// SymbolCompleter
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000432
Kate Stoneb9c1b512016-09-06 20:57:50 +0000433static bool regex_chars(const char comp) {
434 return (comp == '[' || comp == ']' || comp == '(' || comp == ')' ||
435 comp == '{' || comp == '}' || comp == '+' || comp == '.' ||
436 comp == '*' || comp == '|' || comp == '^' || comp == '$' ||
437 comp == '\\' || comp == '?');
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000438}
Eugene Zelenkoc8ecc2a2016-02-19 19:33:46 +0000439
Kate Stoneb9c1b512016-09-06 20:57:50 +0000440CommandCompletions::SymbolCompleter::SymbolCompleter(
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000441 CommandInterpreter &interpreter, CompletionRequest &request)
442 : CommandCompletions::Completer(interpreter, request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000443 std::string regex_str;
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000444 if (!m_request.GetCursorArgumentPrefix().empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000445 regex_str.append("^");
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000446 regex_str.append(m_request.GetCursorArgumentPrefix());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000447 } else {
448 // Match anything since the completion string is empty
449 regex_str.append(".");
450 }
451 std::string::iterator pos =
452 find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
453 while (pos < regex_str.end()) {
454 pos = regex_str.insert(pos, '\\');
455 pos = find_if(pos + 2, regex_str.end(), regex_chars);
456 }
Jan Kratochvilf9d90bc2019-08-20 09:24:20 +0000457 m_regex = RegularExpression(regex_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000458}
459
Jim Ingham4911d362018-09-07 18:43:04 +0000460lldb::SearchDepth CommandCompletions::SymbolCompleter::GetDepth() {
461 return lldb::eSearchDepthModule;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000462}
463
Kate Stoneb9c1b512016-09-06 20:57:50 +0000464Searcher::CallbackReturn CommandCompletions::SymbolCompleter::SearchCallback(
465 SearchFilter &filter, SymbolContext &context, Address *addr,
466 bool complete) {
467 if (context.module_sp) {
468 SymbolContextList sc_list;
469 const bool include_symbols = true;
470 const bool include_inlines = true;
471 const bool append = true;
472 context.module_sp->FindFunctions(m_regex, include_symbols, include_inlines,
473 append, sc_list);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000474
Kate Stoneb9c1b512016-09-06 20:57:50 +0000475 SymbolContext sc;
476 // Now add the functions & symbols to the list - only add if unique:
477 for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
478 if (sc_list.GetContextAtIndex(i, sc)) {
479 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
Jonas Devlieghere07b1a2b2019-07-31 17:58:00 +0000480 // Ensure that the function name matches the regex. This is more than a
481 // sanity check. It is possible that the demangled function name does
482 // not start with the prefix, for example when it's in an anonymous
483 // namespace.
484 if (!func_name.IsEmpty() && m_regex.Execute(func_name.GetStringRef()))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000485 m_match_set.insert(func_name);
486 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000487 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000488 }
489 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000490}
491
Kate Stoneb9c1b512016-09-06 20:57:50 +0000492size_t CommandCompletions::SymbolCompleter::DoCompletion(SearchFilter *filter) {
493 filter->Search(*this);
494 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
495 for (pos = m_match_set.begin(); pos != end; pos++)
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000496 m_request.AddCompletion((*pos).GetCString());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000497
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000498 return m_request.GetNumberOfMatches();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000499}
500
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000501// ModuleCompleter
Kate Stoneb9c1b512016-09-06 20:57:50 +0000502CommandCompletions::ModuleCompleter::ModuleCompleter(
Raphael Isemanna2e76c02018-07-13 18:28:14 +0000503 CommandInterpreter &interpreter, CompletionRequest &request)
504 : CommandCompletions::Completer(interpreter, request) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000505 FileSpec partial_spec(m_request.GetCursorArgumentPrefix());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000506 m_file_name = partial_spec.GetFilename().GetCString();
507 m_dir_name = partial_spec.GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000508}
509
Jim Ingham4911d362018-09-07 18:43:04 +0000510lldb::SearchDepth CommandCompletions::ModuleCompleter::GetDepth() {
511 return lldb::eSearchDepthModule;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000512}
513
Kate Stoneb9c1b512016-09-06 20:57:50 +0000514Searcher::CallbackReturn CommandCompletions::ModuleCompleter::SearchCallback(
515 SearchFilter &filter, SymbolContext &context, Address *addr,
516 bool complete) {
517 if (context.module_sp) {
518 const char *cur_file_name =
519 context.module_sp->GetFileSpec().GetFilename().GetCString();
520 const char *cur_dir_name =
521 context.module_sp->GetFileSpec().GetDirectory().GetCString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000522
Kate Stoneb9c1b512016-09-06 20:57:50 +0000523 bool match = false;
524 if (m_file_name && cur_file_name &&
525 strstr(cur_file_name, m_file_name) == cur_file_name)
526 match = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000527
Kate Stoneb9c1b512016-09-06 20:57:50 +0000528 if (match && m_dir_name && cur_dir_name &&
529 strstr(cur_dir_name, m_dir_name) != cur_dir_name)
530 match = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000531
Kate Stoneb9c1b512016-09-06 20:57:50 +0000532 if (match) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000533 m_request.AddCompletion(cur_file_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000534 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000535 }
536 return Searcher::eCallbackReturnContinue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000537}
538
Kate Stoneb9c1b512016-09-06 20:57:50 +0000539size_t CommandCompletions::ModuleCompleter::DoCompletion(SearchFilter *filter) {
540 filter->Search(*this);
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +0000541 return m_request.GetNumberOfMatches();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000542}