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