1 //===-- SBType.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/API/SBDefines.h" 11 #include "lldb/API/SBType.h" 12 #include "lldb/API/SBTypeEnumMember.h" 13 #include "lldb/API/SBStream.h" 14 #include "lldb/Core/ConstString.h" 15 #include "lldb/Core/Log.h" 16 #include "lldb/Core/Stream.h" 17 #include "lldb/Symbol/ClangASTContext.h" 18 #include "lldb/Symbol/ClangASTType.h" 19 #include "lldb/Symbol/Type.h" 20 21 #include "clang/AST/Decl.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 using namespace clang; 26 27 SBType::SBType() : 28 m_opaque_sp() 29 { 30 } 31 32 SBType::SBType (const ClangASTType &type) : 33 m_opaque_sp(new TypeImpl(ClangASTType(type.GetASTContext(), 34 type.GetOpaqueQualType()))) 35 { 36 } 37 38 SBType::SBType (const lldb::TypeSP &type_sp) : 39 m_opaque_sp(new TypeImpl(type_sp)) 40 { 41 } 42 43 SBType::SBType (const lldb::TypeImplSP &type_impl_sp) : 44 m_opaque_sp(type_impl_sp) 45 { 46 } 47 48 49 SBType::SBType (const SBType &rhs) : 50 m_opaque_sp() 51 { 52 if (this != &rhs) 53 { 54 m_opaque_sp = rhs.m_opaque_sp; 55 } 56 } 57 58 59 //SBType::SBType (TypeImpl* impl) : 60 // m_opaque_ap(impl) 61 //{} 62 // 63 bool 64 SBType::operator == (SBType &rhs) 65 { 66 if (IsValid() == false) 67 return !rhs.IsValid(); 68 69 if (rhs.IsValid() == false) 70 return false; 71 72 return *m_opaque_sp.get() == *rhs.m_opaque_sp.get(); 73 } 74 75 bool 76 SBType::operator != (SBType &rhs) 77 { 78 if (IsValid() == false) 79 return rhs.IsValid(); 80 81 if (rhs.IsValid() == false) 82 return true; 83 84 return *m_opaque_sp.get() != *rhs.m_opaque_sp.get(); 85 } 86 87 lldb::TypeImplSP 88 SBType::GetSP () 89 { 90 return m_opaque_sp; 91 } 92 93 94 void 95 SBType::SetSP (const lldb::TypeImplSP &type_impl_sp) 96 { 97 m_opaque_sp = type_impl_sp; 98 } 99 100 SBType & 101 SBType::operator = (const SBType &rhs) 102 { 103 if (this != &rhs) 104 { 105 m_opaque_sp = rhs.m_opaque_sp; 106 } 107 return *this; 108 } 109 110 SBType::~SBType () 111 {} 112 113 TypeImpl & 114 SBType::ref () 115 { 116 if (m_opaque_sp.get() == NULL) 117 m_opaque_sp.reset (new TypeImpl()); 118 return *m_opaque_sp; 119 } 120 121 const TypeImpl & 122 SBType::ref () const 123 { 124 // "const SBAddress &addr" should already have checked "addr.IsValid()" 125 // prior to calling this function. In case you didn't we will assert 126 // and die to let you know. 127 assert (m_opaque_sp.get()); 128 return *m_opaque_sp; 129 } 130 131 bool 132 SBType::IsValid() const 133 { 134 if (m_opaque_sp.get() == NULL) 135 return false; 136 137 return m_opaque_sp->IsValid(); 138 } 139 140 uint64_t 141 SBType::GetByteSize() 142 { 143 if (!IsValid()) 144 return 0; 145 146 return m_opaque_sp->GetClangASTType(false).GetByteSize(); 147 148 } 149 150 bool 151 SBType::IsPointerType() 152 { 153 if (!IsValid()) 154 return false; 155 return m_opaque_sp->GetClangASTType(true).IsPointerType(); 156 } 157 158 bool 159 SBType::IsArrayType() 160 { 161 if (!IsValid()) 162 return false; 163 return m_opaque_sp->GetClangASTType(true).IsArrayType(nullptr, nullptr, nullptr); 164 } 165 166 bool 167 SBType::IsReferenceType() 168 { 169 if (!IsValid()) 170 return false; 171 return m_opaque_sp->GetClangASTType(true).IsReferenceType(); 172 } 173 174 SBType 175 SBType::GetPointerType() 176 { 177 if (!IsValid()) 178 return SBType(); 179 180 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetPointerType()))); 181 } 182 183 SBType 184 SBType::GetPointeeType() 185 { 186 if (!IsValid()) 187 return SBType(); 188 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetPointeeType()))); 189 } 190 191 SBType 192 SBType::GetReferenceType() 193 { 194 if (!IsValid()) 195 return SBType(); 196 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetReferenceType()))); 197 } 198 199 SBType 200 SBType::GetTypedefedType() 201 { 202 if (!IsValid()) 203 return SBType(); 204 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetTypedefedType()))); 205 } 206 207 SBType 208 SBType::GetDereferencedType() 209 { 210 if (!IsValid()) 211 return SBType(); 212 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetDereferencedType()))); 213 } 214 215 SBType 216 SBType::GetArrayElementType() 217 { 218 if (!IsValid()) 219 return SBType(); 220 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetClangASTType(true).GetArrayElementType()))); 221 } 222 223 bool 224 SBType::IsFunctionType () 225 { 226 if (!IsValid()) 227 return false; 228 return m_opaque_sp->GetClangASTType(true).IsFunctionType(); 229 } 230 231 bool 232 SBType::IsPolymorphicClass () 233 { 234 if (!IsValid()) 235 return false; 236 return m_opaque_sp->GetClangASTType(true).IsPolymorphicClass(); 237 } 238 239 bool 240 SBType::IsTypedefType () 241 { 242 if (!IsValid()) 243 return false; 244 return m_opaque_sp->GetClangASTType(true).IsTypedefType(); 245 } 246 247 lldb::SBType 248 SBType::GetFunctionReturnType () 249 { 250 if (IsValid()) 251 { 252 ClangASTType return_clang_type (m_opaque_sp->GetClangASTType(true).GetFunctionReturnType()); 253 if (return_clang_type.IsValid()) 254 return SBType(return_clang_type); 255 } 256 return lldb::SBType(); 257 } 258 259 lldb::SBTypeList 260 SBType::GetFunctionArgumentTypes () 261 { 262 SBTypeList sb_type_list; 263 if (IsValid()) 264 { 265 ClangASTType func_type(m_opaque_sp->GetClangASTType(true)); 266 size_t count = func_type.GetNumberOfFunctionArguments(); 267 for (size_t i = 0; 268 i < count; 269 i++) 270 { 271 sb_type_list.Append(SBType(func_type.GetFunctionArgumentAtIndex(i))); 272 } 273 } 274 return sb_type_list; 275 } 276 277 uint32_t 278 SBType::GetNumberOfMemberFunctions () 279 { 280 if (IsValid()) 281 { 282 return m_opaque_sp->GetClangASTType(true).GetNumMemberFunctions(); 283 } 284 return 0; 285 } 286 287 lldb::SBTypeMemberFunction 288 SBType::GetMemberFunctionAtIndex (uint32_t idx) 289 { 290 SBTypeMemberFunction sb_func_type; 291 if (IsValid()) 292 sb_func_type.reset(new TypeMemberFunctionImpl(m_opaque_sp->GetClangASTType(true).GetMemberFunctionAtIndex(idx))); 293 return sb_func_type; 294 } 295 296 lldb::SBType 297 SBType::GetUnqualifiedType() 298 { 299 if (!IsValid()) 300 return SBType(); 301 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetUnqualifiedType()))); 302 } 303 304 lldb::SBType 305 SBType::GetCanonicalType() 306 { 307 if (IsValid()) 308 return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetCanonicalType()))); 309 return SBType(); 310 } 311 312 313 lldb::BasicType 314 SBType::GetBasicType() 315 { 316 if (IsValid()) 317 return m_opaque_sp->GetClangASTType(false).GetBasicTypeEnumeration (); 318 return eBasicTypeInvalid; 319 } 320 321 SBType 322 SBType::GetBasicType(lldb::BasicType basic_type) 323 { 324 if (IsValid()) 325 return SBType (ClangASTContext::GetBasicType (m_opaque_sp->GetClangASTContext(false), basic_type)); 326 return SBType(); 327 } 328 329 uint32_t 330 SBType::GetNumberOfDirectBaseClasses () 331 { 332 if (IsValid()) 333 return m_opaque_sp->GetClangASTType(true).GetNumDirectBaseClasses(); 334 return 0; 335 } 336 337 uint32_t 338 SBType::GetNumberOfVirtualBaseClasses () 339 { 340 if (IsValid()) 341 return m_opaque_sp->GetClangASTType(true).GetNumVirtualBaseClasses(); 342 return 0; 343 } 344 345 uint32_t 346 SBType::GetNumberOfFields () 347 { 348 if (IsValid()) 349 return m_opaque_sp->GetClangASTType(true).GetNumFields(); 350 return 0; 351 } 352 353 bool 354 SBType::GetDescription (SBStream &description, lldb::DescriptionLevel description_level) 355 { 356 Stream &strm = description.ref(); 357 358 if (m_opaque_sp) 359 { 360 m_opaque_sp->GetDescription (strm, description_level); 361 } 362 else 363 strm.PutCString ("No value"); 364 365 return true; 366 } 367 368 369 370 SBTypeMember 371 SBType::GetDirectBaseClassAtIndex (uint32_t idx) 372 { 373 SBTypeMember sb_type_member; 374 if (IsValid()) 375 { 376 ClangASTType this_type (m_opaque_sp->GetClangASTType (true)); 377 if (this_type.IsValid()) 378 { 379 uint32_t bit_offset = 0; 380 ClangASTType base_class_type (this_type.GetDirectBaseClassAtIndex(idx, &bit_offset)); 381 if (base_class_type.IsValid()) 382 { 383 sb_type_member.reset (new TypeMemberImpl (TypeImplSP(new TypeImpl(base_class_type)), bit_offset)); 384 } 385 } 386 } 387 return sb_type_member; 388 389 } 390 391 SBTypeMember 392 SBType::GetVirtualBaseClassAtIndex (uint32_t idx) 393 { 394 SBTypeMember sb_type_member; 395 if (IsValid()) 396 { 397 ClangASTType this_type (m_opaque_sp->GetClangASTType (true)); 398 if (this_type.IsValid()) 399 { 400 uint32_t bit_offset = 0; 401 ClangASTType base_class_type (this_type.GetVirtualBaseClassAtIndex(idx, &bit_offset)); 402 if (base_class_type.IsValid()) 403 { 404 sb_type_member.reset (new TypeMemberImpl (TypeImplSP(new TypeImpl(base_class_type)), bit_offset)); 405 } 406 } 407 } 408 return sb_type_member; 409 } 410 411 SBTypeEnumMemberList 412 SBType::GetEnumMembers () 413 { 414 SBTypeEnumMemberList sb_enum_member_list; 415 if (IsValid()) 416 { 417 const clang::EnumDecl *enum_decl = m_opaque_sp->GetClangASTType(true).GetFullyUnqualifiedType().GetAsEnumDecl(); 418 if (enum_decl) 419 { 420 clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; 421 for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) 422 { 423 SBTypeEnumMember enum_member; 424 enum_member.reset(new TypeEnumMemberImpl(*enum_pos, ClangASTType(m_opaque_sp->GetClangASTContext(true), enum_decl->getIntegerType()))); 425 sb_enum_member_list.Append(enum_member); 426 } 427 } 428 } 429 return sb_enum_member_list; 430 } 431 432 SBTypeMember 433 SBType::GetFieldAtIndex (uint32_t idx) 434 { 435 SBTypeMember sb_type_member; 436 if (IsValid()) 437 { 438 ClangASTType this_type (m_opaque_sp->GetClangASTType (false)); 439 if (this_type.IsValid()) 440 { 441 uint64_t bit_offset = 0; 442 uint32_t bitfield_bit_size = 0; 443 bool is_bitfield = false; 444 std::string name_sstr; 445 ClangASTType field_type (this_type.GetFieldAtIndex (idx, 446 name_sstr, 447 &bit_offset, 448 &bitfield_bit_size, 449 &is_bitfield)); 450 if (field_type.IsValid()) 451 { 452 ConstString name; 453 if (!name_sstr.empty()) 454 name.SetCString(name_sstr.c_str()); 455 sb_type_member.reset (new TypeMemberImpl (TypeImplSP (new TypeImpl(field_type)), 456 bit_offset, 457 name, 458 bitfield_bit_size, 459 is_bitfield)); 460 } 461 } 462 } 463 return sb_type_member; 464 } 465 466 bool 467 SBType::IsTypeComplete() 468 { 469 if (!IsValid()) 470 return false; 471 return m_opaque_sp->GetClangASTType(false).IsCompleteType(); 472 } 473 474 uint32_t 475 SBType::GetTypeFlags () 476 { 477 if (!IsValid()) 478 return 0; 479 return m_opaque_sp->GetClangASTType(true).GetTypeInfo(); 480 } 481 482 const char* 483 SBType::GetName() 484 { 485 if (!IsValid()) 486 return ""; 487 return m_opaque_sp->GetName().GetCString(); 488 } 489 490 const char * 491 SBType::GetDisplayTypeName () 492 { 493 if (!IsValid()) 494 return ""; 495 return m_opaque_sp->GetDisplayTypeName().GetCString(); 496 } 497 498 lldb::TypeClass 499 SBType::GetTypeClass () 500 { 501 if (IsValid()) 502 return m_opaque_sp->GetClangASTType(true).GetTypeClass(); 503 return lldb::eTypeClassInvalid; 504 } 505 506 uint32_t 507 SBType::GetNumberOfTemplateArguments () 508 { 509 if (IsValid()) 510 return m_opaque_sp->GetClangASTType(false).GetNumTemplateArguments(); 511 return 0; 512 } 513 514 lldb::SBType 515 SBType::GetTemplateArgumentType (uint32_t idx) 516 { 517 if (IsValid()) 518 { 519 TemplateArgumentKind kind = eTemplateArgumentKindNull; 520 ClangASTType template_arg_type = m_opaque_sp->GetClangASTType(false).GetTemplateArgument (idx, kind); 521 if (template_arg_type.IsValid()) 522 return SBType(template_arg_type); 523 } 524 return SBType(); 525 } 526 527 528 lldb::TemplateArgumentKind 529 SBType::GetTemplateArgumentKind (uint32_t idx) 530 { 531 TemplateArgumentKind kind = eTemplateArgumentKindNull; 532 if (IsValid()) 533 m_opaque_sp->GetClangASTType(false).GetTemplateArgument (idx, kind); 534 return kind; 535 } 536 537 538 SBTypeList::SBTypeList() : 539 m_opaque_ap(new TypeListImpl()) 540 { 541 } 542 543 SBTypeList::SBTypeList(const SBTypeList& rhs) : 544 m_opaque_ap(new TypeListImpl()) 545 { 546 for (uint32_t i = 0, rhs_size = const_cast<SBTypeList&>(rhs).GetSize(); i < rhs_size; i++) 547 Append(const_cast<SBTypeList&>(rhs).GetTypeAtIndex(i)); 548 } 549 550 bool 551 SBTypeList::IsValid () 552 { 553 return (m_opaque_ap.get() != NULL); 554 } 555 556 SBTypeList& 557 SBTypeList::operator = (const SBTypeList& rhs) 558 { 559 if (this != &rhs) 560 { 561 m_opaque_ap.reset (new TypeListImpl()); 562 for (uint32_t i = 0, rhs_size = const_cast<SBTypeList&>(rhs).GetSize(); i < rhs_size; i++) 563 Append(const_cast<SBTypeList&>(rhs).GetTypeAtIndex(i)); 564 } 565 return *this; 566 } 567 568 void 569 SBTypeList::Append (SBType type) 570 { 571 if (type.IsValid()) 572 m_opaque_ap->Append (type.m_opaque_sp); 573 } 574 575 SBType 576 SBTypeList::GetTypeAtIndex(uint32_t index) 577 { 578 if (m_opaque_ap.get()) 579 return SBType(m_opaque_ap->GetTypeAtIndex(index)); 580 return SBType(); 581 } 582 583 uint32_t 584 SBTypeList::GetSize() 585 { 586 return m_opaque_ap->GetSize(); 587 } 588 589 SBTypeList::~SBTypeList() 590 { 591 } 592 593 SBTypeMember::SBTypeMember() : 594 m_opaque_ap() 595 { 596 } 597 598 SBTypeMember::~SBTypeMember() 599 { 600 } 601 602 SBTypeMember::SBTypeMember (const SBTypeMember& rhs) : 603 m_opaque_ap() 604 { 605 if (this != &rhs) 606 { 607 if (rhs.IsValid()) 608 m_opaque_ap.reset(new TypeMemberImpl(rhs.ref())); 609 } 610 } 611 612 lldb::SBTypeMember& 613 SBTypeMember::operator = (const lldb::SBTypeMember& rhs) 614 { 615 if (this != &rhs) 616 { 617 if (rhs.IsValid()) 618 m_opaque_ap.reset(new TypeMemberImpl(rhs.ref())); 619 } 620 return *this; 621 } 622 623 bool 624 SBTypeMember::IsValid() const 625 { 626 return m_opaque_ap.get(); 627 } 628 629 const char * 630 SBTypeMember::GetName () 631 { 632 if (m_opaque_ap.get()) 633 return m_opaque_ap->GetName().GetCString(); 634 return NULL; 635 } 636 637 SBType 638 SBTypeMember::GetType () 639 { 640 SBType sb_type; 641 if (m_opaque_ap.get()) 642 { 643 sb_type.SetSP (m_opaque_ap->GetTypeImpl()); 644 } 645 return sb_type; 646 647 } 648 649 uint64_t 650 SBTypeMember::GetOffsetInBytes() 651 { 652 if (m_opaque_ap.get()) 653 return m_opaque_ap->GetBitOffset() / 8u; 654 return 0; 655 } 656 657 uint64_t 658 SBTypeMember::GetOffsetInBits() 659 { 660 if (m_opaque_ap.get()) 661 return m_opaque_ap->GetBitOffset(); 662 return 0; 663 } 664 665 bool 666 SBTypeMember::IsBitfield() 667 { 668 if (m_opaque_ap.get()) 669 return m_opaque_ap->GetIsBitfield(); 670 return false; 671 } 672 673 uint32_t 674 SBTypeMember::GetBitfieldSizeInBits() 675 { 676 if (m_opaque_ap.get()) 677 return m_opaque_ap->GetBitfieldBitSize(); 678 return 0; 679 } 680 681 682 bool 683 SBTypeMember::GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level) 684 { 685 Stream &strm = description.ref(); 686 687 if (m_opaque_ap.get()) 688 { 689 const uint32_t bit_offset = m_opaque_ap->GetBitOffset(); 690 const uint32_t byte_offset = bit_offset / 8u; 691 const uint32_t byte_bit_offset = bit_offset % 8u; 692 const char *name = m_opaque_ap->GetName().GetCString(); 693 if (byte_bit_offset) 694 strm.Printf ("+%u + %u bits: (", byte_offset, byte_bit_offset); 695 else 696 strm.Printf ("+%u: (", byte_offset); 697 698 TypeImplSP type_impl_sp (m_opaque_ap->GetTypeImpl()); 699 if (type_impl_sp) 700 type_impl_sp->GetDescription(strm, description_level); 701 702 strm.Printf (") %s", name); 703 if (m_opaque_ap->GetIsBitfield()) 704 { 705 const uint32_t bitfield_bit_size = m_opaque_ap->GetBitfieldBitSize(); 706 strm.Printf (" : %u", bitfield_bit_size); 707 } 708 } 709 else 710 { 711 strm.PutCString ("No value"); 712 } 713 return true; 714 } 715 716 717 void 718 SBTypeMember::reset(TypeMemberImpl *type_member_impl) 719 { 720 m_opaque_ap.reset(type_member_impl); 721 } 722 723 TypeMemberImpl & 724 SBTypeMember::ref () 725 { 726 if (m_opaque_ap.get() == NULL) 727 m_opaque_ap.reset (new TypeMemberImpl()); 728 return *m_opaque_ap.get(); 729 } 730 731 const TypeMemberImpl & 732 SBTypeMember::ref () const 733 { 734 return *m_opaque_ap.get(); 735 } 736 737 SBTypeMemberFunction::SBTypeMemberFunction() : 738 m_opaque_sp() 739 { 740 } 741 742 SBTypeMemberFunction::~SBTypeMemberFunction() 743 { 744 } 745 746 SBTypeMemberFunction::SBTypeMemberFunction (const SBTypeMemberFunction& rhs) : 747 m_opaque_sp(rhs.m_opaque_sp) 748 { 749 } 750 751 lldb::SBTypeMemberFunction& 752 SBTypeMemberFunction::operator = (const lldb::SBTypeMemberFunction& rhs) 753 { 754 if (this != &rhs) 755 m_opaque_sp = rhs.m_opaque_sp; 756 return *this; 757 } 758 759 bool 760 SBTypeMemberFunction::IsValid() const 761 { 762 return m_opaque_sp.get(); 763 } 764 765 const char * 766 SBTypeMemberFunction::GetName () 767 { 768 if (m_opaque_sp) 769 return m_opaque_sp->GetName().GetCString(); 770 return NULL; 771 } 772 773 SBType 774 SBTypeMemberFunction::GetType () 775 { 776 SBType sb_type; 777 if (m_opaque_sp) 778 { 779 sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetType()))); 780 } 781 return sb_type; 782 } 783 784 lldb::SBType 785 SBTypeMemberFunction::GetReturnType () 786 { 787 SBType sb_type; 788 if (m_opaque_sp) 789 { 790 sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetReturnType()))); 791 } 792 return sb_type; 793 } 794 795 uint32_t 796 SBTypeMemberFunction::GetNumberOfArguments () 797 { 798 if (m_opaque_sp) 799 return m_opaque_sp->GetNumArguments(); 800 return 0; 801 } 802 803 lldb::SBType 804 SBTypeMemberFunction::GetArgumentTypeAtIndex (uint32_t i) 805 { 806 SBType sb_type; 807 if (m_opaque_sp) 808 { 809 sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetArgumentAtIndex(i)))); 810 } 811 return sb_type; 812 } 813 814 lldb::MemberFunctionKind 815 SBTypeMemberFunction::GetKind () 816 { 817 if (m_opaque_sp) 818 return m_opaque_sp->GetKind(); 819 return lldb::eMemberFunctionKindUnknown; 820 821 } 822 823 bool 824 SBTypeMemberFunction::GetDescription (lldb::SBStream &description, 825 lldb::DescriptionLevel description_level) 826 { 827 Stream &strm = description.ref(); 828 829 if (m_opaque_sp) 830 return m_opaque_sp->GetDescription(strm); 831 832 return false; 833 } 834 835 void 836 SBTypeMemberFunction::reset(TypeMemberFunctionImpl *type_member_impl) 837 { 838 m_opaque_sp.reset(type_member_impl); 839 } 840 841 TypeMemberFunctionImpl & 842 SBTypeMemberFunction::ref () 843 { 844 if (!m_opaque_sp) 845 m_opaque_sp.reset (new TypeMemberFunctionImpl()); 846 return *m_opaque_sp.get(); 847 } 848 849 const TypeMemberFunctionImpl & 850 SBTypeMemberFunction::ref () const 851 { 852 return *m_opaque_sp.get(); 853 } 854