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