]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp
MFV r320924:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Commands / CommandCompletions.cpp
1 //===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // C Includes
11 #include <sys/stat.h>
12 #if defined(__APPLE__) || defined(__linux__)
13 #include <pwd.h>
14 #endif
15
16 // C++ Includes
17 // Other libraries and framework includes
18 #include "llvm/ADT/SmallString.h"
19
20 // Project includes
21 #include "lldb/Core/FileSpecList.h"
22 #include "lldb/Core/Module.h"
23 #include "lldb/Core/PluginManager.h"
24 #include "lldb/Host/FileSpec.h"
25 #include "lldb/Host/FileSystem.h"
26 #include "lldb/Interpreter/Args.h"
27 #include "lldb/Interpreter/CommandCompletions.h"
28 #include "lldb/Interpreter/CommandInterpreter.h"
29 #include "lldb/Interpreter/OptionValueProperties.h"
30 #include "lldb/Symbol/CompileUnit.h"
31 #include "lldb/Symbol/Variable.h"
32 #include "lldb/Target/Target.h"
33 #include "lldb/Utility/CleanUp.h"
34
35 #include "llvm/ADT/SmallString.h"
36
37 using namespace lldb_private;
38
39 CommandCompletions::CommonCompletionElement
40     CommandCompletions::g_common_completions[] = {
41         {eCustomCompletion, nullptr},
42         {eSourceFileCompletion, CommandCompletions::SourceFiles},
43         {eDiskFileCompletion, CommandCompletions::DiskFiles},
44         {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
45         {eSymbolCompletion, CommandCompletions::Symbols},
46         {eModuleCompletion, CommandCompletions::Modules},
47         {eSettingsNameCompletion, CommandCompletions::SettingsNames},
48         {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
49         {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
50         {eVariablePathCompletion, CommandCompletions::VariablePath},
51         {eNoCompletion, nullptr} // This one has to be last in the list.
52 };
53
54 bool CommandCompletions::InvokeCommonCompletionCallbacks(
55     CommandInterpreter &interpreter, uint32_t completion_mask,
56     llvm::StringRef completion_str, int match_start_point,
57     int max_return_elements, SearchFilter *searcher, bool &word_complete,
58     StringList &matches) {
59   bool handled = false;
60
61   if (completion_mask & eCustomCompletion)
62     return false;
63
64   for (int i = 0;; i++) {
65     if (g_common_completions[i].type == eNoCompletion)
66       break;
67     else if ((g_common_completions[i].type & completion_mask) ==
68                  g_common_completions[i].type &&
69              g_common_completions[i].callback != nullptr) {
70       handled = true;
71       g_common_completions[i].callback(interpreter, completion_str,
72                                        match_start_point, max_return_elements,
73                                        searcher, word_complete, matches);
74     }
75   }
76   return handled;
77 }
78
79 int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
80                                     llvm::StringRef partial_file_name,
81                                     int match_start_point,
82                                     int max_return_elements,
83                                     SearchFilter *searcher, bool &word_complete,
84                                     StringList &matches) {
85   word_complete = true;
86   // Find some way to switch "include support files..."
87   SourceFileCompleter completer(interpreter, false, partial_file_name,
88                                 match_start_point, max_return_elements,
89                                 matches);
90
91   if (searcher == nullptr) {
92     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
93     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
94     completer.DoCompletion(&null_searcher);
95   } else {
96     completer.DoCompletion(searcher);
97   }
98   return matches.GetSize();
99 }
100
101 typedef struct DiskFilesOrDirectoriesBaton {
102   const char *remainder;
103   char *partial_name_copy;
104   bool only_directories;
105   bool *saw_directory;
106   StringList *matches;
107   char *end_ptr;
108   size_t baselen;
109 } DiskFilesOrDirectoriesBaton;
110
111 FileSpec::EnumerateDirectoryResult
112 DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type,
113                                const FileSpec &spec) {
114   const char *name = spec.GetFilename().AsCString();
115
116   const DiskFilesOrDirectoriesBaton *parameters =
117       (DiskFilesOrDirectoriesBaton *)baton;
118   char *end_ptr = parameters->end_ptr;
119   char *partial_name_copy = parameters->partial_name_copy;
120   const char *remainder = parameters->remainder;
121
122   // Omit ".", ".." and any . files if the match string doesn't start with .
123   if (name[0] == '.') {
124     if (name[1] == '\0')
125       return FileSpec::eEnumerateDirectoryResultNext;
126     else if (name[1] == '.' && name[2] == '\0')
127       return FileSpec::eEnumerateDirectoryResultNext;
128     else if (remainder[0] != '.')
129       return FileSpec::eEnumerateDirectoryResultNext;
130   }
131
132   // If we found a directory, we put a "/" at the end of the name.
133
134   if (remainder[0] == '\0' || strstr(name, remainder) == name) {
135     if (strlen(name) + parameters->baselen >= PATH_MAX)
136       return FileSpec::eEnumerateDirectoryResultNext;
137
138     strcpy(end_ptr, name);
139
140     bool isa_directory = false;
141     if (file_type == FileSpec::eFileTypeDirectory)
142       isa_directory = true;
143     else if (file_type == FileSpec::eFileTypeSymbolicLink) {
144       if (FileSpec(partial_name_copy, false).IsDirectory())
145         isa_directory = true;
146     }
147
148     if (isa_directory) {
149       *parameters->saw_directory = true;
150       size_t len = strlen(parameters->partial_name_copy);
151       partial_name_copy[len] = '/';
152       partial_name_copy[len + 1] = '\0';
153     }
154     if (parameters->only_directories && !isa_directory)
155       return FileSpec::eEnumerateDirectoryResultNext;
156     parameters->matches->AppendString(partial_name_copy);
157   }
158
159   return FileSpec::eEnumerateDirectoryResultNext;
160 }
161
162 static int DiskFilesOrDirectories(llvm::StringRef partial_file_name,
163                                   bool only_directories, bool &saw_directory,
164                                   StringList &matches) {
165   // I'm going to  use the "glob" function with GLOB_TILDE for user directory
166   // expansion.
167   // If it is not defined on your host system, you'll need to implement it
168   // yourself...
169
170   size_t partial_name_len = partial_file_name.size();
171
172   if (partial_name_len >= PATH_MAX)
173     return matches.GetSize();
174
175   // This copy of the string will be cut up into the directory part, and the
176   // remainder.  end_ptr below will point to the place of the remainder in this
177   // string.  Then when we've resolved the containing directory, and opened it,
178   // we'll read the directory contents and overwrite the partial_name_copy
179   // starting from end_ptr with each of the matches.  Thus we will preserve the
180   // form the user originally typed.
181
182   char partial_name_copy[PATH_MAX];
183   memcpy(partial_name_copy, partial_file_name.data(), partial_name_len);
184   partial_name_copy[partial_name_len] = '\0';
185
186   // We'll need to save a copy of the remainder for comparison, which we do
187   // here.
188   char remainder[PATH_MAX];
189
190   // end_ptr will point past the last / in partial_name_copy, or if there is no
191   // slash to the beginning of the string.
192   char *end_ptr;
193
194   end_ptr = strrchr(partial_name_copy, '/');
195
196   // This will store the resolved form of the containing directory
197   llvm::SmallString<64> containing_part;
198
199   if (end_ptr == nullptr) {
200     // There's no directory.  If the thing begins with a "~" then this is a bare
201     // user name.
202     if (*partial_name_copy == '~') {
203       // Nothing here but the user name.  We could just put a slash on the end,
204       // but for completeness sake we'll resolve the user name and only put a
205       // slash
206       // on the end if it exists.
207       llvm::SmallString<64> resolved_username(partial_name_copy);
208       FileSpec::ResolveUsername(resolved_username);
209
210       // Not sure how this would happen, a username longer than PATH_MAX?
211       // Still...
212       if (resolved_username.size() == 0) {
213         // The user name didn't resolve, let's look in the password database for
214         // matches.
215         // The user name database contains duplicates, and is not in
216         // alphabetical order, so
217         // we'll use a set to manage that for us.
218         FileSpec::ResolvePartialUsername(partial_name_copy, matches);
219         if (matches.GetSize() > 0)
220           saw_directory = true;
221         return matches.GetSize();
222       } else {
223         // The thing exists, put a '/' on the end, and return it...
224         // FIXME: complete user names here:
225         partial_name_copy[partial_name_len] = '/';
226         partial_name_copy[partial_name_len + 1] = '\0';
227         matches.AppendString(partial_name_copy);
228         saw_directory = true;
229         return matches.GetSize();
230       }
231     } else {
232       // The containing part is the CWD, and the whole string is the remainder.
233       containing_part = ".";
234       strcpy(remainder, partial_name_copy);
235       end_ptr = partial_name_copy;
236     }
237   } else {
238     if (end_ptr == partial_name_copy) {
239       // We're completing a file or directory in the root volume.
240       containing_part = "/";
241     } else {
242       containing_part.append(partial_name_copy, end_ptr);
243     }
244     // Push end_ptr past the final "/" and set remainder.
245     end_ptr++;
246     strcpy(remainder, end_ptr);
247   }
248
249   // Look for a user name in the containing part, and if it's there, resolve it
250   // and stick the
251   // result back into the containing_part:
252
253   if (*partial_name_copy == '~') {
254     FileSpec::ResolveUsername(containing_part);
255     // User name doesn't exist, we're not getting any further...
256     if (containing_part.empty())
257       return matches.GetSize();
258   }
259
260   // Okay, containing_part is now the directory we want to open and look for
261   // files:
262
263   size_t baselen = end_ptr - partial_name_copy;
264
265   DiskFilesOrDirectoriesBaton parameters;
266   parameters.remainder = remainder;
267   parameters.partial_name_copy = partial_name_copy;
268   parameters.only_directories = only_directories;
269   parameters.saw_directory = &saw_directory;
270   parameters.matches = &matches;
271   parameters.end_ptr = end_ptr;
272   parameters.baselen = baselen;
273
274   FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true,
275                                DiskFilesOrDirectoriesCallback, &parameters);
276
277   return matches.GetSize();
278 }
279
280 int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
281                                   llvm::StringRef partial_file_name,
282                                   int match_start_point,
283                                   int max_return_elements,
284                                   SearchFilter *searcher, bool &word_complete,
285                                   StringList &matches) {
286   int ret_val =
287       DiskFilesOrDirectories(partial_file_name, false, word_complete, matches);
288   word_complete = !word_complete;
289   return ret_val;
290 }
291
292 int CommandCompletions::DiskDirectories(
293     CommandInterpreter &interpreter, llvm::StringRef partial_file_name,
294     int match_start_point, int max_return_elements, SearchFilter *searcher,
295     bool &word_complete, StringList &matches) {
296   int ret_val =
297       DiskFilesOrDirectories(partial_file_name, true, word_complete, matches);
298   word_complete = false;
299   return ret_val;
300 }
301
302 int CommandCompletions::Modules(CommandInterpreter &interpreter,
303                                 llvm::StringRef partial_file_name,
304                                 int match_start_point, int max_return_elements,
305                                 SearchFilter *searcher, bool &word_complete,
306                                 StringList &matches) {
307   word_complete = true;
308   ModuleCompleter completer(interpreter, partial_file_name, match_start_point,
309                             max_return_elements, matches);
310
311   if (searcher == nullptr) {
312     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
313     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
314     completer.DoCompletion(&null_searcher);
315   } else {
316     completer.DoCompletion(searcher);
317   }
318   return matches.GetSize();
319 }
320
321 int CommandCompletions::Symbols(CommandInterpreter &interpreter,
322                                 llvm::StringRef partial_file_name,
323                                 int match_start_point, int max_return_elements,
324                                 SearchFilter *searcher, bool &word_complete,
325                                 StringList &matches) {
326   word_complete = true;
327   SymbolCompleter completer(interpreter, partial_file_name, match_start_point,
328                             max_return_elements, matches);
329
330   if (searcher == nullptr) {
331     lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
332     SearchFilterForUnconstrainedSearches null_searcher(target_sp);
333     completer.DoCompletion(&null_searcher);
334   } else {
335     completer.DoCompletion(searcher);
336   }
337   return matches.GetSize();
338 }
339
340 int CommandCompletions::SettingsNames(
341     CommandInterpreter &interpreter, llvm::StringRef partial_setting_name,
342     int match_start_point, int max_return_elements, SearchFilter *searcher,
343     bool &word_complete, StringList &matches) {
344   // Cache the full setting name list
345   static StringList g_property_names;
346   if (g_property_names.GetSize() == 0) {
347     // Generate the full setting name list on demand
348     lldb::OptionValuePropertiesSP properties_sp(
349         interpreter.GetDebugger().GetValueProperties());
350     if (properties_sp) {
351       StreamString strm;
352       properties_sp->DumpValue(nullptr, strm, OptionValue::eDumpOptionName);
353       const std::string &str = strm.GetString();
354       g_property_names.SplitIntoLines(str.c_str(), str.size());
355     }
356   }
357
358   size_t exact_matches_idx = SIZE_MAX;
359   const size_t num_matches = g_property_names.AutoComplete(
360       partial_setting_name, matches, exact_matches_idx);
361   word_complete = exact_matches_idx != SIZE_MAX;
362   return num_matches;
363 }
364
365 int CommandCompletions::PlatformPluginNames(
366     CommandInterpreter &interpreter, llvm::StringRef partial_name,
367     int match_start_point, int max_return_elements, SearchFilter *searcher,
368     bool &word_complete, lldb_private::StringList &matches) {
369   const uint32_t num_matches =
370       PluginManager::AutoCompletePlatformName(partial_name, matches);
371   word_complete = num_matches == 1;
372   return num_matches;
373 }
374
375 int CommandCompletions::ArchitectureNames(
376     CommandInterpreter &interpreter, llvm::StringRef partial_name,
377     int match_start_point, int max_return_elements, SearchFilter *searcher,
378     bool &word_complete, lldb_private::StringList &matches) {
379   const uint32_t num_matches = ArchSpec::AutoComplete(partial_name, matches);
380   word_complete = num_matches == 1;
381   return num_matches;
382 }
383
384 int CommandCompletions::VariablePath(
385     CommandInterpreter &interpreter, llvm::StringRef partial_name,
386     int match_start_point, int max_return_elements, SearchFilter *searcher,
387     bool &word_complete, lldb_private::StringList &matches) {
388   return Variable::AutoComplete(interpreter.GetExecutionContext(), partial_name,
389                                 matches, word_complete);
390 }
391
392 CommandCompletions::Completer::Completer(CommandInterpreter &interpreter,
393                                          llvm::StringRef completion_str,
394                                          int match_start_point,
395                                          int max_return_elements,
396                                          StringList &matches)
397     : m_interpreter(interpreter), m_completion_str(completion_str),
398       m_match_start_point(match_start_point),
399       m_max_return_elements(max_return_elements), m_matches(matches) {}
400
401 CommandCompletions::Completer::~Completer() = default;
402
403 //----------------------------------------------------------------------
404 // SourceFileCompleter
405 //----------------------------------------------------------------------
406
407 CommandCompletions::SourceFileCompleter::SourceFileCompleter(
408     CommandInterpreter &interpreter, bool include_support_files,
409     llvm::StringRef completion_str, int match_start_point,
410     int max_return_elements, StringList &matches)
411     : CommandCompletions::Completer(interpreter, completion_str,
412                                     match_start_point, max_return_elements,
413                                     matches),
414       m_include_support_files(include_support_files), m_matching_files() {
415   FileSpec partial_spec(m_completion_str, false);
416   m_file_name = partial_spec.GetFilename().GetCString();
417   m_dir_name = partial_spec.GetDirectory().GetCString();
418 }
419
420 Searcher::Depth CommandCompletions::SourceFileCompleter::GetDepth() {
421   return eDepthCompUnit;
422 }
423
424 Searcher::CallbackReturn
425 CommandCompletions::SourceFileCompleter::SearchCallback(SearchFilter &filter,
426                                                         SymbolContext &context,
427                                                         Address *addr,
428                                                         bool complete) {
429   if (context.comp_unit != nullptr) {
430     if (m_include_support_files) {
431       FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
432       for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) {
433         const FileSpec &sfile_spec =
434             supporting_files.GetFileSpecAtIndex(sfiles);
435         const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
436         const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
437         bool match = false;
438         if (m_file_name && sfile_file_name &&
439             strstr(sfile_file_name, m_file_name) == sfile_file_name)
440           match = true;
441         if (match && m_dir_name && sfile_dir_name &&
442             strstr(sfile_dir_name, m_dir_name) != sfile_dir_name)
443           match = false;
444
445         if (match) {
446           m_matching_files.AppendIfUnique(sfile_spec);
447         }
448       }
449     } else {
450       const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
451       const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
452
453       bool match = false;
454       if (m_file_name && cur_file_name &&
455           strstr(cur_file_name, m_file_name) == cur_file_name)
456         match = true;
457
458       if (match && m_dir_name && cur_dir_name &&
459           strstr(cur_dir_name, m_dir_name) != cur_dir_name)
460         match = false;
461
462       if (match) {
463         m_matching_files.AppendIfUnique(context.comp_unit);
464       }
465     }
466   }
467   return Searcher::eCallbackReturnContinue;
468 }
469
470 size_t
471 CommandCompletions::SourceFileCompleter::DoCompletion(SearchFilter *filter) {
472   filter->Search(*this);
473   // Now convert the filelist to completions:
474   for (size_t i = 0; i < m_matching_files.GetSize(); i++) {
475     m_matches.AppendString(
476         m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
477   }
478   return m_matches.GetSize();
479 }
480
481 //----------------------------------------------------------------------
482 // SymbolCompleter
483 //----------------------------------------------------------------------
484
485 static bool regex_chars(const char comp) {
486   return (comp == '[' || comp == ']' || comp == '(' || comp == ')' ||
487           comp == '{' || comp == '}' || comp == '+' || comp == '.' ||
488           comp == '*' || comp == '|' || comp == '^' || comp == '$' ||
489           comp == '\\' || comp == '?');
490 }
491
492 CommandCompletions::SymbolCompleter::SymbolCompleter(
493     CommandInterpreter &interpreter, llvm::StringRef completion_str,
494     int match_start_point, int max_return_elements, StringList &matches)
495     : CommandCompletions::Completer(interpreter, completion_str,
496                                     match_start_point, max_return_elements,
497                                     matches) {
498   std::string regex_str;
499   if (!completion_str.empty()) {
500     regex_str.append("^");
501     regex_str.append(completion_str);
502   } else {
503     // Match anything since the completion string is empty
504     regex_str.append(".");
505   }
506   std::string::iterator pos =
507       find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
508   while (pos < regex_str.end()) {
509     pos = regex_str.insert(pos, '\\');
510     pos = find_if(pos + 2, regex_str.end(), regex_chars);
511   }
512   m_regex.Compile(regex_str);
513 }
514
515 Searcher::Depth CommandCompletions::SymbolCompleter::GetDepth() {
516   return eDepthModule;
517 }
518
519 Searcher::CallbackReturn CommandCompletions::SymbolCompleter::SearchCallback(
520     SearchFilter &filter, SymbolContext &context, Address *addr,
521     bool complete) {
522   if (context.module_sp) {
523     SymbolContextList sc_list;
524     const bool include_symbols = true;
525     const bool include_inlines = true;
526     const bool append = true;
527     context.module_sp->FindFunctions(m_regex, include_symbols, include_inlines,
528                                      append, sc_list);
529
530     SymbolContext sc;
531     // Now add the functions & symbols to the list - only add if unique:
532     for (uint32_t i = 0; i < sc_list.GetSize(); i++) {
533       if (sc_list.GetContextAtIndex(i, sc)) {
534         ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
535         if (!func_name.IsEmpty())
536           m_match_set.insert(func_name);
537       }
538     }
539   }
540   return Searcher::eCallbackReturnContinue;
541 }
542
543 size_t CommandCompletions::SymbolCompleter::DoCompletion(SearchFilter *filter) {
544   filter->Search(*this);
545   collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
546   for (pos = m_match_set.begin(); pos != end; pos++)
547     m_matches.AppendString((*pos).GetCString());
548
549   return m_matches.GetSize();
550 }
551
552 //----------------------------------------------------------------------
553 // ModuleCompleter
554 //----------------------------------------------------------------------
555 CommandCompletions::ModuleCompleter::ModuleCompleter(
556     CommandInterpreter &interpreter, llvm::StringRef completion_str,
557     int match_start_point, int max_return_elements, StringList &matches)
558     : CommandCompletions::Completer(interpreter, completion_str,
559                                     match_start_point, max_return_elements,
560                                     matches) {
561   FileSpec partial_spec(m_completion_str, false);
562   m_file_name = partial_spec.GetFilename().GetCString();
563   m_dir_name = partial_spec.GetDirectory().GetCString();
564 }
565
566 Searcher::Depth CommandCompletions::ModuleCompleter::GetDepth() {
567   return eDepthModule;
568 }
569
570 Searcher::CallbackReturn CommandCompletions::ModuleCompleter::SearchCallback(
571     SearchFilter &filter, SymbolContext &context, Address *addr,
572     bool complete) {
573   if (context.module_sp) {
574     const char *cur_file_name =
575         context.module_sp->GetFileSpec().GetFilename().GetCString();
576     const char *cur_dir_name =
577         context.module_sp->GetFileSpec().GetDirectory().GetCString();
578
579     bool match = false;
580     if (m_file_name && cur_file_name &&
581         strstr(cur_file_name, m_file_name) == cur_file_name)
582       match = true;
583
584     if (match && m_dir_name && cur_dir_name &&
585         strstr(cur_dir_name, m_dir_name) != cur_dir_name)
586       match = false;
587
588     if (match) {
589       m_matches.AppendString(cur_file_name);
590     }
591   }
592   return Searcher::eCallbackReturnContinue;
593 }
594
595 size_t CommandCompletions::ModuleCompleter::DoCompletion(SearchFilter *filter) {
596   filter->Search(*this);
597   return m_matches.GetSize();
598 }