//===-- Block.h -------------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_Block_h_
#define liblldb_Block_h_

// C Includes
// C++ Includes
#include <vector>

// Other libraries and framework includes
// Project includes
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/UserID.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

//----------------------------------------------------------------------
/// @class Block Block.h "lldb/Symbol/Block.h"
/// @brief A class that describes a single lexical block.
///
/// A Function object owns a BlockList object which owns one or more
/// Block objects. The BlockList object contains a section offset
/// address range, and Block objects contain one or more ranges
/// which are offsets into that range. Blocks are can have discontiguous
/// ranges within the BlockList address range, and each block can
/// contain child blocks each with their own sets of ranges.
///
/// Each block has a variable list that represents local, argument, and
/// static variables that are scoped to the block.
///
/// Inlined functions are represented by attaching a
/// InlineFunctionInfo shared pointer object to a block. Inlined
/// functions are represented as named blocks.
//----------------------------------------------------------------------
class Block : public UserID, public SymbolContextScope {
public:
  typedef RangeArray<uint32_t, uint32_t, 1> RangeList;
  typedef RangeList::Entry Range;

  //------------------------------------------------------------------
  /// Construct with a User ID \a uid, \a depth.
  ///
  /// Initialize this block with the specified UID \a uid. The
  /// \a depth in the \a block_list is used to represent the parent,
  /// sibling, and child block information and also allows for partial
  /// parsing at the block level.
  ///
  /// @param[in] uid
  ///     The UID for a given block. This value is given by the
  ///     SymbolFile plug-in and can be any value that helps the
  ///     SymbolFile plug-in to match this block back to the debug
  ///     information data that it parses for further or more in
  ///     depth parsing. Common values would be the index into a
  ///     table, or an offset into the debug information.
  ///
  /// @param[in] depth
  ///     The integer depth of this block in the block list hierarchy.
  ///
  /// @param[in] block_list
  ///     The block list that this object belongs to.
  ///
  /// @see BlockList
  //------------------------------------------------------------------
  Block(lldb::user_id_t uid);

  //------------------------------------------------------------------
  /// Destructor.
  //------------------------------------------------------------------
  ~Block() override;

  //------------------------------------------------------------------
  /// Add a child to this object.
  ///
  /// @param[in] child_block_sp
  ///     A shared pointer to a child block that will get added to
  ///     this block.
  //------------------------------------------------------------------
  void AddChild(const lldb::BlockSP &child_block_sp);

  //------------------------------------------------------------------
  /// Add a new offset range to this block.
  ///
  /// @param[in] start_offset
  ///     An offset into this Function's address range that
  ///     describes the start address of a range for this block.
  ///
  /// @param[in] end_offset
  ///     An offset into this Function's address range that
  ///     describes the end address of a range for this block.
  //------------------------------------------------------------------
  void AddRange(const Range &range);

  void FinalizeRanges();

  //------------------------------------------------------------------
  /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
  ///
  /// @see SymbolContextScope
  //------------------------------------------------------------------
  void CalculateSymbolContext(SymbolContext *sc) override;

  lldb::ModuleSP CalculateSymbolContextModule() override;

  CompileUnit *CalculateSymbolContextCompileUnit() override;

  Function *CalculateSymbolContextFunction() override;

  Block *CalculateSymbolContextBlock() override;

  //------------------------------------------------------------------
  /// Check if an offset is in one of the block offset ranges.
  ///
  /// @param[in] range_offset
  ///     An offset into the Function's address range.
  ///
  /// @return
  ///     Returns \b true if \a range_offset falls in one of this
  ///     block's ranges, \b false otherwise.
  //------------------------------------------------------------------
  bool Contains(lldb::addr_t range_offset) const;

  //------------------------------------------------------------------
  /// Check if a offset range is in one of the block offset ranges.
  ///
  /// @param[in] range
  ///     An offset range into the Function's address range.
  ///
  /// @return
  ///     Returns \b true if \a range falls in one of this
  ///     block's ranges, \b false otherwise.
  //------------------------------------------------------------------
  bool Contains(const Range &range) const;

  //------------------------------------------------------------------
  /// Check if this object contains "block" as a child block at any
  /// depth.
  ///
  /// @param[in] block
  ///     A potential child block.
  ///
  /// @return
  ///     Returns \b true if \a block is a child of this block, \b
  ///     false otherwise.
  //------------------------------------------------------------------
  bool Contains(const Block *block) const;

