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