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