xref: /freebsd/contrib/llvm-project/lldb/source/Symbol/Variable.cpp (revision 9e5787d2284e187abb5b654d924394a65772e004)
1 //===-- Variable.cpp ------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Symbol/Variable.h"
10 
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/Core/ValueObjectVariable.h"
14 #include "lldb/Symbol/Block.h"
15 #include "lldb/Symbol/CompileUnit.h"
16 #include "lldb/Symbol/CompilerDecl.h"
17 #include "lldb/Symbol/CompilerDeclContext.h"
18 #include "lldb/Symbol/Function.h"
19 #include "lldb/Symbol/SymbolContext.h"
20 #include "lldb/Symbol/SymbolFile.h"
21 #include "lldb/Symbol/Type.h"
22 #include "lldb/Symbol/TypeSystem.h"
23 #include "lldb/Symbol/VariableList.h"
24 #include "lldb/Target/ABI.h"
25 #include "lldb/Target/Process.h"
26 #include "lldb/Target/RegisterContext.h"
27 #include "lldb/Target/StackFrame.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Target/Thread.h"
30 #include "lldb/Utility/RegularExpression.h"
31 #include "lldb/Utility/Stream.h"
32 
33 #include "llvm/ADT/Twine.h"
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 
38 Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled,
39                    const lldb::SymbolFileTypeSP &symfile_type_sp,
40                    ValueType scope, SymbolContextScope *context,
41                    const RangeList &scope_range, Declaration *decl_ptr,
42                    const DWARFExpression &location, bool external,
43                    bool artificial, bool static_member)
44     : UserID(uid), m_name(name), m_mangled(ConstString(mangled)),
45       m_symfile_type_sp(symfile_type_sp), m_scope(scope),
46       m_owner_scope(context), m_scope_range(scope_range),
47       m_declaration(decl_ptr), m_location(location), m_external(external),
48       m_artificial(artificial), m_loc_is_const_data(false),
49       m_static_member(static_member) {}
50 
51 Variable::~Variable() {}
52 
53 lldb::LanguageType Variable::GetLanguage() const {
54   lldb::LanguageType lang = m_mangled.GuessLanguage();
55   if (lang != lldb::eLanguageTypeUnknown)
56     return lang;
57 
58   if (auto *func = m_owner_scope->CalculateSymbolContextFunction()) {
59     if ((lang = func->GetLanguage()) != lldb::eLanguageTypeUnknown)
60       return lang;
61   } else if (auto *comp_unit =
62                  m_owner_scope->CalculateSymbolContextCompileUnit()) {
63     if ((lang = comp_unit->GetLanguage()) != lldb::eLanguageTypeUnknown)
64       return lang;
65   }
66 
67   return lldb::eLanguageTypeUnknown;
68 }
69 
70 ConstString Variable::GetName() const {
71   ConstString name = m_mangled.GetName();
72   if (name)
73     return name;
74   return m_name;
75 }
76 
77 ConstString Variable::GetUnqualifiedName() const { return m_name; }
78 
79 bool Variable::NameMatches(ConstString name) const {
80   if (m_name == name)
81     return true;
82   SymbolContext variable_sc;
83   m_owner_scope->CalculateSymbolContext(&variable_sc);
84 
85   return m_mangled.NameMatches(name);
86 }
87 bool Variable::NameMatches(const RegularExpression &regex) const {
88   if (regex.Execute(m_name.AsCString()))
89     return true;
90   if (m_mangled)
91     return m_mangled.NameMatches(regex);
92   return false;
93 }
94 
95 Type *Variable::GetType() {
96   if (m_symfile_type_sp)
97     return m_symfile_type_sp->GetType();
98   return nullptr;
99 }
100 
101 void Variable::Dump(Stream *s, bool show_context) const {
102   s->Printf("%p: ", static_cast<const void *>(this));
103   s->Indent();
104   *s << "Variable" << (const UserID &)*this;
105 
106   if (m_name)
107     *s << ", name = \"" << m_name << "\"";
108 
109   if (m_symfile_type_sp) {
110     Type *type = m_symfile_type_sp->GetType();
111     if (type) {
112       s->Format(", type = {{{0:x-16}} {1} (", type->GetID(), type);
113       type->DumpTypeName(s);
114       s->PutChar(')');
115     }
116   }
117 
118   if (m_scope != eValueTypeInvalid) {
119     s->PutCString(", scope = ");
120     switch (m_scope) {
121     case eValueTypeVariableGlobal:
122       s->PutCString(m_external ? "global" : "static");
123       break;
124     case eValueTypeVariableArgument:
125       s->PutCString("parameter");
126       break;
127     case eValueTypeVariableLocal:
128       s->PutCString("local");
129       break;
130     case eValueTypeVariableThreadLocal:
131       s->PutCString("thread local");
132       break;
133     default:
134       s->AsRawOstream() << "??? (" << m_scope << ')';
135     }
136   }
137 
138   if (show_context && m_owner_scope != nullptr) {
139     s->PutCString(", context = ( ");
140     m_owner_scope->DumpSymbolContext(s);
141     s->PutCString(" )");
142   }
143 
144   bool show_fullpaths = false;
145   m_declaration.Dump(s, show_fullpaths);
146 
147   if (m_location.IsValid()) {
148     s->PutCString(", location = ");
149     lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
150     if (m_location.IsLocationList()) {
151       SymbolContext variable_sc;
152       m_owner_scope->CalculateSymbolContext(&variable_sc);
153       if (variable_sc.function)
154         loclist_base_addr = variable_sc.function->GetAddressRange()
155                                 .GetBaseAddress()
156                                 .GetFileAddress();
157     }
158     ABISP abi;
159     if (m_owner_scope) {
160       ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
161       if (module_sp)
162         abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
163     }
164     m_location.GetDescription(s, lldb::eDescriptionLevelBrief,
165                               loclist_base_addr, abi.get());
166   }
167 
168   if (m_external)
169     s->PutCString(", external");
170 
171   if (m_artificial)
172     s->PutCString(", artificial");
173 
174   s->EOL();
175 }
176 
177 bool Variable::DumpDeclaration(Stream *s, bool show_fullpaths,
178                                bool show_module) {
179   bool dumped_declaration_info = false;
180   if (m_owner_scope) {
181     SymbolContext sc;
182     m_owner_scope->CalculateSymbolContext(&sc);
183     sc.block = nullptr;
184     sc.line_entry.Clear();
185     bool show_inlined_frames = false;
186     const bool show_function_arguments = true;
187     const bool show_function_name = true;
188 
189     dumped_declaration_info = sc.DumpStopContext(
190         s, nullptr, Address(), show_fullpaths, show_module, show_inlined_frames,
191         show_function_arguments, show_function_name);
192 
193     if (sc.function)
194       s->PutChar(':');
195   }
196   if (m_declaration.DumpStopContext(s, false))
197     dumped_declaration_info = true;
198   return dumped_declaration_info;
199 }
200 
201 size_t Variable::MemorySize() const { return sizeof(Variable); }
202 
203 CompilerDeclContext Variable::GetDeclContext() {
204   Type *type = GetType();
205   if (type)
206     return type->GetSymbolFile()->GetDeclContextContainingUID(GetID());
207   return CompilerDeclContext();
208 }
209 
210 CompilerDecl Variable::GetDecl() {
211   Type *type = GetType();
212   return type ? type->GetSymbolFile()->GetDeclForUID(GetID()) : CompilerDecl();
213 }
214 
215 void Variable::CalculateSymbolContext(SymbolContext *sc) {
216   if (m_owner_scope) {
217     m_owner_scope->CalculateSymbolContext(sc);
218     sc->variable = this;
219   } else
220     sc->Clear(false);
221 }
222 
223 bool Variable::LocationIsValidForFrame(StackFrame *frame) {
224   // Is the variable is described by a single location?
225   if (!m_location.IsLocationList()) {
226     // Yes it is, the location is valid.
227     return true;
228   }
229 
230   if (frame) {
231     Function *function =
232         frame->GetSymbolContext(eSymbolContextFunction).function;
233     if (function) {
234       TargetSP target_sp(frame->CalculateTarget());
235 
236       addr_t loclist_base_load_addr =
237           function->GetAddressRange().GetBaseAddress().GetLoadAddress(
238               target_sp.get());
239       if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
240         return false;
241       // It is a location list. We just need to tell if the location list
242       // contains the current address when converted to a load address
243       return m_location.LocationListContainsAddress(
244           loclist_base_load_addr,
245           frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get()));
246     }
247   }
248   return false;
249 }
250 
251 bool Variable::LocationIsValidForAddress(const Address &address) {
252   // Be sure to resolve the address to section offset prior to calling this
253   // function.
254   if (address.IsSectionOffset()) {
255     SymbolContext sc;
256     CalculateSymbolContext(&sc);
257     if (sc.module_sp == address.GetModule()) {
258       // Is the variable is described by a single location?
259       if (!m_location.IsLocationList()) {
260         // Yes it is, the location is valid.
261         return true;
262       }
263 
264       if (sc.function) {
265         addr_t loclist_base_file_addr =
266             sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
267         if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
268           return false;
269         // It is a location list. We just need to tell if the location list
270         // contains the current address when converted to a load address
271         return m_location.LocationListContainsAddress(loclist_base_file_addr,
272                                                       address.GetFileAddress());
273       }
274     }
275   }
276   return false;
277 }
278 
279 bool Variable::IsInScope(StackFrame *frame) {
280   switch (m_scope) {
281   case eValueTypeRegister:
282   case eValueTypeRegisterSet:
283     return frame != nullptr;
284 
285   case eValueTypeConstResult:
286   case eValueTypeVariableGlobal:
287   case eValueTypeVariableStatic:
288   case eValueTypeVariableThreadLocal:
289     return true;
290 
291   case eValueTypeVariableArgument:
292   case eValueTypeVariableLocal:
293     if (frame) {
294       // We don't have a location list, we just need to see if the block that
295       // this variable was defined in is currently
296       Block *deepest_frame_block =
297           frame->GetSymbolContext(eSymbolContextBlock).block;
298       if (deepest_frame_block) {
299         SymbolContext variable_sc;
300         CalculateSymbolContext(&variable_sc);
301 
302         // Check for static or global variable defined at the compile unit
303         // level that wasn't defined in a block
304         if (variable_sc.block == nullptr)
305           return true;
306 
307         // Check if the variable is valid in the current block
308         if (variable_sc.block != deepest_frame_block &&
309             !variable_sc.block->Contains(deepest_frame_block))
310           return false;
311 
312         // If no scope range is specified then it means that the scope is the
313         // same as the scope of the enclosing lexical block.
314         if (m_scope_range.IsEmpty())
315           return true;
316 
317         addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
318         return m_scope_range.FindEntryThatContains(file_address) != nullptr;
319       }
320     }
321     break;
322 
323   default:
324     break;
325   }
326   return false;
327 }
328 
329 Status Variable::GetValuesForVariableExpressionPath(
330     llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
331     GetVariableCallback callback, void *baton, VariableList &variable_list,
332     ValueObjectList &valobj_list) {
333   Status error;
334   if (!callback || variable_expr_path.empty()) {
335     error.SetErrorString("unknown error");
336     return error;
337   }
338 
339   switch (variable_expr_path.front()) {
340   case '*':
341     error = Variable::GetValuesForVariableExpressionPath(
342         variable_expr_path.drop_front(), scope, callback, baton, variable_list,
343         valobj_list);
344     if (error.Fail()) {
345       error.SetErrorString("unknown error");
346       return error;
347     }
348     for (uint32_t i = 0; i < valobj_list.GetSize();) {
349       Status tmp_error;
350       ValueObjectSP valobj_sp(
351           valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
352       if (tmp_error.Fail()) {
353         variable_list.RemoveVariableAtIndex(i);
354         valobj_list.RemoveValueObjectAtIndex(i);
355       } else {
356         valobj_list.SetValueObjectAtIndex(i, valobj_sp);
357         ++i;
358       }
359     }
360     return error;
361   case '&': {
362     error = Variable::GetValuesForVariableExpressionPath(
363         variable_expr_path.drop_front(), scope, callback, baton, variable_list,
364         valobj_list);
365     if (error.Success()) {
366       for (uint32_t i = 0; i < valobj_list.GetSize();) {
367         Status tmp_error;
368         ValueObjectSP valobj_sp(
369             valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
370         if (tmp_error.Fail()) {
371           variable_list.RemoveVariableAtIndex(i);
372           valobj_list.RemoveValueObjectAtIndex(i);
373         } else {
374           valobj_list.SetValueObjectAtIndex(i, valobj_sp);
375           ++i;
376         }
377       }
378     } else {
379       error.SetErrorString("unknown error");
380     }
381     return error;
382   } break;
383 
384   default: {
385     static RegularExpression g_regex(
386         llvm::StringRef("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)"));
387     llvm::SmallVector<llvm::StringRef, 2> matches;
388     variable_list.Clear();
389     if (!g_regex.Execute(variable_expr_path, &matches)) {
390       error.SetErrorStringWithFormat(
391           "unable to extract a variable name from '%s'",
392           variable_expr_path.str().c_str());
393       return error;
394     }
395     std::string variable_name = matches[1].str();
396     if (!callback(baton, variable_name.c_str(), variable_list)) {
397       error.SetErrorString("unknown error");
398       return error;
399     }
400     uint32_t i = 0;
401     while (i < variable_list.GetSize()) {
402       VariableSP var_sp(variable_list.GetVariableAtIndex(i));
403       ValueObjectSP valobj_sp;
404       if (!var_sp) {
405         variable_list.RemoveVariableAtIndex(i);
406         continue;
407       }
408       ValueObjectSP variable_valobj_sp(
409           ValueObjectVariable::Create(scope, var_sp));
410       if (!variable_valobj_sp) {
411         variable_list.RemoveVariableAtIndex(i);
412         continue;
413       }
414 
415       llvm::StringRef variable_sub_expr_path =
416           variable_expr_path.drop_front(variable_name.size());
417       if (!variable_sub_expr_path.empty()) {
418         valobj_sp = variable_valobj_sp->GetValueForExpressionPath(
419             variable_sub_expr_path);
420         if (!valobj_sp) {
421           error.SetErrorStringWithFormat(
422               "invalid expression path '%s' for variable '%s'",
423               variable_sub_expr_path.str().c_str(),
424               var_sp->GetName().GetCString());
425           variable_list.RemoveVariableAtIndex(i);
426           continue;
427         }
428       } else {
429         // Just the name of a variable with no extras
430         valobj_sp = variable_valobj_sp;
431       }
432 
433       valobj_list.Append(valobj_sp);
434       ++i;
435     }
436 
437     if (variable_list.GetSize() > 0) {
438       error.Clear();
439       return error;
440     }
441   } break;
442   }
443   error.SetErrorString("unknown error");
444   return error;
445 }
446 
447 bool Variable::DumpLocationForAddress(Stream *s, const Address &address) {
448   // Be sure to resolve the address to section offset prior to calling this
449   // function.
450   if (address.IsSectionOffset()) {
451     SymbolContext sc;
452     CalculateSymbolContext(&sc);
453     if (sc.module_sp == address.GetModule()) {
454       ABISP abi;
455       if (m_owner_scope) {
456         ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
457         if (module_sp)
458           abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
459       }
460 
461       const addr_t file_addr = address.GetFileAddress();
462       if (sc.function) {
463         if (sc.function->GetAddressRange().ContainsFileAddress(address)) {
464           addr_t loclist_base_file_addr =
465               sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
466           if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
467             return false;
468           return m_location.DumpLocationForAddress(s, eDescriptionLevelBrief,
469                                                    loclist_base_file_addr,
470                                                    file_addr, abi.get());
471         }
472       }
473       return m_location.DumpLocationForAddress(s, eDescriptionLevelBrief,
474                                                LLDB_INVALID_ADDRESS, file_addr,
475                                                abi.get());
476     }
477   }
478   return false;
479 }
480 
481 static void PrivateAutoComplete(
482     StackFrame *frame, llvm::StringRef partial_path,
483     const llvm::Twine
484         &prefix_path, // Anything that has been resolved already will be in here
485     const CompilerType &compiler_type, CompletionRequest &request);
486 
487 static void PrivateAutoCompleteMembers(
488     StackFrame *frame, const std::string &partial_member_name,
489     llvm::StringRef partial_path,
490     const llvm::Twine
491         &prefix_path, // Anything that has been resolved already will be in here
492     const CompilerType &compiler_type, CompletionRequest &request) {
493 
494   // We are in a type parsing child members
495   const uint32_t num_bases = compiler_type.GetNumDirectBaseClasses();
496 
497   if (num_bases > 0) {
498     for (uint32_t i = 0; i < num_bases; ++i) {
499       CompilerType base_class_type =
500           compiler_type.GetDirectBaseClassAtIndex(i, nullptr);
501 
502       PrivateAutoCompleteMembers(frame, partial_member_name, partial_path,
503                                  prefix_path,
504                                  base_class_type.GetCanonicalType(), request);
505     }
506   }
507 
508   const uint32_t num_vbases = compiler_type.GetNumVirtualBaseClasses();
509 
510   if (num_vbases > 0) {
511     for (uint32_t i = 0; i < num_vbases; ++i) {
512       CompilerType vbase_class_type =
513           compiler_type.GetVirtualBaseClassAtIndex(i, nullptr);
514 
515       PrivateAutoCompleteMembers(frame, partial_member_name, partial_path,
516                                  prefix_path,
517                                  vbase_class_type.GetCanonicalType(), request);
518     }
519   }
520 
521   // We are in a type parsing child members
522   const uint32_t num_fields = compiler_type.GetNumFields();
523 
524   if (num_fields > 0) {
525     for (uint32_t i = 0; i < num_fields; ++i) {
526       std::string member_name;
527 
528       CompilerType member_compiler_type = compiler_type.GetFieldAtIndex(
529           i, member_name, nullptr, nullptr, nullptr);
530 
531       if (partial_member_name.empty() ||
532           llvm::StringRef(member_name).startswith(partial_member_name)) {
533         if (member_name == partial_member_name) {
534           PrivateAutoComplete(
535               frame, partial_path,
536               prefix_path + member_name, // Anything that has been resolved
537                                          // already will be in here
538               member_compiler_type.GetCanonicalType(), request);
539         } else {
540           request.AddCompletion((prefix_path + member_name).str());
541         }
542       }
543     }
544   }
545 }
546 
547 static void PrivateAutoComplete(
548     StackFrame *frame, llvm::StringRef partial_path,
549     const llvm::Twine
550         &prefix_path, // Anything that has been resolved already will be in here
551     const CompilerType &compiler_type, CompletionRequest &request) {
552   //    printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path =
553   //    '%s'\n", prefix_path.c_str(), partial_path.c_str());
554   std::string remaining_partial_path;
555 
556   const lldb::TypeClass type_class = compiler_type.GetTypeClass();
557   if (partial_path.empty()) {
558     if (compiler_type.IsValid()) {
559       switch (type_class) {
560       default:
561       case eTypeClassArray:
562       case eTypeClassBlockPointer:
563       case eTypeClassBuiltin:
564       case eTypeClassComplexFloat:
565       case eTypeClassComplexInteger:
566       case eTypeClassEnumeration:
567       case eTypeClassFunction:
568       case eTypeClassMemberPointer:
569       case eTypeClassReference:
570       case eTypeClassTypedef:
571       case eTypeClassVector: {
572         request.AddCompletion(prefix_path.str());
573       } break;
574 
575       case eTypeClassClass:
576       case eTypeClassStruct:
577       case eTypeClassUnion:
578         if (prefix_path.str().back() != '.')
579           request.AddCompletion((prefix_path + ".").str());
580         break;
581 
582       case eTypeClassObjCObject:
583       case eTypeClassObjCInterface:
584         break;
585       case eTypeClassObjCObjectPointer:
586       case eTypeClassPointer: {
587         bool omit_empty_base_classes = true;
588         if (compiler_type.GetNumChildren(omit_empty_base_classes, nullptr) > 0)
589           request.AddCompletion((prefix_path + "->").str());
590         else {
591           request.AddCompletion(prefix_path.str());
592         }
593       } break;
594       }
595     } else {
596       if (frame) {
597         const bool get_file_globals = true;
598 
599         VariableList *variable_list = frame->GetVariableList(get_file_globals);
600 
601         if (variable_list) {
602           for (const VariableSP &var_sp : *variable_list)
603             request.AddCompletion(var_sp->GetName().AsCString());
604         }
605       }
606     }
607   } else {
608     const char ch = partial_path[0];
609     switch (ch) {
610     case '*':
611       if (prefix_path.str().empty()) {
612         PrivateAutoComplete(frame, partial_path.substr(1), "*", compiler_type,
613                             request);
614       }
615       break;
616 
617     case '&':
618       if (prefix_path.isTriviallyEmpty()) {
619         PrivateAutoComplete(frame, partial_path.substr(1), std::string("&"),
620                             compiler_type, request);
621       }
622       break;
623 
624     case '-':
625       if (partial_path.size() > 1 && partial_path[1] == '>' &&
626           !prefix_path.str().empty()) {
627         switch (type_class) {
628         case lldb::eTypeClassPointer: {
629           CompilerType pointee_type(compiler_type.GetPointeeType());
630           if (partial_path.size() > 2 && partial_path[2]) {
631             // If there is more after the "->", then search deeper
632             PrivateAutoComplete(frame, partial_path.substr(2),
633                                 prefix_path + "->",
634                                 pointee_type.GetCanonicalType(), request);
635           } else {
636             // Nothing after the "->", so list all members
637             PrivateAutoCompleteMembers(
638                 frame, std::string(), std::string(), prefix_path + "->",
639                 pointee_type.GetCanonicalType(), request);
640           }
641         } break;
642         default:
643           break;
644         }
645       }
646       break;
647 
648     case '.':
649       if (compiler_type.IsValid()) {
650         switch (type_class) {
651         case lldb::eTypeClassUnion:
652         case lldb::eTypeClassStruct:
653         case lldb::eTypeClassClass:
654           if (partial_path.size() > 1 && partial_path[1]) {
655             // If there is more after the ".", then search deeper
656             PrivateAutoComplete(frame, partial_path.substr(1),
657                                 prefix_path + ".", compiler_type, request);
658 
659           } else {
660             // Nothing after the ".", so list all members
661             PrivateAutoCompleteMembers(frame, std::string(), partial_path,
662                                        prefix_path + ".", compiler_type,
663                                        request);
664           }
665           break;
666         default:
667           break;
668         }
669       }
670       break;
671     default:
672       if (isalpha(ch) || ch == '_' || ch == '$') {
673         const size_t partial_path_len = partial_path.size();
674         size_t pos = 1;
675         while (pos < partial_path_len) {
676           const char curr_ch = partial_path[pos];
677           if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$') {
678             ++pos;
679             continue;
680           }
681           break;
682         }
683 
684         std::string token(std::string(partial_path), 0, pos);
685         remaining_partial_path = std::string(partial_path.substr(pos));
686 
687         if (compiler_type.IsValid()) {
688           PrivateAutoCompleteMembers(frame, token, remaining_partial_path,
689                                      prefix_path, compiler_type, request);
690         } else if (frame) {
691           // We haven't found our variable yet
692           const bool get_file_globals = true;
693 
694           VariableList *variable_list =
695               frame->GetVariableList(get_file_globals);
696 
697           if (!variable_list)
698             break;
699 
700           for (VariableSP var_sp : *variable_list) {
701 
702             if (!var_sp)
703               continue;
704 
705             llvm::StringRef variable_name = var_sp->GetName().GetStringRef();
706             if (variable_name.startswith(token)) {
707               if (variable_name == token) {
708                 Type *variable_type = var_sp->GetType();
709                 if (variable_type) {
710                   CompilerType variable_compiler_type(
711                       variable_type->GetForwardCompilerType());
712                   PrivateAutoComplete(
713                       frame, remaining_partial_path,
714                       prefix_path + token, // Anything that has been resolved
715                                            // already will be in here
716                       variable_compiler_type.GetCanonicalType(), request);
717                 } else {
718                   request.AddCompletion((prefix_path + variable_name).str());
719                 }
720               } else if (remaining_partial_path.empty()) {
721                 request.AddCompletion((prefix_path + variable_name).str());
722               }
723             }
724           }
725         }
726       }
727       break;
728     }
729   }
730 }
731 
732 void Variable::AutoComplete(const ExecutionContext &exe_ctx,
733                             CompletionRequest &request) {
734   CompilerType compiler_type;
735 
736   PrivateAutoComplete(exe_ctx.GetFramePtr(), request.GetCursorArgumentPrefix(),
737                       "", compiler_type, request);
738 }
739