Variable.cpp revision 288943
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
30using namespace lldb;
31using namespace lldb_private;
32
33//----------------------------------------------------------------------
34// Variable constructor
35//----------------------------------------------------------------------
36Variable::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//----------------------------------------------------------------------
65Variable::~Variable()
66{
67}
68
69lldb::LanguageType
70Variable::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
81ConstString
82Variable::GetName() const
83{
84    ConstString name = m_mangled.GetName(GetLanguage());
85    if (name)
86        return name;
87    return m_name;
88}
89
90bool
91Variable::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}
103bool
104Variable::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
113Type *
114Variable::GetType()
115{
116    if (m_symfile_type_sp)
117        return m_symfile_type_sp->GetType();
118    return nullptr;
119}
120
121void
122Variable::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
194bool
195Variable::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
225size_t
226Variable::MemorySize() const
227{
228    return sizeof(Variable);
229}
230
231
232void
233Variable::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
244bool
245Variable::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
274bool
275Variable::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
308bool
309Variable::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
351Error
352Variable::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
512bool
513Variable::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
557static void
558PrivateAutoComplete (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
565static void
566PrivateAutoCompleteMembers (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
574static void
575PrivateAutoCompleteMembers (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
653static void
654PrivateAutoComplete (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
917size_t
918Variable::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