SymbolContext.cpp revision f15996eea072cdaa8a092f22d3a1212b3d95f0ec
1//===-- SymbolContext.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/SymbolContext.h" 11 12#include "lldb/Core/Module.h" 13#include "lldb/Interpreter/Args.h" 14#include "lldb/Symbol/CompileUnit.h" 15#include "lldb/Symbol/ObjectFile.h" 16#include "lldb/Symbol/Symbol.h" 17#include "lldb/Symbol/SymbolVendor.h" 18#include "lldb/Target/Target.h" 19 20using namespace lldb; 21using namespace lldb_private; 22 23SymbolContext::SymbolContext() : 24 target_sp (), 25 module_sp (), 26 comp_unit (NULL), 27 function (NULL), 28 block (NULL), 29 line_entry (), 30 symbol (NULL) 31{ 32} 33 34SymbolContext::SymbolContext(const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) : 35 target_sp (), 36 module_sp (m), 37 comp_unit (cu), 38 function (f), 39 block (b), 40 line_entry (), 41 symbol (s) 42{ 43 if (le) 44 line_entry = *le; 45} 46 47SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) : 48 target_sp (t), 49 module_sp (m), 50 comp_unit (cu), 51 function (f), 52 block (b), 53 line_entry (), 54 symbol (s) 55{ 56 if (le) 57 line_entry = *le; 58} 59 60SymbolContext::SymbolContext(const SymbolContext& rhs) : 61 target_sp (rhs.target_sp), 62 module_sp (rhs.module_sp), 63 comp_unit (rhs.comp_unit), 64 function (rhs.function), 65 block (rhs.block), 66 line_entry (rhs.line_entry), 67 symbol (rhs.symbol) 68{ 69} 70 71 72SymbolContext::SymbolContext (SymbolContextScope *sc_scope) : 73 target_sp (), 74 module_sp (), 75 comp_unit (NULL), 76 function (NULL), 77 block (NULL), 78 line_entry (), 79 symbol (NULL) 80{ 81 sc_scope->CalculateSymbolContext (this); 82} 83 84const SymbolContext& 85SymbolContext::operator= (const SymbolContext& rhs) 86{ 87 if (this != &rhs) 88 { 89 target_sp = rhs.target_sp; 90 module_sp = rhs.module_sp; 91 comp_unit = rhs.comp_unit; 92 function = rhs.function; 93 block = rhs.block; 94 line_entry = rhs.line_entry; 95 symbol = rhs.symbol; 96 } 97 return *this; 98} 99 100void 101SymbolContext::Clear() 102{ 103 target_sp.reset(); 104 module_sp.reset(); 105 comp_unit = NULL; 106 function = NULL; 107 block = NULL; 108 line_entry.Clear(); 109 symbol = NULL; 110} 111 112void 113SymbolContext::DumpStopContext 114( 115 Stream *s, 116 ExecutionContextScope *exe_scope, 117 const Address &addr, 118 bool show_fullpaths, 119 bool show_module, 120 bool show_inlined_frames 121) const 122{ 123 if (show_module && module_sp) 124 { 125 if (show_fullpaths) 126 *s << module_sp->GetFileSpec(); 127 else 128 *s << module_sp->GetFileSpec().GetFilename(); 129 s->PutChar('`'); 130 } 131 132 if (function != NULL) 133 { 134 if (function->GetMangled().GetName()) 135 function->GetMangled().GetName().Dump(s); 136 137 if (addr.IsValid()) 138 { 139 const addr_t function_offset = addr.GetOffset() - function->GetAddressRange().GetBaseAddress().GetOffset(); 140 if (function_offset) 141 s->Printf(" + %llu", function_offset); 142 } 143 144 if (block != NULL) 145 { 146 s->IndentMore(); 147 block->DumpStopContext (s, this, NULL, show_fullpaths, show_inlined_frames); 148 s->IndentLess(); 149 } 150 else 151 { 152 if (line_entry.IsValid()) 153 { 154 s->PutCString(" at "); 155 if (line_entry.DumpStopContext(s, show_fullpaths)) 156 return; 157 } 158 } 159 } 160 else if (symbol != NULL) 161 { 162 symbol->GetMangled().GetName().Dump(s); 163 164 if (addr.IsValid() && symbol->GetAddressRangePtr()) 165 { 166 const addr_t symbol_offset = addr.GetOffset() - symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(); 167 if (symbol_offset) 168 s->Printf(" + %llu", symbol_offset); 169 } 170 } 171 else if (addr.IsValid()) 172 { 173 addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress); 174 } 175} 176 177void 178SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target) const 179{ 180 if (module_sp) 181 { 182 s->Indent(" Module: file = \""); 183 module_sp->GetFileSpec().Dump(s); 184 *s << '"'; 185 if (module_sp->GetArchitecture().IsValid()) 186 s->Printf (", arch = \"%s\"", module_sp->GetArchitecture().GetArchitectureName()); 187 s->EOL(); 188 } 189 190 if (comp_unit != NULL) 191 { 192 s->Indent("CompileUnit: "); 193 comp_unit->GetDescription (s, level); 194 s->EOL(); 195 } 196 197 if (function != NULL) 198 { 199 s->Indent(" Function: "); 200 function->GetDescription (s, level, target); 201 s->EOL(); 202 203 Type *func_type = function->GetType(); 204 if (func_type) 205 { 206 s->Indent(" FuncType: "); 207 func_type->GetDescription (s, level, false); 208 s->EOL(); 209 } 210 } 211 212 if (block != NULL) 213 { 214 std::vector<Block *> blocks; 215 blocks.push_back (block); 216 Block *parent_block = block->GetParent(); 217 218 while (parent_block) 219 { 220 blocks.push_back (parent_block); 221 parent_block = parent_block->GetParent(); 222 } 223 std::vector<Block *>::reverse_iterator pos; 224 std::vector<Block *>::reverse_iterator begin = blocks.rbegin(); 225 std::vector<Block *>::reverse_iterator end = blocks.rend(); 226 for (pos = begin; pos != end; ++pos) 227 { 228 if (pos == begin) 229 s->Indent(" Blocks: "); 230 else 231 s->Indent(" "); 232 (*pos)->GetDescription(s, function, level, target); 233 s->EOL(); 234 } 235 } 236 237 if (line_entry.IsValid()) 238 { 239 s->Indent(" LineEntry: "); 240 line_entry.GetDescription (s, level, comp_unit, target, false); 241 s->EOL(); 242 } 243 244 if (symbol != NULL) 245 { 246 s->Indent(" Symbol: "); 247 symbol->GetDescription(s, level, target); 248 s->EOL(); 249 } 250} 251 252uint32_t 253SymbolContext::GetResolvedMask () const 254{ 255 uint32_t resolved_mask = 0; 256 if (target_sp) resolved_mask |= eSymbolContextTarget; 257 if (module_sp) resolved_mask |= eSymbolContextModule; 258 if (comp_unit) resolved_mask |= eSymbolContextCompUnit; 259 if (function) resolved_mask |= eSymbolContextFunction; 260 if (block) resolved_mask |= eSymbolContextBlock; 261 if (line_entry.IsValid()) resolved_mask |= eSymbolContextLineEntry; 262 if (symbol) resolved_mask |= eSymbolContextSymbol; 263 return resolved_mask; 264} 265 266 267void 268SymbolContext::Dump(Stream *s, Target *target) const 269{ 270 *s << (void *)this << ": "; 271 s->Indent(); 272 s->PutCString("SymbolContext"); 273 s->IndentMore(); 274 s->EOL(); 275 s->IndentMore(); 276 s->Indent(); 277 *s << "Module = " << (void *)module_sp.get() << ' '; 278 if (module_sp) 279 module_sp->GetFileSpec().Dump(s); 280 s->EOL(); 281 s->Indent(); 282 *s << "CompileUnit = " << (void *)comp_unit; 283 if (comp_unit != NULL) 284 *s << " {0x" << comp_unit->GetID() << "} " << *(static_cast<FileSpec*> (comp_unit)); 285 s->EOL(); 286 s->Indent(); 287 *s << "Function = " << (void *)function; 288 if (function != NULL) 289 { 290 *s << " {0x" << function->GetID() << "} " << function->GetType()->GetName() << ", address-range = "; 291 function->GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); 292 s->EOL(); 293 s->Indent(); 294 Type* func_type = function->GetType(); 295 if (func_type) 296 { 297 *s << " Type = "; 298 func_type->Dump (s, false); 299 } 300 } 301 s->EOL(); 302 s->Indent(); 303 *s << "Block = " << (void *)block; 304 if (block != NULL) 305 *s << " {0x" << block->GetID() << '}'; 306 // Dump the block and pass it a negative depth to we print all the parent blocks 307 //if (block != NULL) 308 // block->Dump(s, function->GetFileAddress(), INT_MIN); 309 s->EOL(); 310 s->Indent(); 311 *s << "LineEntry = "; 312 line_entry.Dump (s, target, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true); 313 s->EOL(); 314 s->Indent(); 315 *s << "Symbol = " << (void *)symbol; 316 if (symbol != NULL && symbol->GetMangled()) 317 *s << ' ' << symbol->GetMangled().GetName().AsCString(); 318 s->EOL(); 319 s->IndentLess(); 320 s->IndentLess(); 321} 322 323bool 324lldb_private::operator== (const SymbolContext& lhs, const SymbolContext& rhs) 325{ 326 return lhs.function == rhs.function 327 && lhs.symbol == rhs.symbol 328 && lhs.module_sp.get() == rhs.module_sp.get() 329 && lhs.comp_unit == rhs.comp_unit 330 && lhs.target_sp.get() == rhs.target_sp.get() 331 && LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0; 332} 333 334bool 335lldb_private::operator!= (const SymbolContext& lhs, const SymbolContext& rhs) 336{ 337 return lhs.function != rhs.function 338 || lhs.symbol != rhs.symbol 339 || lhs.module_sp.get() != rhs.module_sp.get() 340 || lhs.comp_unit != rhs.comp_unit 341 || lhs.target_sp.get() != rhs.target_sp.get() 342 || LineEntry::Compare(lhs.line_entry, rhs.line_entry) != 0; 343} 344 345bool 346SymbolContext::GetAddressRange (uint32_t scope, AddressRange &range) const 347{ 348 if ((scope & eSymbolContextLineEntry) && line_entry.IsValid()) 349 { 350 range = line_entry.range; 351 return true; 352 } 353 else if ((scope & eSymbolContextFunction) && function != NULL) 354 { 355 range = function->GetAddressRange(); 356 return true; 357 } 358 else if ((scope & eSymbolContextSymbol) && symbol != NULL && symbol->GetAddressRangePtr()) 359 { 360 range = *symbol->GetAddressRangePtr(); 361 362 if (range.GetByteSize() == 0) 363 { 364 if (module_sp) 365 { 366 ObjectFile *objfile = module_sp->GetObjectFile(); 367 if (objfile) 368 { 369 Symtab *symtab = objfile->GetSymtab(); 370 if (symtab) 371 range.SetByteSize(symtab->CalculateSymbolSize (symbol)); 372 } 373 } 374 } 375 return true; 376 } 377 range.Clear(); 378 return false; 379} 380 381ClangNamespaceDecl 382SymbolContext::FindNamespace (const ConstString &name) const 383{ 384 ClangNamespaceDecl namespace_decl; 385 if (module_sp) 386 namespace_decl = module_sp->GetSymbolVendor()->FindNamespace (*this, name); 387 return namespace_decl; 388} 389 390size_t 391SymbolContext::FindFunctionsByName (const ConstString &name, 392 bool include_symbols, 393 bool append, 394 SymbolContextList &sc_list) const 395{ 396 if (!append) 397 sc_list.Clear(); 398 399 if (function != NULL) 400 { 401 // FIXME: Look in the class of the current function, if it exists, 402 // for methods matching name. 403 } 404 405 if (module_sp != NULL) 406 module_sp->FindFunctions (name, eFunctionNameTypeBase | eFunctionNameTypeFull, include_symbols, true, sc_list); 407 408 if (target_sp) 409 target_sp->GetImages().FindFunctions (name, eFunctionNameTypeBase | eFunctionNameTypeFull, include_symbols, true, sc_list); 410 411 return sc_list.GetSize(); 412} 413 414//lldb::VariableSP 415//SymbolContext::FindVariableByName (const char *name) const 416//{ 417// lldb::VariableSP return_value; 418// return return_value; 419//} 420 421lldb::TypeSP 422SymbolContext::FindTypeByName (const ConstString &name) const 423{ 424 lldb::TypeSP return_value; 425 426 TypeList types; 427 428 if (module_sp && module_sp->FindTypes (*this, name, false, 1, types)) 429 return types.GetTypeAtIndex(0); 430 431 if (!return_value.get() && target_sp && target_sp->GetImages().FindTypes (*this, name, false, 1, types)) 432 return types.GetTypeAtIndex(0); 433 434 return return_value; 435} 436 437//---------------------------------------------------------------------- 438// 439// SymbolContextSpecifier 440// 441//---------------------------------------------------------------------- 442 443bool 444SymbolContextSpecifier::AddLineSpecification (uint32_t line_no, SpecificationType type) 445{ 446 bool return_value = true; 447 switch (type) 448 { 449 case eNothingSpecified: 450 Clear(); 451 break; 452 case eLineStartSpecified: 453 m_start_line = line_no; 454 m_type |= eLineStartSpecified; 455 break; 456 case eLineEndSpecified: 457 m_end_line = line_no; 458 m_type |= eLineEndSpecified; 459 break; 460 default: 461 return_value = false; 462 break; 463 } 464 return return_value; 465} 466 467bool 468SymbolContextSpecifier::AddSpecification (const char *spec_string, SpecificationType type) 469{ 470 bool return_value = true; 471 switch (type) 472 { 473 case eNothingSpecified: 474 Clear(); 475 break; 476 case eModuleSpecified: 477 { 478 // See if we can find the Module, if so stick it in the SymbolContext. 479 FileSpec module_spec(spec_string, false); 480 lldb::ModuleSP module_sp = m_target_sp->GetImages().FindFirstModuleForFileSpec (module_spec, NULL, NULL); 481 m_type |= eModuleSpecified; 482 if (module_sp) 483 m_module_sp = module_sp; 484 else 485 m_module_spec.assign (spec_string); 486 } 487 break; 488 case eFileSpecified: 489 // CompUnits can't necessarily be resolved here, since an inlined function might show up in 490 // a number of CompUnits. Instead we just convert to a FileSpec and store it away. 491 m_file_spec_ap.reset (new FileSpec (spec_string, false)); 492 m_type |= eFileSpecified; 493 break; 494 case eLineStartSpecified: 495 m_start_line = Args::StringToSInt32(spec_string, 0, 0, &return_value); 496 if (return_value) 497 m_type |= eLineStartSpecified; 498 break; 499 case eLineEndSpecified: 500 m_end_line = Args::StringToSInt32(spec_string, 0, 0, &return_value); 501 if (return_value) 502 m_type |= eLineEndSpecified; 503 break; 504 case eFunctionSpecified: 505 m_function_spec.assign(spec_string); 506 m_type |= eFunctionSpecified; 507 break; 508 case eClassOrNamespaceSpecified: 509 Clear(); 510 m_class_name.assign (spec_string); 511 m_type = eClassOrNamespaceSpecified; 512 break; 513 case eAddressRangeSpecified: 514 // Not specified yet... 515 break; 516 } 517 518 return return_value; 519} 520 521void 522SymbolContextSpecifier::Clear() 523{ 524 m_module_spec.clear(); 525 m_file_spec_ap.reset(); 526 m_function_spec.clear(); 527 m_class_name.clear(); 528 m_start_line = 0; 529 m_end_line = 0; 530 m_address_range_ap.reset(); 531 532 m_type = eNothingSpecified; 533} 534 535bool 536SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) 537{ 538 if (m_type == eNothingSpecified) 539 return true; 540 541 if (m_target_sp.get() != sc.target_sp.get()) 542 return false; 543 544 if (m_type & eModuleSpecified) 545 { 546 if (sc.module_sp) 547 { 548 if (m_module_sp.get() != NULL) 549 { 550 if (m_module_sp.get() != sc.module_sp.get()) 551 return false; 552 } 553 else 554 { 555 FileSpec module_file_spec (m_module_spec.c_str(), false); 556 if (!FileSpec::Equal (module_file_spec, sc.module_sp->GetFileSpec(), false)) 557 return false; 558 } 559 } 560 } 561 if (m_type & eFileSpecified) 562 { 563 if (m_file_spec_ap.get()) 564 { 565 // If we don't have a block or a comp_unit, then we aren't going to match a source file. 566 if (sc.block == NULL && sc.comp_unit == NULL) 567 return false; 568 569 // Check if the block is present, and if so is it inlined: 570 bool was_inlined = false; 571 if (sc.block != NULL) 572 { 573 const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo(); 574 if (inline_info != NULL) 575 { 576 was_inlined = true; 577 if (!FileSpec::Equal (inline_info->GetDeclaration().GetFile(), *(m_file_spec_ap.get()), false)) 578 return false; 579 } 580 } 581 582 // Next check the comp unit, but only if the SymbolContext was not inlined. 583 if (!was_inlined && sc.comp_unit != NULL) 584 { 585 if (!FileSpec::Equal (*(sc.comp_unit), *(m_file_spec_ap.get()), false)) 586 return false; 587 } 588 } 589 } 590 if (m_type & eLineStartSpecified 591 || m_type & eLineEndSpecified) 592 { 593 if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line) 594 return false; 595 } 596 597 if (m_type & eFunctionSpecified) 598 { 599 // First check the current block, and if it is inlined, get the inlined function name: 600 bool was_inlined = false; 601 ConstString func_name(m_function_spec.c_str()); 602 603 if (sc.block != NULL) 604 { 605 const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo(); 606 if (inline_info != NULL) 607 { 608 was_inlined = true; 609 const Mangled &name = inline_info->GetMangled(); 610 if (!name.NameMatches (func_name)) 611 return false; 612 } 613 } 614 // If it wasn't inlined, check the name in the function or symbol: 615 if (!was_inlined) 616 { 617 if (sc.function != NULL) 618 { 619 if (!sc.function->GetMangled().NameMatches(func_name)) 620 return false; 621 } 622 else if (sc.symbol != NULL) 623 { 624 if (!sc.symbol->GetMangled().NameMatches(func_name)) 625 return false; 626 } 627 } 628 629 630 } 631 632 return true; 633} 634 635bool 636SymbolContextSpecifier::AddressMatches(lldb::addr_t addr) 637{ 638 if (m_type & eAddressRangeSpecified) 639 { 640 641 } 642 else 643 { 644 Address match_address (addr, NULL); 645 SymbolContext sc; 646 m_target_sp->GetImages().ResolveSymbolContextForAddress(match_address, eSymbolContextEverything, sc); 647 return SymbolContextMatches(sc); 648 } 649 return true; 650} 651 652void 653SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level) const 654{ 655 char path_str[PATH_MAX + 1]; 656 657 if (m_type == eNothingSpecified) 658 { 659 s->Printf ("Nothing specified.\n"); 660 } 661 662 if (m_type == eModuleSpecified) 663 { 664 s->Indent(); 665 if (m_module_sp) 666 { 667 m_module_sp->GetFileSpec().GetPath (path_str, PATH_MAX); 668 s->Printf ("Module: %s\n", path_str); 669 } 670 else 671 s->Printf ("Module: %s\n", m_module_spec.c_str()); 672 } 673 674 if (m_type == eFileSpecified && m_file_spec_ap.get() != NULL) 675 { 676 m_file_spec_ap->GetPath (path_str, PATH_MAX); 677 s->Indent(); 678 s->Printf ("File: %s", path_str); 679 if (m_type == eLineStartSpecified) 680 { 681 s->Printf (" from line %d", m_start_line); 682 if (m_type == eLineEndSpecified) 683 s->Printf ("to line %d", m_end_line); 684 else 685 s->Printf ("to end", m_end_line); 686 } 687 else if (m_type == eLineEndSpecified) 688 { 689 s->Printf (" from start to line %d", m_end_line); 690 } 691 s->Printf (".\n"); 692 } 693 694 if (m_type == eLineStartSpecified) 695 { 696 s->Indent(); 697 s->Printf ("From line %d", m_start_line); 698 if (m_type == eLineEndSpecified) 699 s->Printf ("to line %d", m_end_line); 700 else 701 s->Printf ("to end", m_end_line); 702 s->Printf (".\n"); 703 } 704 else if (m_type == eLineEndSpecified) 705 { 706 s->Printf ("From start to line %d.\n", m_end_line); 707 } 708 709 if (m_type == eFunctionSpecified) 710 { 711 s->Indent(); 712 s->Printf ("Function: %s.\n", m_function_spec.c_str()); 713 } 714 715 if (m_type == eClassOrNamespaceSpecified) 716 { 717 s->Indent(); 718 s->Printf ("Class name: %s.\n", m_class_name.c_str()); 719 } 720 721 if (m_type == eAddressRangeSpecified && m_address_range_ap.get() != NULL) 722 { 723 s->Indent(); 724 s->PutCString ("Address range: "); 725 m_address_range_ap->Dump (s, m_target_sp.get(), Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); 726 s->PutCString ("\n"); 727 } 728} 729 730//---------------------------------------------------------------------- 731// 732// SymbolContextList 733// 734//---------------------------------------------------------------------- 735 736 737SymbolContextList::SymbolContextList() : 738 m_symbol_contexts() 739{ 740} 741 742SymbolContextList::~SymbolContextList() 743{ 744} 745 746void 747SymbolContextList::Append(const SymbolContext& sc) 748{ 749 m_symbol_contexts.push_back(sc); 750} 751 752bool 753SymbolContextList::AppendIfUnique (const SymbolContext& sc, bool merge_symbol_into_function) 754{ 755 collection::iterator pos, end = m_symbol_contexts.end(); 756 for (pos = m_symbol_contexts.begin(); pos != end; ++pos) 757 { 758 if (*pos == sc) 759 return false; 760 } 761 if (merge_symbol_into_function 762 && sc.symbol != NULL 763 && sc.comp_unit == NULL 764 && sc.function == NULL 765 && sc.block == NULL 766 && sc.line_entry.IsValid() == false) 767 { 768 const AddressRange *symbol_range = sc.symbol->GetAddressRangePtr(); 769 if (symbol_range) 770 { 771 for (pos = m_symbol_contexts.begin(); pos != end; ++pos) 772 { 773 if (pos->function) 774 { 775 if (pos->function->GetAddressRange().GetBaseAddress() == symbol_range->GetBaseAddress()) 776 { 777 // Do we already have a function with this symbol? 778 if (pos->symbol == sc.symbol) 779 return false; 780 if (pos->symbol == NULL) 781 { 782 pos->symbol = sc.symbol; 783 return false; 784 } 785 } 786 } 787 } 788 } 789 } 790 m_symbol_contexts.push_back(sc); 791 return true; 792} 793 794void 795SymbolContextList::Clear() 796{ 797 m_symbol_contexts.clear(); 798} 799 800void 801SymbolContextList::Dump(Stream *s, Target *target) const 802{ 803 804 *s << (void *)this << ": "; 805 s->Indent(); 806 s->PutCString("SymbolContextList"); 807 s->EOL(); 808 s->IndentMore(); 809 810 collection::const_iterator pos, end = m_symbol_contexts.end(); 811 for (pos = m_symbol_contexts.begin(); pos != end; ++pos) 812 { 813 pos->Dump(s, target); 814 } 815 s->IndentLess(); 816} 817 818bool 819SymbolContextList::GetContextAtIndex(uint32_t idx, SymbolContext& sc) const 820{ 821 if (idx < m_symbol_contexts.size()) 822 { 823 sc = m_symbol_contexts[idx]; 824 return true; 825 } 826 return false; 827} 828 829bool 830SymbolContextList::RemoveContextAtIndex (uint32_t idx) 831{ 832 if (idx < m_symbol_contexts.size()) 833 { 834 m_symbol_contexts.erase(m_symbol_contexts.begin() + idx); 835 return true; 836 } 837 return false; 838} 839 840uint32_t 841SymbolContextList::GetSize() const 842{ 843 return m_symbol_contexts.size(); 844} 845