  //------------------------------------------------------------------
  /// Dump the block contents.
  ///
  /// @param[in] s
  ///     The stream to which to dump the object description.
  ///
  /// @param[in] base_addr
  ///     The resolved start address of the Function's address
  ///     range. This should be resolved as the file or load address
  ///     prior to passing the value into this function for dumping.
  ///
  /// @param[in] depth
  ///     Limit the number of levels deep that this function should
  ///     print as this block can contain child blocks. Specify
  ///     INT_MAX to dump all child blocks.
  ///
  /// @param[in] show_context
  ///     If \b true, variables will dump their context information.
  //------------------------------------------------------------------
  void Dump(Stream *s, lldb::addr_t base_addr, int32_t depth,
            bool show_context) const;

  //------------------------------------------------------------------
  /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
  ///
  /// @see SymbolContextScope
  //------------------------------------------------------------------
  void DumpSymbolContext(Stream *s) override;

  void DumpAddressRanges(Stream *s, lldb::addr_t base_addr);

  void GetDescription(Stream *s, Function *function,
                      lldb::DescriptionLevel level, Target *target) const;

  //------------------------------------------------------------------
  /// Get the parent block.
  ///
  /// @return
  ///     The parent block pointer, or nullptr if this block has no
  ///     parent.
  //------------------------------------------------------------------
  Block *GetParent() const;

  //------------------------------------------------------------------
  /// Get the inlined block that contains this block.
  ///
  /// @return
  ///     If this block contains inlined function info, it will return
  ///     this block, else parent blocks will be searched to see if
  ///     any contain this block. nullptr will be returned if this block
  ///     nor any parent blocks are inlined function blocks.
  //------------------------------------------------------------------
  Block *GetContainingInlinedBlock();

  //------------------------------------------------------------------
  /// Get the inlined parent block for this block.
  ///
  /// @return
  ///     The parent block pointer, or nullptr if this block has no
  ///     parent.
  //------------------------------------------------------------------
  Block *GetInlinedParent();

  //------------------------------------------------------------------
  /// Get the sibling block for this block.
  ///
  /// @return
  ///     The sibling block pointer, or nullptr if this block has no
  ///     sibling.
  //------------------------------------------------------------------
  Block *GetSibling() const;

  //------------------------------------------------------------------
  /// Get the first child block.
  ///
  /// @return
  ///     The first child block pointer, or nullptr if this block has no
  ///     children.
  //------------------------------------------------------------------
  Block *GetFirstChild() const {
    return (m_children.empty() ? nullptr : m_children.front().get());
  }

  //------------------------------------------------------------------
  /// Get the variable list for this block only.
  ///
  /// @param[in] can_create
  ///     If \b true, the variables can be parsed if they already
  ///     haven't been, else the current state of the block will be
  ///     returned.
  ///
  /// @return
  ///     A variable list shared pointer that contains all variables
  ///     for this block.
  //------------------------------------------------------------------
  lldb::VariableListSP GetBlockVariableList(bool can_create);

  //------------------------------------------------------------------
  /// Get the variable list for this block and optionally all child
  /// blocks if \a get_child_variables is \b true.
  ///
  /// @param[in] get_child_variables
  ///     If \b true, all variables from all child blocks will be
  ///     added to the variable list.
  ///
  /// @param[in] can_create
  ///     If \b true, the variables can be parsed if they already
  ///     haven't been, else the current state of the block will be
  ///     returned. Passing \b true for this parameter can be used
  ///     to see the current state of what has been parsed up to this
  ///     point.
  ///
  /// @param[in] add_inline_child_block_variables
  ///     If this is \b false, no child variables of child blocks
  ///     that are inlined functions will be gotten. If \b true then
  ///     all child variables will be added regardless of whether they
  ///     come from inlined functions or not.
  ///
  /// @return
  ///     A variable list shared pointer that contains all variables
  ///     for this block.
  //------------------------------------------------------------------
  uint32_t AppendBlockVariables(bool can_create, bool get_child_block_variables,
                                bool stop_if_child_block_is_inlined_function,
                                const std::function<bool(Variable *)> &filter,
                                VariableList *variable_list);

  //------------------------------------------------------------------
  /// Appends the variables from this block, and optionally from all
  /// parent blocks, to \a variable_list.
  ///
  /// @param[in] can_create
  ///     If \b true, the variables can be parsed if they already
  ///     haven't been, else the current state of the block will be
  ///     returned. Passing \b true for this parameter can be used
  ///     to see the current state of what has been parsed up to this
  ///     point.
  ///
  /// @param[in] get_parent_variables
  ///     If \b true, all variables from all parent blocks will be
  ///     added to the variable list.
  ///
  /// @param[in] stop_if_block_is_inlined_function
  ///     If \b true, all variables from all parent blocks will be
  ///     added to the variable list until there are no parent blocks
  ///     or the parent block has inlined function info.
  ///
  /// @param[in,out] variable_list
  ///     All variables in this block, and optionally all parent
  ///     blocks will be added to this list.
  ///
  /// @return
  ///     The number of variable that were appended to \a
  ///     variable_list.
  //------------------------------------------------------------------
  uint32_t AppendVariables(bool can_create, bool get_parent_variables,
                           bool stop_if_block_is_inlined_function,
                           const std::function<bool(Variable *)> &filter,
                           VariableList *variable_list);

