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