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