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