1254721Semaste//===-- Block.cpp -----------------------------------------------*- C++ -*-===// 2254721Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6254721Semaste// 7254721Semaste//===----------------------------------------------------------------------===// 8254721Semaste 9254721Semaste#include "lldb/Symbol/Block.h" 10254721Semaste 11254721Semaste#include "lldb/Core/Module.h" 12254721Semaste#include "lldb/Core/Section.h" 13254721Semaste#include "lldb/Symbol/Function.h" 14254721Semaste#include "lldb/Symbol/SymbolFile.h" 15254721Semaste#include "lldb/Symbol/VariableList.h" 16321369Sdim#include "lldb/Utility/Log.h" 17254721Semaste 18353358Sdim#include <memory> 19353358Sdim 20254721Semasteusing namespace lldb; 21254721Semasteusing namespace lldb_private; 22254721Semaste 23314564SdimBlock::Block(lldb::user_id_t uid) 24314564Sdim : UserID(uid), m_parent_scope(nullptr), m_children(), m_ranges(), 25314564Sdim m_inlineInfoSP(), m_variable_list_sp(), m_parsed_block_info(false), 26314564Sdim m_parsed_block_variables(false), m_parsed_child_blocks(false) {} 27254721Semaste 28314564SdimBlock::~Block() {} 29254721Semaste 30314564Sdimvoid Block::GetDescription(Stream *s, Function *function, 31314564Sdim lldb::DescriptionLevel level, Target *target) const { 32314564Sdim *s << "id = " << ((const UserID &)*this); 33254721Semaste 34314564Sdim size_t num_ranges = m_ranges.GetSize(); 35314564Sdim if (num_ranges > 0) { 36254721Semaste 37314564Sdim addr_t base_addr = LLDB_INVALID_ADDRESS; 38314564Sdim if (target) 39314564Sdim base_addr = 40314564Sdim function->GetAddressRange().GetBaseAddress().GetLoadAddress(target); 41314564Sdim if (base_addr == LLDB_INVALID_ADDRESS) 42314564Sdim base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress(); 43314564Sdim 44314564Sdim s->Printf(", range%s = ", num_ranges > 1 ? "s" : ""); 45314564Sdim for (size_t i = 0; i < num_ranges; ++i) { 46314564Sdim const Range &range = m_ranges.GetEntryRef(i); 47360784Sdim DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(), 48360784Sdim base_addr + range.GetRangeEnd(), 4); 49254721Semaste } 50314564Sdim } 51254721Semaste 52314564Sdim if (m_inlineInfoSP.get() != nullptr) { 53314564Sdim bool show_fullpaths = (level == eDescriptionLevelVerbose); 54314564Sdim m_inlineInfoSP->Dump(s, show_fullpaths); 55314564Sdim } 56254721Semaste} 57254721Semaste 58314564Sdimvoid Block::Dump(Stream *s, addr_t base_addr, int32_t depth, 59314564Sdim bool show_context) const { 60314564Sdim if (depth < 0) { 61314564Sdim Block *parent = GetParent(); 62314564Sdim if (parent) { 63341825Sdim // We have a depth that is less than zero, print our parent blocks first 64314564Sdim parent->Dump(s, base_addr, depth + 1, show_context); 65254721Semaste } 66314564Sdim } 67254721Semaste 68314564Sdim s->Printf("%p: ", static_cast<const void *>(this)); 69314564Sdim s->Indent(); 70314564Sdim *s << "Block" << static_cast<const UserID &>(*this); 71314564Sdim const Block *parent_block = GetParent(); 72314564Sdim if (parent_block) { 73314564Sdim s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID()); 74314564Sdim } 75314564Sdim if (m_inlineInfoSP.get() != nullptr) { 76314564Sdim bool show_fullpaths = false; 77314564Sdim m_inlineInfoSP->Dump(s, show_fullpaths); 78314564Sdim } 79254721Semaste 80314564Sdim if (!m_ranges.IsEmpty()) { 81314564Sdim *s << ", ranges ="; 82276479Sdim 83314564Sdim size_t num_ranges = m_ranges.GetSize(); 84314564Sdim for (size_t i = 0; i < num_ranges; ++i) { 85314564Sdim const Range &range = m_ranges.GetEntryRef(i); 86344779Sdim if (parent_block != nullptr && !parent_block->Contains(range)) 87314564Sdim *s << '!'; 88314564Sdim else 89314564Sdim *s << ' '; 90360784Sdim DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(), 91360784Sdim base_addr + range.GetRangeEnd(), 4); 92254721Semaste } 93314564Sdim } 94314564Sdim s->EOL(); 95254721Semaste 96314564Sdim if (depth > 0) { 97314564Sdim s->IndentMore(); 98254721Semaste 99314564Sdim if (m_variable_list_sp.get()) { 100314564Sdim m_variable_list_sp->Dump(s, show_context); 101254721Semaste } 102254721Semaste 103254721Semaste collection::const_iterator pos, end = m_children.end(); 104254721Semaste for (pos = m_children.begin(); pos != end; ++pos) 105314564Sdim (*pos)->Dump(s, base_addr, depth - 1, show_context); 106314564Sdim 107314564Sdim s->IndentLess(); 108314564Sdim } 109254721Semaste} 110254721Semaste 111314564SdimBlock *Block::FindBlockByID(user_id_t block_id) { 112314564Sdim if (block_id == GetID()) 113314564Sdim return this; 114314564Sdim 115314564Sdim Block *matching_block = nullptr; 116314564Sdim collection::const_iterator pos, end = m_children.end(); 117314564Sdim for (pos = m_children.begin(); pos != end; ++pos) { 118314564Sdim matching_block = (*pos)->FindBlockByID(block_id); 119314564Sdim if (matching_block) 120314564Sdim break; 121314564Sdim } 122314564Sdim return matching_block; 123254721Semaste} 124254721Semaste 125314564Sdimvoid Block::CalculateSymbolContext(SymbolContext *sc) { 126314564Sdim if (m_parent_scope) 127314564Sdim m_parent_scope->CalculateSymbolContext(sc); 128314564Sdim sc->block = this; 129254721Semaste} 130254721Semaste 131314564Sdimlldb::ModuleSP Block::CalculateSymbolContextModule() { 132314564Sdim if (m_parent_scope) 133314564Sdim return m_parent_scope->CalculateSymbolContextModule(); 134314564Sdim return lldb::ModuleSP(); 135254721Semaste} 136254721Semaste 137314564SdimCompileUnit *Block::CalculateSymbolContextCompileUnit() { 138314564Sdim if (m_parent_scope) 139314564Sdim return m_parent_scope->CalculateSymbolContextCompileUnit(); 140314564Sdim return nullptr; 141254721Semaste} 142254721Semaste 143314564SdimFunction *Block::CalculateSymbolContextFunction() { 144314564Sdim if (m_parent_scope) 145314564Sdim return m_parent_scope->CalculateSymbolContextFunction(); 146314564Sdim return nullptr; 147254721Semaste} 148254721Semaste 149314564SdimBlock *Block::CalculateSymbolContextBlock() { return this; } 150314564Sdim 151314564Sdimvoid Block::DumpSymbolContext(Stream *s) { 152314564Sdim Function *function = CalculateSymbolContextFunction(); 153314564Sdim if (function) 154314564Sdim function->DumpSymbolContext(s); 155314564Sdim s->Printf(", Block{0x%8.8" PRIx64 "}", GetID()); 156254721Semaste} 157254721Semaste 158314564Sdimvoid Block::DumpAddressRanges(Stream *s, lldb::addr_t base_addr) { 159314564Sdim if (!m_ranges.IsEmpty()) { 160314564Sdim size_t num_ranges = m_ranges.GetSize(); 161314564Sdim for (size_t i = 0; i < num_ranges; ++i) { 162314564Sdim const Range &range = m_ranges.GetEntryRef(i); 163360784Sdim DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(), 164360784Sdim base_addr + range.GetRangeEnd(), 4); 165254721Semaste } 166314564Sdim } 167254721Semaste} 168254721Semaste 169314564Sdimbool Block::Contains(addr_t range_offset) const { 170314564Sdim return m_ranges.FindEntryThatContains(range_offset) != nullptr; 171254721Semaste} 172254721Semaste 173314564Sdimbool Block::Contains(const Block *block) const { 174314564Sdim if (this == block) 175314564Sdim return false; // This block doesn't contain itself... 176314564Sdim 177314564Sdim // Walk the parent chain for "block" and see if any if them match this block 178314564Sdim const Block *block_parent; 179314564Sdim for (block_parent = block->GetParent(); block_parent != nullptr; 180314564Sdim block_parent = block_parent->GetParent()) { 181314564Sdim if (this == block_parent) 182314564Sdim return true; // One of the parents of "block" is this object! 183314564Sdim } 184314564Sdim return false; 185254721Semaste} 186254721Semaste 187314564Sdimbool Block::Contains(const Range &range) const { 188314564Sdim return m_ranges.FindEntryThatContains(range) != nullptr; 189254721Semaste} 190254721Semaste 191314564SdimBlock *Block::GetParent() const { 192314564Sdim if (m_parent_scope) 193314564Sdim return m_parent_scope->CalculateSymbolContextBlock(); 194314564Sdim return nullptr; 195254721Semaste} 196254721Semaste 197314564SdimBlock *Block::GetContainingInlinedBlock() { 198314564Sdim if (GetInlinedFunctionInfo()) 199314564Sdim return this; 200314564Sdim return GetInlinedParent(); 201254721Semaste} 202254721Semaste 203314564SdimBlock *Block::GetInlinedParent() { 204314564Sdim Block *parent_block = GetParent(); 205314564Sdim if (parent_block) { 206314564Sdim if (parent_block->GetInlinedFunctionInfo()) 207314564Sdim return parent_block; 208314564Sdim else 209314564Sdim return parent_block->GetInlinedParent(); 210314564Sdim } 211314564Sdim return nullptr; 212254721Semaste} 213254721Semaste 214353358SdimBlock *Block::GetContainingInlinedBlockWithCallSite( 215353358Sdim const Declaration &find_call_site) { 216353358Sdim Block *inlined_block = GetContainingInlinedBlock(); 217353358Sdim 218353358Sdim while (inlined_block) { 219353358Sdim const auto *function_info = inlined_block->GetInlinedFunctionInfo(); 220353358Sdim 221353358Sdim if (function_info && 222353358Sdim function_info->GetCallSite().FileAndLineEqual(find_call_site)) 223353358Sdim return inlined_block; 224353358Sdim inlined_block = inlined_block->GetInlinedParent(); 225353358Sdim } 226353358Sdim return nullptr; 227353358Sdim} 228353358Sdim 229314564Sdimbool Block::GetRangeContainingOffset(const addr_t offset, Range &range) { 230314564Sdim const Range *range_ptr = m_ranges.FindEntryThatContains(offset); 231314564Sdim if (range_ptr) { 232314564Sdim range = *range_ptr; 233314564Sdim return true; 234314564Sdim } 235314564Sdim range.Clear(); 236314564Sdim return false; 237254721Semaste} 238254721Semaste 239314564Sdimbool Block::GetRangeContainingAddress(const Address &addr, 240314564Sdim AddressRange &range) { 241314564Sdim Function *function = CalculateSymbolContextFunction(); 242314564Sdim if (function) { 243314564Sdim const AddressRange &func_range = function->GetAddressRange(); 244314564Sdim if (addr.GetSection() == func_range.GetBaseAddress().GetSection()) { 245314564Sdim const addr_t addr_offset = addr.GetOffset(); 246314564Sdim const addr_t func_offset = func_range.GetBaseAddress().GetOffset(); 247314564Sdim if (addr_offset >= func_offset && 248314564Sdim addr_offset < func_offset + func_range.GetByteSize()) { 249314564Sdim addr_t offset = addr_offset - func_offset; 250254721Semaste 251314564Sdim const Range *range_ptr = m_ranges.FindEntryThatContains(offset); 252254721Semaste 253314564Sdim if (range_ptr) { 254314564Sdim range.GetBaseAddress() = func_range.GetBaseAddress(); 255314564Sdim range.GetBaseAddress().SetOffset(func_offset + 256314564Sdim range_ptr->GetRangeBase()); 257314564Sdim range.SetByteSize(range_ptr->GetByteSize()); 258314564Sdim return true; 259254721Semaste } 260314564Sdim } 261254721Semaste } 262314564Sdim } 263314564Sdim range.Clear(); 264314564Sdim return false; 265254721Semaste} 266254721Semaste 267314564Sdimbool Block::GetRangeContainingLoadAddress(lldb::addr_t load_addr, 268314564Sdim Target &target, AddressRange &range) { 269314564Sdim Address load_address; 270314564Sdim load_address.SetLoadAddress(load_addr, &target); 271314564Sdim AddressRange containing_range; 272314564Sdim return GetRangeContainingAddress(load_address, containing_range); 273254721Semaste} 274254721Semaste 275314564Sdimuint32_t Block::GetRangeIndexContainingAddress(const Address &addr) { 276314564Sdim Function *function = CalculateSymbolContextFunction(); 277314564Sdim if (function) { 278314564Sdim const AddressRange &func_range = function->GetAddressRange(); 279314564Sdim if (addr.GetSection() == func_range.GetBaseAddress().GetSection()) { 280314564Sdim const addr_t addr_offset = addr.GetOffset(); 281314564Sdim const addr_t func_offset = func_range.GetBaseAddress().GetOffset(); 282314564Sdim if (addr_offset >= func_offset && 283314564Sdim addr_offset < func_offset + func_range.GetByteSize()) { 284314564Sdim addr_t offset = addr_offset - func_offset; 285314564Sdim return m_ranges.FindEntryIndexThatContains(offset); 286314564Sdim } 287314564Sdim } 288314564Sdim } 289314564Sdim return UINT32_MAX; 290314564Sdim} 291254721Semaste 292314564Sdimbool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) { 293314564Sdim if (range_idx < m_ranges.GetSize()) { 294254721Semaste Function *function = CalculateSymbolContextFunction(); 295314564Sdim if (function) { 296314564Sdim const Range &vm_range = m_ranges.GetEntryRef(range_idx); 297314564Sdim range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress(); 298314564Sdim range.GetBaseAddress().Slide(vm_range.GetRangeBase()); 299314564Sdim range.SetByteSize(vm_range.GetByteSize()); 300314564Sdim return true; 301254721Semaste } 302314564Sdim } 303314564Sdim return false; 304254721Semaste} 305254721Semaste 306314564Sdimbool Block::GetStartAddress(Address &addr) { 307314564Sdim if (m_ranges.IsEmpty()) 308254721Semaste return false; 309254721Semaste 310314564Sdim Function *function = CalculateSymbolContextFunction(); 311314564Sdim if (function) { 312314564Sdim addr = function->GetAddressRange().GetBaseAddress(); 313314564Sdim addr.Slide(m_ranges.GetEntryRef(0).GetRangeBase()); 314314564Sdim return true; 315314564Sdim } 316314564Sdim return false; 317254721Semaste} 318254721Semaste 319314564Sdimvoid Block::FinalizeRanges() { 320314564Sdim m_ranges.Sort(); 321314564Sdim m_ranges.CombineConsecutiveRanges(); 322254721Semaste} 323254721Semaste 324314564Sdimvoid Block::AddRange(const Range &range) { 325314564Sdim Block *parent_block = GetParent(); 326314564Sdim if (parent_block && !parent_block->Contains(range)) { 327314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS)); 328314564Sdim if (log) { 329314564Sdim ModuleSP module_sp(m_parent_scope->CalculateSymbolContextModule()); 330314564Sdim Function *function = m_parent_scope->CalculateSymbolContextFunction(); 331314564Sdim const addr_t function_file_addr = 332314564Sdim function->GetAddressRange().GetBaseAddress().GetFileAddress(); 333314564Sdim const addr_t block_start_addr = function_file_addr + range.GetRangeBase(); 334314564Sdim const addr_t block_end_addr = function_file_addr + range.GetRangeEnd(); 335314564Sdim Type *func_type = function->GetType(); 336314564Sdim 337314564Sdim const Declaration &func_decl = func_type->GetDeclaration(); 338314564Sdim if (func_decl.GetLine()) { 339360784Sdim LLDB_LOGF(log, 340360784Sdim "warning: %s:%u block {0x%8.8" PRIx64 341360784Sdim "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 342360784Sdim ") which is not contained in parent block {0x%8.8" PRIx64 343360784Sdim "} in function {0x%8.8" PRIx64 "} from %s", 344360784Sdim func_decl.GetFile().GetPath().c_str(), func_decl.GetLine(), 345360784Sdim GetID(), (uint32_t)m_ranges.GetSize(), block_start_addr, 346360784Sdim block_end_addr, parent_block->GetID(), function->GetID(), 347360784Sdim module_sp->GetFileSpec().GetPath().c_str()); 348314564Sdim } else { 349360784Sdim LLDB_LOGF(log, 350360784Sdim "warning: block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 351360784Sdim " - 0x%" PRIx64 352360784Sdim ") which is not contained in parent block {0x%8.8" PRIx64 353360784Sdim "} in function {0x%8.8" PRIx64 "} from %s", 354360784Sdim GetID(), (uint32_t)m_ranges.GetSize(), block_start_addr, 355360784Sdim block_end_addr, parent_block->GetID(), function->GetID(), 356360784Sdim module_sp->GetFileSpec().GetPath().c_str()); 357314564Sdim } 358254721Semaste } 359314564Sdim parent_block->AddRange(range); 360314564Sdim } 361314564Sdim m_ranges.Append(range); 362254721Semaste} 363254721Semaste 364254721Semaste// Return the current number of bytes that this object occupies in memory 365314564Sdimsize_t Block::MemorySize() const { 366314564Sdim size_t mem_size = sizeof(Block) + m_ranges.GetSize() * sizeof(Range); 367314564Sdim if (m_inlineInfoSP.get()) 368314564Sdim mem_size += m_inlineInfoSP->MemorySize(); 369314564Sdim if (m_variable_list_sp.get()) 370314564Sdim mem_size += m_variable_list_sp->MemorySize(); 371314564Sdim return mem_size; 372254721Semaste} 373254721Semaste 374314564Sdimvoid Block::AddChild(const BlockSP &child_block_sp) { 375314564Sdim if (child_block_sp) { 376314564Sdim child_block_sp->SetParentScope(this); 377314564Sdim m_children.push_back(child_block_sp); 378314564Sdim } 379254721Semaste} 380254721Semaste 381314564Sdimvoid Block::SetInlinedFunctionInfo(const char *name, const char *mangled, 382314564Sdim const Declaration *decl_ptr, 383314564Sdim const Declaration *call_decl_ptr) { 384353358Sdim m_inlineInfoSP = std::make_shared<InlineFunctionInfo>(name, mangled, decl_ptr, 385353358Sdim call_decl_ptr); 386254721Semaste} 387254721Semaste 388314564SdimVariableListSP Block::GetBlockVariableList(bool can_create) { 389344779Sdim if (!m_parsed_block_variables) { 390314564Sdim if (m_variable_list_sp.get() == nullptr && can_create) { 391314564Sdim m_parsed_block_variables = true; 392314564Sdim SymbolContext sc; 393314564Sdim CalculateSymbolContext(&sc); 394314564Sdim assert(sc.module_sp); 395360784Sdim sc.module_sp->GetSymbolFile()->ParseVariablesForContext(sc); 396254721Semaste } 397314564Sdim } 398314564Sdim return m_variable_list_sp; 399254721Semaste} 400254721Semaste 401254721Semasteuint32_t 402314564SdimBlock::AppendBlockVariables(bool can_create, bool get_child_block_variables, 403314564Sdim bool stop_if_child_block_is_inlined_function, 404314564Sdim const std::function<bool(Variable *)> &filter, 405314564Sdim VariableList *variable_list) { 406314564Sdim uint32_t num_variables_added = 0; 407314564Sdim VariableList *block_var_list = GetBlockVariableList(can_create).get(); 408314564Sdim if (block_var_list) { 409360784Sdim for (const VariableSP &var_sp : *block_var_list) { 410360784Sdim if (filter(var_sp.get())) { 411314564Sdim num_variables_added++; 412360784Sdim variable_list->AddVariable(var_sp); 413314564Sdim } 414254721Semaste } 415314564Sdim } 416309124Sdim 417314564Sdim if (get_child_block_variables) { 418314564Sdim collection::const_iterator pos, end = m_children.end(); 419314564Sdim for (pos = m_children.begin(); pos != end; ++pos) { 420314564Sdim Block *child_block = pos->get(); 421344779Sdim if (!stop_if_child_block_is_inlined_function || 422314564Sdim child_block->GetInlinedFunctionInfo() == nullptr) { 423314564Sdim num_variables_added += child_block->AppendBlockVariables( 424314564Sdim can_create, get_child_block_variables, 425314564Sdim stop_if_child_block_is_inlined_function, filter, variable_list); 426314564Sdim } 427254721Semaste } 428314564Sdim } 429314564Sdim return num_variables_added; 430254721Semaste} 431254721Semaste 432314564Sdimuint32_t Block::AppendVariables(bool can_create, bool get_parent_variables, 433314564Sdim bool stop_if_block_is_inlined_function, 434314564Sdim const std::function<bool(Variable *)> &filter, 435314564Sdim VariableList *variable_list) { 436314564Sdim uint32_t num_variables_added = 0; 437314564Sdim VariableListSP variable_list_sp(GetBlockVariableList(can_create)); 438254721Semaste 439314564Sdim bool is_inlined_function = GetInlinedFunctionInfo() != nullptr; 440314564Sdim if (variable_list_sp) { 441314564Sdim for (size_t i = 0; i < variable_list_sp->GetSize(); ++i) { 442314564Sdim VariableSP variable = variable_list_sp->GetVariableAtIndex(i); 443314564Sdim if (filter(variable.get())) { 444314564Sdim num_variables_added++; 445314564Sdim variable_list->AddVariable(variable); 446314564Sdim } 447254721Semaste } 448314564Sdim } 449309124Sdim 450314564Sdim if (get_parent_variables) { 451314564Sdim if (stop_if_block_is_inlined_function && is_inlined_function) 452314564Sdim return num_variables_added; 453314564Sdim 454314564Sdim Block *parent_block = GetParent(); 455314564Sdim if (parent_block) 456314564Sdim num_variables_added += parent_block->AppendVariables( 457314564Sdim can_create, get_parent_variables, stop_if_block_is_inlined_function, 458314564Sdim filter, variable_list); 459314564Sdim } 460314564Sdim return num_variables_added; 461254721Semaste} 462254721Semaste 463344779SdimSymbolFile *Block::GetSymbolFile() { 464344779Sdim if (ModuleSP module_sp = CalculateSymbolContextModule()) 465360784Sdim return module_sp->GetSymbolFile(); 466344779Sdim return nullptr; 467344779Sdim} 468344779Sdim 469314564SdimCompilerDeclContext Block::GetDeclContext() { 470344779Sdim if (SymbolFile *sym_file = GetSymbolFile()) 471344779Sdim return sym_file->GetDeclContextForUID(GetID()); 472314564Sdim return CompilerDeclContext(); 473254721Semaste} 474254721Semaste 475314564Sdimvoid Block::SetBlockInfoHasBeenParsed(bool b, bool set_children) { 476314564Sdim m_parsed_block_info = b; 477314564Sdim if (set_children) { 478314564Sdim m_parsed_child_blocks = true; 479314564Sdim collection::const_iterator pos, end = m_children.end(); 480314564Sdim for (pos = m_children.begin(); pos != end; ++pos) 481314564Sdim (*pos)->SetBlockInfoHasBeenParsed(b, true); 482314564Sdim } 483254721Semaste} 484254721Semaste 485314564Sdimvoid Block::SetDidParseVariables(bool b, bool set_children) { 486314564Sdim m_parsed_block_variables = b; 487314564Sdim if (set_children) { 488314564Sdim collection::const_iterator pos, end = m_children.end(); 489314564Sdim for (pos = m_children.begin(); pos != end; ++pos) 490314564Sdim (*pos)->SetDidParseVariables(b, true); 491314564Sdim } 492254721Semaste} 493254721Semaste 494314564SdimBlock *Block::GetSibling() const { 495314564Sdim if (m_parent_scope) { 496314564Sdim Block *parent_block = GetParent(); 497314564Sdim if (parent_block) 498314564Sdim return parent_block->GetSiblingForChild(this); 499314564Sdim } 500314564Sdim return nullptr; 501254721Semaste} 502254721Semaste// A parent of child blocks can be asked to find a sibling block given 503254721Semaste// one of its child blocks 504314564SdimBlock *Block::GetSiblingForChild(const Block *child_block) const { 505314564Sdim if (!m_children.empty()) { 506314564Sdim collection::const_iterator pos, end = m_children.end(); 507314564Sdim for (pos = m_children.begin(); pos != end; ++pos) { 508314564Sdim if (pos->get() == child_block) { 509314564Sdim if (++pos != end) 510314564Sdim return pos->get(); 511314564Sdim break; 512314564Sdim } 513254721Semaste } 514314564Sdim } 515314564Sdim return nullptr; 516254721Semaste} 517