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