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