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