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