1 //===-- Variable.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 #include "lldb/Symbol/Variable.h"
11 
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Stream.h"
14 #include "lldb/Core/RegularExpression.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Core/ValueObjectVariable.h"
17 #include "lldb/Symbol/Block.h"
18 #include "lldb/Symbol/CompileUnit.h"
19 #include "lldb/Symbol/Function.h"
20 #include "lldb/Symbol/SymbolContext.h"
21 #include "lldb/Symbol/Type.h"
22 #include "lldb/Symbol/VariableList.h"
23 #include "lldb/Target/ABI.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/RegisterContext.h"
26 #include "lldb/Target/StackFrame.h"
27 #include "lldb/Target/Thread.h"
28 #include "lldb/Target/Target.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 //----------------------------------------------------------------------
34 // Variable constructor
35 //----------------------------------------------------------------------
36 Variable::Variable
37 (
38     lldb::user_id_t uid,
39     const char *name,
40     const char *mangled,  // The mangled or fully qualified name of the variable.
41     const lldb::SymbolFileTypeSP &symfile_type_sp,
42     ValueType scope,
43     SymbolContextScope *context,
44     Declaration* decl_ptr,
45     const DWARFExpression& location,
46     bool external,
47     bool artificial,
48     bool static_member
49 ) :
50     UserID(uid),
51     m_name(name),
52     m_mangled (ConstString(mangled)),
53     m_symfile_type_sp(symfile_type_sp),
54     m_scope(scope),
55     m_owner_scope(context),
56     m_declaration(decl_ptr),
57     m_location(location),
58     m_external(external),
59     m_artificial(artificial),
60     m_static_member(static_member)
61 {
62 }
63 
64 //----------------------------------------------------------------------
65 // Destructor
66 //----------------------------------------------------------------------
67 Variable::~Variable()
68 {
69 }
70 
71 lldb::LanguageType
72 Variable::GetLanguage () const
73 {
74     SymbolContext variable_sc;
75     m_owner_scope->CalculateSymbolContext(&variable_sc);
76     if (variable_sc.comp_unit)
77         return variable_sc.comp_unit->GetLanguage();
78     return lldb::eLanguageTypeUnknown;
79 }
80 
81 
82 
83 ConstString
84 Variable::GetName() const
85 {
86     ConstString name = m_mangled.GetName(GetLanguage());
87     if (name)
88         return name;
89     return m_name;
90 }
91 
92 bool
93 Variable::NameMatches (const ConstString &name) const
94 {
95     if (m_name == name)
96         return true;
97     SymbolContext variable_sc;
98     m_owner_scope->CalculateSymbolContext(&variable_sc);
99 
100     LanguageType language = eLanguageTypeUnknown;
101     if (variable_sc.comp_unit)
102         language = variable_sc.comp_unit->GetLanguage();
103     return m_mangled.NameMatches (name, language);
104 }
105 bool
106 Variable::NameMatches (const RegularExpression& regex) const
107 {
108     if (regex.Execute (m_name.AsCString()))
109         return true;
110     if (m_mangled)
111         return m_mangled.NameMatches (regex, GetLanguage());
112     return false;
113 }
114 
115 Type *
116 Variable::GetType()
117 {
118     if (m_symfile_type_sp)
119         return m_symfile_type_sp->GetType();
120     return nullptr;
121 }
122 
123 void
124 Variable::Dump(Stream *s, bool show_context) const
125 {
126     s->Printf("%p: ", static_cast<const void*>(this));
127     s->Indent();
128     *s << "Variable" << (const UserID&)*this;
129 
130     if (m_name)
131         *s << ", name = \"" << m_name << "\"";
132 
133     if (m_symfile_type_sp)
134     {
135         Type *type = m_symfile_type_sp->GetType();
136         if (type)
137         {
138             *s << ", type = {" << type->GetID() << "} " << (void*)type << " (";
139             type->DumpTypeName(s);
140             s->PutChar(')');
141         }
142     }
143 
144     if (m_scope != eValueTypeInvalid)
145     {
146         s->PutCString(", scope = ");
147         switch (m_scope)
148         {
149         case eValueTypeVariableGlobal:       s->PutCString(m_external ? "global" : "static"); break;
150         case eValueTypeVariableArgument:    s->PutCString("parameter"); break;
151         case eValueTypeVariableLocal:        s->PutCString("local"); break;
152         default:            *s << "??? (" << m_scope << ')';
153         }
154     }
155 
156     if (show_context && m_owner_scope != nullptr)
157     {
158         s->PutCString(", context = ( ");
159         m_owner_scope->DumpSymbolContext(s);
160         s->PutCString(" )");
161     }
162 
163     bool show_fullpaths = false;
164     m_declaration.Dump(s, show_fullpaths);
165 
166     if (m_location.IsValid())
167     {
168         s->PutCString(", location = ");
169         lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
170         if (m_location.IsLocationList())
171         {
172             SymbolContext variable_sc;
173             m_owner_scope->CalculateSymbolContext(&variable_sc);
174             if (variable_sc.function)
175                 loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
176         }
177         ABI *abi = nullptr;
178         if (m_owner_scope)
179         {
180             ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
181             if (module_sp)
182                 abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
183         }
184         m_location.GetDescription(s, lldb::eDescriptionLevelBrief, loclist_base_addr, abi);
185     }
186 
187     if (m_external)
188         s->PutCString(", external");
189 
190     if (m_artificial)
191         s->PutCString(", artificial");
192 
193     s->EOL();
194 }
195 
196 bool
197 Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
198 {
199     bool dumped_declaration_info = false;
200     if (m_owner_scope)
201     {
202         SymbolContext sc;
203         m_owner_scope->CalculateSymbolContext(&sc);
204         sc.block = nullptr;
205         sc.line_entry.Clear();
206         bool show_inlined_frames = false;
207         const bool show_function_arguments = true;
208         const bool show_function_name = true;
209 
210         dumped_declaration_info = sc.DumpStopContext (s,
211                                                       nullptr,
212                                                       Address(),
213                                                       show_fullpaths,
214                                                       show_module,
215                                                       show_inlined_frames,
216                                                       show_function_arguments,
217                                                       show_function_name);
218 
219         if (sc.function)
220             s->PutChar(':');
221     }
222     if (m_declaration.DumpStopContext (s, false))
223         dumped_declaration_info = true;
224     return dumped_declaration_info;
225 }
226 
227 size_t
228 Variable::MemorySize() const
229 {
230     return sizeof(Variable);
231 }
232 
233 
234 void
235 Variable::CalculateSymbolContext (SymbolContext *sc)
236 {
237     if (m_owner_scope)
238     {
239         m_owner_scope->CalculateSymbolContext(sc);
240         sc->variable = this;
241     }
242     else
243         sc->Clear(false);
244 }
245 
246 bool
247 Variable::LocationIsValidForFrame (StackFrame *frame)
248 {
249     // Is the variable is described by a single location?
250     if (!m_location.IsLocationList())
251     {
252         // Yes it is, the location is valid.
253         return true;
254     }
255 
256     if (frame)
257     {
258         Function *function = frame->GetSymbolContext(eSymbolContextFunction).function;
259         if (function)
260         {
261             TargetSP target_sp (frame->CalculateTarget());
262 
263             addr_t loclist_base_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress (target_sp.get());
264             if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
265                 return false;
266             // It is a location list. We just need to tell if the location
267             // list contains the current address when converted to a load
268             // address
269             return m_location.LocationListContainsAddress (loclist_base_load_addr,
270                                                            frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get()));
271         }
272     }
273     return false;
274 }
275 
276 bool
277 Variable::LocationIsValidForAddress (const Address &address)
278 {
279     // Be sure to resolve the address to section offset prior to
280     // calling this function.
281     if (address.IsSectionOffset())
282     {
283         SymbolContext sc;
284         CalculateSymbolContext(&sc);
285         if (sc.module_sp == address.GetModule())
286         {
287             // Is the variable is described by a single location?
288             if (!m_location.IsLocationList())
289             {
290                 // Yes it is, the location is valid.
291                 return true;
292             }
293 
294             if (sc.function)
295             {
296                 addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
297                 if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
298                     return false;
299                 // It is a location list. We just need to tell if the location
300                 // list contains the current address when converted to a load
301                 // address
302                 return m_location.LocationListContainsAddress (loclist_base_file_addr,
303                                                                address.GetFileAddress());
304             }
305         }
306     }
307     return false;
308 }
309 
310 bool
311 Variable::IsInScope (StackFrame *frame)
312 {
313     switch (m_scope)
314     {
315     case eValueTypeRegister:
316     case eValueTypeRegisterSet:
317         return frame != nullptr;
318 
319     case eValueTypeConstResult:
320     case eValueTypeVariableGlobal:
321     case eValueTypeVariableStatic:
322         return true;
323 
324     case eValueTypeVariableArgument:
325     case eValueTypeVariableLocal:
326         if (frame)
327         {
328             // We don't have a location list, we just need to see if the block
329             // that this variable was defined in is currently
330             Block *deepest_frame_block = frame->GetSymbolContext(eSymbolContextBlock).block;
331             if (deepest_frame_block)
332             {
333                 SymbolContext variable_sc;
334                 CalculateSymbolContext (&variable_sc);
335                 // Check for static or global variable defined at the compile unit
336                 // level that wasn't defined in a block
337                 if (variable_sc.block == nullptr)
338                     return true;
339 
340                 if (variable_sc.block == deepest_frame_block)
341                     return true;
342                 return variable_sc.block->Contains (deepest_frame_block);
343             }
344         }
345         break;
346 
347     default:
348         break;
349     }
350     return false;
351 }
352 
353 Error
354 Variable::GetValuesForVariableExpressionPath (const char *variable_expr_path,
355                                               ExecutionContextScope *scope,
356                                               GetVariableCallback callback,
357                                               void *baton,
358                                               VariableList &variable_list,
359                                               ValueObjectList &valobj_list)
360 {
361     Error error;
362     if (variable_expr_path && callback)
363     {
364         switch (variable_expr_path[0])
365         {
366         case '*':
367             {
368                 error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
369                                                                       scope,
370                                                                       callback,
371                                                                       baton,
372                                                                       variable_list,
373                                                                       valobj_list);
374                 if (error.Success())
375                 {
376                     for (uint32_t i=0; i<valobj_list.GetSize(); )
377                     {
378                         Error tmp_error;
379                         ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
380                         if (tmp_error.Fail())
381                         {
382                             variable_list.RemoveVariableAtIndex (i);
383                             valobj_list.RemoveValueObjectAtIndex (i);
384                         }
385                         else
386                         {
387                             valobj_list.SetValueObjectAtIndex (i, valobj_sp);
388                             ++i;
389                         }
390                     }
391                 }
392                 else
393                 {
394                     error.SetErrorString ("unknown error");
395                 }
396                 return error;
397             }
398             break;
399 
400         case '&':
401             {
402                 error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
403                                                                       scope,
404                                                                       callback,
405                                                                       baton,
406                                                                       variable_list,
407                                                                       valobj_list);
408                 if (error.Success())
409                 {
410                     for (uint32_t i=0; i<valobj_list.GetSize(); )
411                     {
412                         Error tmp_error;
413                         ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
414                         if (tmp_error.Fail())
415                         {
416                             variable_list.RemoveVariableAtIndex (i);
417                             valobj_list.RemoveValueObjectAtIndex (i);
418                         }
419                         else
420                         {
421                             valobj_list.SetValueObjectAtIndex (i, valobj_sp);
422                             ++i;
423                         }
424                     }
425                 }
426                 else
427                 {
428                     error.SetErrorString ("unknown error");
429                 }
430                 return error;
431             }
432             break;
433 
434         default:
435             {
436                 static RegularExpression g_regex ("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)");
437                 RegularExpression::Match regex_match(1);
438                 if (g_regex.Execute(variable_expr_path, &regex_match))
439                 {
440                     std::string variable_name;
441                     if (regex_match.GetMatchAtIndex(variable_expr_path, 1, variable_name))
442                     {
443                         variable_list.Clear();
444                         if (callback (baton, variable_name.c_str(), variable_list))
445                         {
446                             uint32_t i=0;
447                             while (i < variable_list.GetSize())
448                             {
449                                 VariableSP var_sp (variable_list.GetVariableAtIndex (i));
450                                 ValueObjectSP valobj_sp;
451                                 if (var_sp)
452                                 {
453                                     ValueObjectSP variable_valobj_sp(ValueObjectVariable::Create (scope, var_sp));
454                                     if (variable_valobj_sp)
455                                     {
456                                         const char *variable_sub_expr_path = variable_expr_path + variable_name.size();
457                                         if (*variable_sub_expr_path)
458                                         {
459                                             const char* first_unparsed = nullptr;
460                                             ValueObject::ExpressionPathScanEndReason reason_to_stop;
461                                             ValueObject::ExpressionPathEndResultType final_value_type;
462                                             ValueObject::GetValueForExpressionPathOptions options;
463                                             ValueObject::ExpressionPathAftermath final_task_on_target;
464 
465                                             valobj_sp = variable_valobj_sp->GetValueForExpressionPath (variable_sub_expr_path,
466                                                                                                        &first_unparsed,
467                                                                                                        &reason_to_stop,
468                                                                                                        &final_value_type,
469                                                                                                        options,
470                                                                                                        &final_task_on_target);
471                                             if (!valobj_sp)
472                                             {
473                                                 error.SetErrorStringWithFormat ("invalid expression path '%s' for variable '%s'",
474                                                                                 variable_sub_expr_path,
475                                                                                 var_sp->GetName().GetCString());
476                                             }
477                                         }
478                                         else
479                                         {
480                                             // Just the name of a variable with no extras
481                                             valobj_sp = variable_valobj_sp;
482                                         }
483                                     }
484                                 }
485 
486                                 if (!var_sp || !valobj_sp)
487                                 {
488                                     variable_list.RemoveVariableAtIndex (i);
489                                 }
490                                 else
491                                 {
492                                     valobj_list.Append(valobj_sp);
493                                     ++i;
494                                 }
495                             }
496 
497                             if (variable_list.GetSize() > 0)
498                             {
499                                 error.Clear();
500                                 return error;
501                             }
502                         }
503                     }
504                 }
505                 error.SetErrorStringWithFormat ("unable to extract a variable name from '%s'", variable_expr_path);
506             }
507             break;
508         }
509     }
510     error.SetErrorString ("unknown error");
511     return error;
512 }
513 
514 bool
515 Variable::DumpLocationForAddress (Stream *s, const Address &address)
516 {
517     // Be sure to resolve the address to section offset prior to
518     // calling this function.
519     if (address.IsSectionOffset())
520     {
521         SymbolContext sc;
522         CalculateSymbolContext(&sc);
523         if (sc.module_sp == address.GetModule())
524         {
525             ABI *abi = nullptr;
526             if (m_owner_scope)
527             {
528                 ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
529                 if (module_sp)
530                     abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
531             }
532 
533             const addr_t file_addr = address.GetFileAddress();
534             if (sc.function)
535             {
536                 if (sc.function->GetAddressRange().ContainsFileAddress(address))
537                 {
538                     addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
539                     if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
540                         return false;
541                     return m_location.DumpLocationForAddress (s,
542                                                               eDescriptionLevelBrief,
543                                                               loclist_base_file_addr,
544                                                               file_addr,
545                                                               abi);
546                 }
547             }
548             return m_location.DumpLocationForAddress (s,
549                                                       eDescriptionLevelBrief,
550                                                       LLDB_INVALID_ADDRESS,
551                                                       file_addr,
552                                                       abi);
553         }
554     }
555     return false;
556 }
557 
558 
559 static void
560 PrivateAutoComplete (StackFrame *frame,
561                      const std::string &partial_path,
562                      const std::string &prefix_path, // Anything that has been resolved already will be in here
563                      const CompilerType& clang_type,
564                      StringList &matches,
565                      bool &word_complete);
566 
567 static void
568 PrivateAutoCompleteMembers (StackFrame *frame,
569                             const std::string &partial_member_name,
570                             const std::string &partial_path,
571                             const std::string &prefix_path, // Anything that has been resolved already will be in here
572                             const CompilerType& clang_type,
573                             StringList &matches,
574                             bool &word_complete);
575 
576 static void
577 PrivateAutoCompleteMembers (StackFrame *frame,
578                             const std::string &partial_member_name,
579                             const std::string &partial_path,
580                             const std::string &prefix_path, // Anything that has been resolved already will be in here
581                             const CompilerType& clang_type,
582                             StringList &matches,
583                             bool &word_complete)
584 {
585 
586     // We are in a type parsing child members
587     const uint32_t num_bases = clang_type.GetNumDirectBaseClasses();
588 
589     if (num_bases > 0)
590     {
591         for (uint32_t i = 0; i < num_bases; ++i)
592         {
593             CompilerType base_class_type = clang_type.GetDirectBaseClassAtIndex(i, nullptr);
594 
595             PrivateAutoCompleteMembers (frame,
596                                         partial_member_name,
597                                         partial_path,
598                                         prefix_path,
599                                         base_class_type.GetCanonicalType(),
600                                         matches,
601                                         word_complete);
602         }
603     }
604 
605     const uint32_t num_vbases = clang_type.GetNumVirtualBaseClasses();
606 
607     if (num_vbases > 0)
608     {
609         for (uint32_t i = 0; i < num_vbases; ++i)
610         {
611             CompilerType vbase_class_type = clang_type.GetVirtualBaseClassAtIndex(i,nullptr);
612 
613             PrivateAutoCompleteMembers (frame,
614                                         partial_member_name,
615                                         partial_path,
616                                         prefix_path,
617                                         vbase_class_type.GetCanonicalType(),
618                                         matches,
619                                         word_complete);
620         }
621     }
622 
623     // We are in a type parsing child members
624     const uint32_t num_fields = clang_type.GetNumFields();
625 
626     if (num_fields > 0)
627     {
628         for (uint32_t i = 0; i < num_fields; ++i)
629         {
630             std::string member_name;
631 
632             CompilerType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, nullptr, nullptr, nullptr);
633 
634             if (partial_member_name.empty() ||
635                 member_name.find(partial_member_name) == 0)
636             {
637                 if (member_name == partial_member_name)
638                 {
639                     PrivateAutoComplete (frame,
640                                          partial_path,
641                                          prefix_path + member_name, // Anything that has been resolved already will be in here
642                                          member_clang_type.GetCanonicalType(),
643                                          matches,
644                                          word_complete);
645                 }
646                 else
647                 {
648                     matches.AppendString (prefix_path + member_name);
649                 }
650             }
651         }
652     }
653 }
654 
655 static void
656 PrivateAutoComplete (StackFrame *frame,
657                      const std::string &partial_path,
658                      const std::string &prefix_path, // Anything that has been resolved already will be in here
659                      const CompilerType& clang_type,
660                      StringList &matches,
661                      bool &word_complete)
662 {
663 //    printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str());
664     std::string remaining_partial_path;
665 
666     const lldb::TypeClass type_class = clang_type.GetTypeClass();
667     if (partial_path.empty())
668     {
669         if (clang_type.IsValid())
670         {
671             switch (type_class)
672             {
673                 default:
674                 case eTypeClassArray:
675                 case eTypeClassBlockPointer:
676                 case eTypeClassBuiltin:
677                 case eTypeClassComplexFloat:
678                 case eTypeClassComplexInteger:
679                 case eTypeClassEnumeration:
680                 case eTypeClassFunction:
681                 case eTypeClassMemberPointer:
682                 case eTypeClassReference:
683                 case eTypeClassTypedef:
684                 case eTypeClassVector:
685                     {
686                         matches.AppendString (prefix_path);
687                         word_complete = matches.GetSize() == 1;
688                     }
689                     break;
690 
691                 case eTypeClassClass:
692                 case eTypeClassStruct:
693                 case eTypeClassUnion:
694                     if (prefix_path.back() != '.')
695                         matches.AppendString (prefix_path + '.');
696                     break;
697 
698                 case eTypeClassObjCObject:
699                 case eTypeClassObjCInterface:
700                     break;
701                 case eTypeClassObjCObjectPointer:
702                 case eTypeClassPointer:
703                     {
704                         bool omit_empty_base_classes = true;
705                         if (clang_type.GetNumChildren (omit_empty_base_classes) > 0)
706                             matches.AppendString (prefix_path + "->");
707                         else
708                         {
709                             matches.AppendString (prefix_path);
710                             word_complete = true;
711                         }
712                     }
713                     break;
714             }
715         }
716         else
717         {
718             if (frame)
719             {
720                 const bool get_file_globals = true;
721 
722                 VariableList *variable_list = frame->GetVariableList(get_file_globals);
723 
724                 if (variable_list)
725                 {
726                     const size_t num_variables = variable_list->GetSize();
727                     for (size_t i=0; i<num_variables; ++i)
728                     {
729                         Variable *variable = variable_list->GetVariableAtIndex(i).get();
730                         matches.AppendString (variable->GetName().AsCString());
731                     }
732                 }
733             }
734         }
735     }
736     else
737     {
738         const char ch = partial_path[0];
739         switch (ch)
740         {
741         case '*':
742             if (prefix_path.empty())
743             {
744                 PrivateAutoComplete (frame,
745                                      partial_path.substr(1),
746                                      std::string("*"),
747                                      clang_type,
748                                      matches,
749                                      word_complete);
750             }
751             break;
752 
753         case '&':
754             if (prefix_path.empty())
755             {
756                 PrivateAutoComplete (frame,
757                                      partial_path.substr(1),
758                                      std::string("&"),
759                                      clang_type,
760                                      matches,
761                                      word_complete);
762             }
763             break;
764 
765         case '-':
766             if (partial_path[1] == '>' && !prefix_path.empty())
767             {
768                 switch (type_class)
769                 {
770                     case lldb::eTypeClassPointer:
771                         {
772                             CompilerType pointee_type(clang_type.GetPointeeType());
773                             if (partial_path[2])
774                             {
775                                 // If there is more after the "->", then search deeper
776                                 PrivateAutoComplete (frame,
777                                                      partial_path.substr(2),
778                                                      prefix_path + "->",
779                                                      pointee_type.GetCanonicalType(),
780                                                      matches,
781                                                      word_complete);
782                             }
783                             else
784                             {
785                                 // Nothing after the "->", so list all members
786                                 PrivateAutoCompleteMembers (frame,
787                                                             std::string(),
788                                                             std::string(),
789                                                             prefix_path + "->",
790                                                             pointee_type.GetCanonicalType(),
791                                                             matches,
792                                                             word_complete);
793                             }
794                         }
795                     default:
796                         break;
797                 }
798             }
799             break;
800 
801         case '.':
802             if (clang_type.IsValid())
803             {
804                 switch (type_class)
805                 {
806                     case lldb::eTypeClassUnion:
807                     case lldb::eTypeClassStruct:
808                     case lldb::eTypeClassClass:
809                         if (partial_path[1])
810                         {
811                             // If there is more after the ".", then search deeper
812                             PrivateAutoComplete (frame,
813                                                  partial_path.substr(1),
814                                                  prefix_path + ".",
815                                                  clang_type,
816                                                  matches,
817                                                  word_complete);
818 
819                         }
820                         else
821                         {
822                             // Nothing after the ".", so list all members
823                             PrivateAutoCompleteMembers (frame,
824                                                         std::string(),
825                                                         partial_path,
826                                                         prefix_path + ".",
827                                                         clang_type,
828                                                         matches,
829                                                         word_complete);
830                         }
831                     default:
832                         break;
833                 }
834             }
835             break;
836         default:
837             if (isalpha(ch) || ch == '_' || ch == '$')
838             {
839                 const size_t partial_path_len = partial_path.size();
840                 size_t pos = 1;
841                 while (pos < partial_path_len)
842                 {
843                     const char curr_ch = partial_path[pos];
844                     if (isalnum(curr_ch) || curr_ch == '_'  || curr_ch == '$')
845                     {
846                         ++pos;
847                         continue;
848                     }
849                     break;
850                 }
851 
852                 std::string token(partial_path, 0, pos);
853                 remaining_partial_path = partial_path.substr(pos);
854 
855                 if (clang_type.IsValid())
856                 {
857                     PrivateAutoCompleteMembers (frame,
858                                                 token,
859                                                 remaining_partial_path,
860                                                 prefix_path,
861                                                 clang_type,
862                                                 matches,
863                                                 word_complete);
864                 }
865                 else if (frame)
866                 {
867                     // We haven't found our variable yet
868                     const bool get_file_globals = true;
869 
870                     VariableList *variable_list = frame->GetVariableList(get_file_globals);
871 
872                     if (!variable_list)
873                         break;
874 
875                     const size_t num_variables = variable_list->GetSize();
876                     for (size_t i=0; i<num_variables; ++i)
877                     {
878                         Variable *variable = variable_list->GetVariableAtIndex(i).get();
879 
880                         if (!variable)
881                             continue;
882 
883                         const char *variable_name = variable->GetName().AsCString();
884                         if (strstr(variable_name, token.c_str()) == variable_name)
885                         {
886                             if (strcmp (variable_name, token.c_str()) == 0)
887                             {
888                                 Type *variable_type = variable->GetType();
889                                 if (variable_type)
890                                 {
891                                     CompilerType variable_clang_type (variable_type->GetForwardCompilerType ());
892                                     PrivateAutoComplete (frame,
893                                                          remaining_partial_path,
894                                                          prefix_path + token, // Anything that has been resolved already will be in here
895                                                          variable_clang_type.GetCanonicalType(),
896                                                          matches,
897                                                          word_complete);
898                                 }
899                                 else
900                                 {
901                                     matches.AppendString (prefix_path + variable_name);
902                                 }
903                             }
904                             else if (remaining_partial_path.empty())
905                             {
906                                 matches.AppendString (prefix_path + variable_name);
907                             }
908                         }
909                     }
910                 }
911             }
912             break;
913         }
914     }
915 }
916 
917 
918 
919 size_t
920 Variable::AutoComplete (const ExecutionContext &exe_ctx,
921                         const char *partial_path_cstr,
922                         StringList &matches,
923                         bool &word_complete)
924 {
925     word_complete = false;
926     std::string partial_path;
927     std::string prefix_path;
928     CompilerType clang_type;
929     if (partial_path_cstr && partial_path_cstr[0])
930         partial_path = partial_path_cstr;
931 
932     PrivateAutoComplete (exe_ctx.GetFramePtr(),
933                          partial_path,
934                          prefix_path,
935                          clang_type,
936                          matches,
937                          word_complete);
938 
939     return matches.GetSize();
940 }
941 
942