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