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