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