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