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