  //------------------------------------------------------------------
  /// Get const accessor for any inlined function information.
  ///
  /// @return
  ///     A const pointer to any inlined function information, or nullptr
  ///     if this is a regular block.
  //------------------------------------------------------------------
  const InlineFunctionInfo *GetInlinedFunctionInfo() const {
    return m_inlineInfoSP.get();
  }

  CompilerDeclContext GetDeclContext();

  //------------------------------------------------------------------
  /// Get the memory cost of this object.
  ///
  /// Returns the cost of this object plus any owned objects from the
  /// ranges, variables, and inline function information.
  ///
  /// @return
  ///     The number of bytes that this object occupies in memory.
  //------------------------------------------------------------------
  size_t MemorySize() const;

  //------------------------------------------------------------------
  /// Set accessor for any inlined function information.
  ///
  /// @param[in] name
  ///     The method name for the inlined function. This value should
  ///     not be nullptr.
  ///
  /// @param[in] mangled
  ///     The mangled method name for the inlined function. This can
  ///     be nullptr if there is no mangled name for an inlined function
  ///     or if the name is the same as \a name.
  ///
  /// @param[in] decl_ptr
  ///     A optional pointer to declaration information for the
  ///     inlined function information. This value can be nullptr to
  ///     indicate that no declaration information is available.
  ///
  /// @param[in] call_decl_ptr
  ///     Optional calling location declaration information that
  ///     describes from where this inlined function was called.
  //------------------------------------------------------------------
  void SetInlinedFunctionInfo(const char *name, const char *mangled,
                              const Declaration *decl_ptr,
                              const Declaration *call_decl_ptr);

  void SetParentScope(SymbolContextScope *parent_scope) {
    m_parent_scope = parent_scope;
  }

  //------------------------------------------------------------------
  /// Set accessor for the variable list.
  ///
  /// Called by the SymbolFile plug-ins after they have parsed the
  /// variable lists and are ready to hand ownership of the list over
  /// to this object.
  ///
  /// @param[in] variable_list_sp
  ///     A shared pointer to a VariableList.
  //------------------------------------------------------------------
  void SetVariableList(lldb::VariableListSP &variable_list_sp) {
    m_variable_list_sp = variable_list_sp;
  }

  bool BlockInfoHasBeenParsed() const { return m_parsed_block_info; }

  void SetBlockInfoHasBeenParsed(bool b, bool set_children);

  Block *FindBlockByID(lldb::user_id_t block_id);

  size_t GetNumRanges() const { return m_ranges.GetSize(); }

  bool GetRangeContainingOffset(const lldb::addr_t offset, Range &range);

  bool GetRangeContainingAddress(const Address &addr, AddressRange &range);

  bool GetRangeContainingLoadAddress(lldb::addr_t load_addr, Target &target,
                                     AddressRange &range);

  uint32_t GetRangeIndexContainingAddress(const Address &addr);

  //------------------------------------------------------------------
  // Since blocks might have multiple discontiguous address ranges,
  // we need to be able to get at any of the address ranges in a block.
  //------------------------------------------------------------------
  bool GetRangeAtIndex(uint32_t range_idx, AddressRange &range);

  bool GetStartAddress(Address &addr);

  void SetDidParseVariables(bool b, bool set_children);

protected:
  typedef std::vector<lldb::BlockSP> collection;
  //------------------------------------------------------------------
  // Member variables.
  //------------------------------------------------------------------
  SymbolContextScope *m_parent_scope;
  collection m_children;
  RangeList m_ranges;
  lldb::InlineFunctionInfoSP m_inlineInfoSP; ///< Inlined function information.
  lldb::VariableListSP m_variable_list_sp; ///< The variable list for all local,
                                           ///static and parameter variables
                                           ///scoped to this block.
  bool m_parsed_block_info : 1, ///< Set to true if this block and it's children
                                ///have all been parsed
      m_parsed_block_variables : 1, m_parsed_child_blocks : 1;

  // A parent of child blocks can be asked to find a sibling block given
  // one of its child blocks
  Block *GetSiblingForChild(const Block *child_block) const;

private:
  DISALLOW_COPY_AND_ASSIGN(Block);
};

} // namespace lldb_private

#endif // liblldb_Block_h_
