Home | History | Annotate | Download | only in Symbol
      1 //===-- Variable.cpp --------------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "lldb/Symbol/Variable.h"
     11 
     12 #include "lldb/Core/Module.h"
     13 #include "lldb/Core/Stream.h"
     14 #include "lldb/Core/RegularExpression.h"
     15 #include "lldb/Core/ValueObject.h"
     16 #include "lldb/Core/ValueObjectVariable.h"
     17 #include "lldb/Symbol/Block.h"
     18 #include "lldb/Symbol/Function.h"
     19 #include "lldb/Symbol/SymbolContext.h"
     20 #include "lldb/Symbol/Type.h"
     21 #include "lldb/Symbol/VariableList.h"
     22 #include "lldb/Target/ABI.h"
     23 #include "lldb/Target/Process.h"
     24 #include "lldb/Target/RegisterContext.h"
     25 #include "lldb/Target/StackFrame.h"
     26 #include "lldb/Target/Thread.h"
     27 #include "lldb/Target/Target.h"
     28 
     29 using namespace lldb;
     30 using namespace lldb_private;
     31 
     32 //----------------------------------------------------------------------
     33 // Variable constructor
     34 //----------------------------------------------------------------------
     35 Variable::Variable
     36 (
     37     lldb::user_id_t uid,
     38     const char *name,
     39     const char *mangled,   // The mangled variable name for variables in namespaces
     40     const lldb::SymbolFileTypeSP &symfile_type_sp,
     41     ValueType scope,
     42     SymbolContextScope *context,
     43     Declaration* decl_ptr,
     44     const DWARFExpression& location,
     45     bool external,
     46     bool artificial
     47 ) :
     48     UserID(uid),
     49     m_name(name),
     50     m_mangled (ConstString(mangled), true),
     51     m_symfile_type_sp(symfile_type_sp),
     52     m_scope(scope),
     53     m_owner_scope(context),
     54     m_declaration(decl_ptr),
     55     m_location(location),
     56     m_external(external),
     57     m_artificial(artificial)
     58 {
     59 }
     60 
     61 //----------------------------------------------------------------------
     62 // Destructor
     63 //----------------------------------------------------------------------
     64 Variable::~Variable()
     65 {
     66 }
     67 
     68 
     69 const ConstString&
     70 Variable::GetName() const
     71 {
     72     if (m_mangled)
     73         return m_mangled.GetName();
     74     return m_name;
     75 }
     76 
     77 bool
     78 Variable::NameMatches (const RegularExpression& regex) const
     79 {
     80     if (regex.Execute (m_name.AsCString()))
     81         return true;
     82     return m_mangled.NameMatches (regex);
     83 }
     84 
     85 Type *
     86 Variable::GetType()
     87 {
     88     if (m_symfile_type_sp)
     89         return m_symfile_type_sp->GetType();
     90     return NULL;
     91 }
     92 
     93 void
     94 Variable::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 
    166 bool
    167 Variable::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 
    193 size_t
    194 Variable::MemorySize() const
    195 {
    196     return sizeof(Variable);
    197 }
    198 
    199 
    200 void
    201 Variable::CalculateSymbolContext (SymbolContext *sc)
    202 {
    203     if (m_owner_scope)
    204         m_owner_scope->CalculateSymbolContext(sc);
    205     else
    206         sc->Clear(false);
    207 }
    208 
    209 bool
    210 Variable::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 
    239 bool
    240 Variable::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 
    273 bool
    274 Variable::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 
    316 Error
    317 Variable::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 
    477 bool
    478 Variable::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 
    522 static void
    523 PrivateAutoComplete (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 
    530 static void
    531 PrivateAutoCompleteMembers (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 
    539 static void
    540 PrivateAutoCompleteMembers (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 
    618 static void
    619 PrivateAutoComplete (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                 const size_t num_variables = variable_list->GetSize();
    688                 for (size_t i=0; i<num_variables; ++i)
    689                 {
    690                     Variable *variable = variable_list->GetVariableAtIndex(i).get();
    691                     matches.AppendString (variable->GetName().AsCString());
    692                 }
    693             }
    694         }
    695     }
    696     else
    697     {
    698         const char ch = partial_path[0];
    699         switch (ch)
    700         {
    701         case '*':
    702             if (prefix_path.empty())
    703             {
    704                 PrivateAutoComplete (frame,
    705                                      partial_path.substr(1),
    706                                      std::string("*"),
    707                                      clang_type,
    708                                      matches,
    709                                      word_complete);
    710             }
    711             break;
    712 
    713         case '&':
    714             if (prefix_path.empty())
    715             {
    716                 PrivateAutoComplete (frame,
    717                                      partial_path.substr(1),
    718                                      std::string("&"),
    719                                      clang_type,
    720                                      matches,
    721                                      word_complete);
    722             }
    723             break;
    724 
    725         case '-':
    726             if (partial_path[1] == '>' && !prefix_path.empty())
    727             {
    728                 switch (type_class)
    729                 {
    730                     case lldb::eTypeClassPointer:
    731                         {
    732                             ClangASTType pointee_type(clang_type.GetPointeeType());
    733                             if (partial_path[2])
    734                             {
    735                                 // If there is more after the "->", then search deeper
    736                                 PrivateAutoComplete (frame,
    737                                                      partial_path.substr(2),
    738                                                      prefix_path + "->",
    739                                                      pointee_type.GetCanonicalType(),
    740                                                      matches,
    741                                                      word_complete);
    742                             }
    743                             else
    744                             {
    745                                 // Nothing after the "->", so list all members
    746                                 PrivateAutoCompleteMembers (frame,
    747                                                             std::string(),
    748                                                             std::string(),
    749                                                             prefix_path + "->",
    750                                                             pointee_type.GetCanonicalType(),
    751                                                             matches,
    752                                                             word_complete);
    753                             }
    754                         }
    755                     default:
    756                         break;
    757                 }
    758             }
    759             break;
    760 
    761         case '.':
    762             if (clang_type.IsValid())
    763             {
    764                 switch (type_class)
    765                 {
    766                     case lldb::eTypeClassUnion:
    767                     case lldb::eTypeClassStruct:
    768                     case lldb::eTypeClassClass:
    769                         if (partial_path[1])
    770                         {
    771                             // If there is more after the ".", then search deeper
    772                             PrivateAutoComplete (frame,
    773                                                  partial_path.substr(1),
    774                                                  prefix_path + ".",
    775                                                  clang_type,
    776                                                  matches,
    777                                                  word_complete);
    778 
    779                         }
    780                         else
    781                         {
    782                             // Nothing after the ".", so list all members
    783                             PrivateAutoCompleteMembers (frame,
    784                                                         std::string(),
    785                                                         partial_path,
    786                                                         prefix_path + ".",
    787                                                         clang_type,
    788                                                         matches,
    789                                                         word_complete);
    790                         }
    791                     default:
    792                         break;
    793                 }
    794             }
    795             break;
    796         default:
    797             if (isalpha(ch) || ch == '_' || ch == '$')
    798             {
    799                 const size_t partial_path_len = partial_path.size();
    800                 size_t pos = 1;
    801                 while (pos < partial_path_len)
    802                 {
    803                     const char curr_ch = partial_path[pos];
    804                     if (isalnum(curr_ch) || curr_ch == '_'  || curr_ch == '$')
    805                     {
    806                         ++pos;
    807                         continue;
    808                     }
    809                     break;
    810                 }
    811 
    812                 std::string token(partial_path, 0, pos);
    813                 remaining_partial_path = partial_path.substr(pos);
    814 
    815                 if (clang_type.IsValid())
    816                 {
    817                     PrivateAutoCompleteMembers (frame,
    818                                                 token,
    819                                                 remaining_partial_path,
    820                                                 prefix_path,
    821                                                 clang_type,
    822                                                 matches,
    823                                                 word_complete);
    824                 }
    825                 else if (frame)
    826                 {
    827                     // We haven't found our variable yet
    828                     const bool get_file_globals = true;
    829 
    830                     VariableList *variable_list = frame->GetVariableList(get_file_globals);
    831 
    832                     const size_t num_variables = variable_list->GetSize();
    833                     for (size_t i=0; i<num_variables; ++i)
    834                     {
    835                         Variable *variable = variable_list->GetVariableAtIndex(i).get();
    836                         const char *variable_name = variable->GetName().AsCString();
    837                         if (strstr(variable_name, token.c_str()) == variable_name)
    838                         {
    839                             if (strcmp (variable_name, token.c_str()) == 0)
    840                             {
    841                                 Type *variable_type = variable->GetType();
    842                                 if (variable_type)
    843                                 {
    844                                     ClangASTType variable_clang_type (variable_type->GetClangForwardType());
    845                                     PrivateAutoComplete (frame,
    846                                                          remaining_partial_path,
    847                                                          prefix_path + token, // Anything that has been resolved already will be in here
    848                                                          variable_clang_type.GetCanonicalType(),
    849                                                          matches,
    850                                                          word_complete);
    851                                 }
    852                                 else
    853                                 {
    854                                     matches.AppendString (prefix_path + variable_name);
    855                                 }
    856                             }
    857                             else if (remaining_partial_path.empty())
    858                             {
    859                                 matches.AppendString (prefix_path + variable_name);
    860                             }
    861                         }
    862                     }
    863                 }
    864             }
    865             break;
    866         }
    867     }
    868 }
    869 
    870 
    871 
    872 size_t
    873 Variable::AutoComplete (const ExecutionContext &exe_ctx,
    874                         const char *partial_path_cstr,
    875                         StringList &matches,
    876                         bool &word_complete)
    877 {
    878     word_complete = false;
    879     std::string partial_path;
    880     std::string prefix_path;
    881     ClangASTType clang_type;
    882     if (partial_path_cstr && partial_path_cstr[0])
    883         partial_path = partial_path_cstr;
    884 
    885     PrivateAutoComplete (exe_ctx.GetFramePtr(),
    886                          partial_path,
    887                          prefix_path,
    888                          clang_type,
    889                          matches,
    890                          word_complete);
    891 
    892     return matches.GetSize();
    893 }
    894 
    895