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