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