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