public boolean isChildOf(@Nullable final WrapImpl wrap, LeafBlockWrapper leaf) {
   if (getIgnoreParentWraps()) return false;
   if (leaf != null && myIgnoredWraps != null) {
     Collection<LeafBlockWrapper> leaves = myIgnoredWraps.get(wrap);
     if (leaves != null && leaves.contains(leaf)) {
       return false;
     }
   }
   for (WrapImpl parent : myParents) {
     if (parent == wrap) return true;
     if (parent.isChildOf(wrap, leaf)) return true;
   }
   return false;
 }
 /**
  * Allows to register given wrap as a parent of the current wrap.
  *
  * <p><code>'Parent'</code> wrap registration here means that {@link #isChildOf(WrapImpl,
  * LeafBlockWrapper)} returns <code>'true'</code> if given wrap is used as a <code>'parent'</code>
  * argument.
  *
  * @param parent parent wrap to register for the current wrap
  */
 void registerParent(@Nullable WrapImpl parent) {
   if (parent == this) return;
   if (parent == null) return;
   if (parent.isChildOf(this, null)) return;
   if (myParents == emptyParentsSet) myParents = new HashSet<WrapImpl>(5);
   myParents.add(parent);
 }
  /**
   * Wraps given root block and all of its descendants and returns root block wrapper.
   *
   * <p>This method performs necessary infrastructure actions and delegates actual processing to
   * {@link #buildCompositeBlock(Block, CompositeBlockWrapper, int, WrapImpl, boolean)} and {@link
   * #processSimpleBlock(Block, CompositeBlockWrapper, boolean, int, Block)}.
   *
   * @param rootBlock block to wrap
   * @param index index of the current block at its parent block. <code>-1</code> may be used here
   *     if we don't have information about parent block
   * @param parent parent block wrapper. <code>null</code> may be used here we no parent block
   *     wrapper exists
   * @param currentWrapParent parent wrap if any; <code>null</code> otherwise
   * @param parentBlock parent block of the block to wrap
   * @param rootBlockIsRightBlock flag that shows if target block is the right-most block
   * @return wrapper for the given <code>'rootBlock'</code>
   */
  private AbstractBlockWrapper buildFrom(
      final Block rootBlock,
      final int index,
      @Nullable final CompositeBlockWrapper parent,
      @Nullable WrapImpl currentWrapParent,
      @Nullable final Block parentBlock,
      boolean rootBlockIsRightBlock) {
    final WrapImpl wrap = (WrapImpl) rootBlock.getWrap();
    if (wrap != null) {
      wrap.registerParent(currentWrapParent);
      currentWrapParent = wrap;
    }
    TextRange textRange = rootBlock.getTextRange();
    final int blockStartOffset = textRange.getStartOffset();

    if (parent != null) {
      if (textRange.getStartOffset() < parent.getStartOffset()) {
        assertInvalidRanges(
            textRange.getStartOffset(),
            parent.getStartOffset(),
            myModel,
            "child block start is less than parent block start");
      }

      if (textRange.getEndOffset() > parent.getEndOffset()) {
        assertInvalidRanges(
            textRange.getEndOffset(),
            parent.getEndOffset(),
            myModel,
            "child block end is after parent block end");
      }
    }

    myCurrentWhiteSpace.append(blockStartOffset, myModel, myOptions);

    if (myCollectAlignmentsInsideFormattingRange
        && rootBlock.getAlignment() != null
        && isAffectedByFormatting(rootBlock)
        && !myInsideFormatRestrictingTag) {
      myAlignmentsInsideRangeToModify.add(rootBlock.getAlignment());
    }

    if (rootBlock.getAlignment() != null) {
      myBlocksToAlign.putValue(rootBlock.getAlignment(), rootBlock);
    }

    ReadOnlyBlockInformationProvider previousProvider = myReadOnlyBlockInformationProvider;
    try {
      if (rootBlock instanceof ReadOnlyBlockInformationProvider) {
        myReadOnlyBlockInformationProvider = (ReadOnlyBlockInformationProvider) rootBlock;
      }
      if (isInsideFormattingRanges(rootBlock, rootBlockIsRightBlock)
          || myCollectAlignmentsInsideFormattingRange && isInsideExtendedAffectedRange(rootBlock)) {
        final List<Block> subBlocks = rootBlock.getSubBlocks();
        if (subBlocks.isEmpty()
            || myReadOnlyBlockInformationProvider != null
                && myReadOnlyBlockInformationProvider.isReadOnly(rootBlock)) {
          final AbstractBlockWrapper wrapper =
              processSimpleBlock(rootBlock, parent, false, index, parentBlock);
          if (!subBlocks.isEmpty()) {
            wrapper.setIndent((IndentImpl) subBlocks.get(0).getIndent());
          }
          return wrapper;
        }
        return buildCompositeBlock(
            rootBlock, parent, index, currentWrapParent, rootBlockIsRightBlock);
      } else {
        // block building is skipped
        return processSimpleBlock(rootBlock, parent, true, index, parentBlock);
      }
    } finally {
      myReadOnlyBlockInformationProvider = previousProvider;
    }
  }