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