static boolean processOffsets(@NotNull ASTNode node,
                                int @NotNull [] offsetsInNode,
                                @NotNull ProgressIndicator progress,
                                @NotNull NodeTextOccurrenceProcessor processor) {
    final int scopeStartOffset = node.getStartOffset();
    // helps to avoid full tree rescan in subsequent com.intellij.lang.ASTNode#findLeafElementAt calls (O(n) instead of O(n^2))
    ASTNode lastElement = null;
    for (int offset : offsetsInNode) {
      progress.checkCanceled();
      final ASTNode leafNode = findNextLeafElementAt(node, lastElement, offset);
      if (leafNode == null) {
        PsiElement psi = node.getPsi();
        LOG.error("Cannot find leaf: node=" + node + "; psi= " + psi + "; language=" + (psi==null?null:psi.getLanguage())+
                  "; offset=" + offset + "; lastElement=" + lastElement);
        continue;
      }
      final int offsetInLeaf = offset - leafNode.getStartOffset() + scopeStartOffset;
      if (offsetInLeaf < 0) {
        throw new AssertionError("offset=" + offset + "; scopeStartOffset=" + scopeStartOffset + "; node=" + node);
      }
      if (!processor.execute(leafNode, offsetInLeaf)) {
        return false;
      }
      lastElement = leafNode;
    }
    return true;
  }
static boolean processOffsets(@NotNull ASTNode node,
                                int @NotNull [] offsetsInNode,
                                @NotNull ProgressIndicator progress,
                                @NotNull NodeTextOccurrenceProcessor processor)