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