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