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