/**
   * Return a list of all ancestors of this node. The first node of list is the root and the last is
   * the parent of this node.
   *
   * @param <T>
   * @param t
   * @return
   */
  @NonNull
  public static List<? extends ParseTree> getAncestors(@NonNull ParseTree t) {
    if (t.getParent() == null) {
      return Collections.emptyList();
    }

    List<ParseTree> ancestors = new ArrayList<>();
    t = t.getParent();
    while (t != null) {
      ancestors.add(0, t); // insert at start
      t = t.getParent();
    }

    return ancestors;
  }
  /**
   * Converts ParseTree (that is generated by ANTLRv4) to DetailNode tree.
   *
   * @param parseTreeNode root node of ParseTree
   * @return root of DetailNode tree
   */
  private DetailNode convertParseTreeToDetailNode(ParseTree parseTreeNode) {
    final JavadocNodeImpl rootJavadocNode = createRootJavadocNode(parseTreeNode);

    JavadocNodeImpl currentJavadocParent = rootJavadocNode;
    ParseTree parseTreeParent = parseTreeNode;

    while (currentJavadocParent != null) {
      // remove unnecessary children tokens
      if (currentJavadocParent.getType() == JavadocTokenTypes.TEXT) {
        currentJavadocParent.setChildren((DetailNode[]) JavadocNodeImpl.EMPTY_DETAIL_NODE_ARRAY);
      }

      final JavadocNodeImpl[] children = (JavadocNodeImpl[]) currentJavadocParent.getChildren();

      insertChildrenNodes(children, parseTreeParent);

      if (children.length > 0) {
        currentJavadocParent = children[0];
        parseTreeParent = parseTreeParent.getChild(0);
      } else {
        JavadocNodeImpl nextJavadocSibling =
            (JavadocNodeImpl) JavadocUtils.getNextSibling(currentJavadocParent);

        ParseTree nextParseTreeSibling = getNextSibling(parseTreeParent);

        if (nextJavadocSibling == null) {
          JavadocNodeImpl tempJavadocParent = (JavadocNodeImpl) currentJavadocParent.getParent();

          ParseTree tempParseTreeParent = parseTreeParent.getParent();

          while (nextJavadocSibling == null && tempJavadocParent != null) {

            nextJavadocSibling = (JavadocNodeImpl) JavadocUtils.getNextSibling(tempJavadocParent);

            nextParseTreeSibling = getNextSibling(tempParseTreeParent);

            tempJavadocParent = (JavadocNodeImpl) tempJavadocParent.getParent();
            tempParseTreeParent = tempParseTreeParent.getParent();
          }
        }
        currentJavadocParent = nextJavadocSibling;
        parseTreeParent = nextParseTreeSibling;
      }
    }

    return rootJavadocNode;
  }
  /**
   * Gets whether or not {@code a} is an ancestor of or equal to {@code b}.
   *
   * @param a The first tree.
   * @param b The second tree.
   * @return {@code true} if {@code a} is an ancestor of or is equal to {@code b}, otherwise {@code
   *     false}.
   */
  public static boolean isAncestorOf(@NonNull ParseTree a, @NonNull ParseTree b) {
    for (ParseTree current = b; current != null; current = current.getParent()) {
      if (current.equals(a)) {
        return true;
      }
    }

    return false;
  }
  /**
   * Gets next sibling of ParseTree node.
   *
   * @param node ParseTree node
   * @return next sibling of ParseTree node.
   */
  private static ParseTree getNextSibling(ParseTree node) {
    ParseTree nextSibling = null;

    if (node.getParent() != null) {
      final ParseTree parent = node.getParent();
      final int childCount = parent.getChildCount();

      int index = 0;
      while (true) {
        final ParseTree currentNode = parent.getChild(index);
        if (currentNode.equals(node)) {
          if (index != childCount - 1) {
            nextSibling = parent.getChild(index + 1);
          }
          break;
        }
        index++;
      }
    }
    return nextSibling;
  }
  @CheckForNull
  public static RuleNode findAncestor(@NonNull ParseTree tree, int ruleIndex) {
    for (ParseTree current = tree; current != null; current = current.getParent()) {
      if (!(current instanceof RuleNode)) {
        continue;
      }

      RuleNode ruleNode = (RuleNode) current;
      if (ruleNode.getRuleContext().getRuleIndex() == ruleIndex) {
        return ruleNode;
      }
    }

    return null;
  }
  @CheckForNull
  public static <ContextClass> ContextClass findAncestor(
      @NonNull ParseTree tree, @NonNull Class<ContextClass> nodeType) {
    for (ParseTree current = tree; current != null; current = current.getParent()) {
      if (!(current instanceof RuleNode)) {
        continue;
      }

      RuleNode ruleNode = (RuleNode) current;
      RuleContext ruleContext = ruleNode.getRuleContext();
      if (nodeType.isInstance(ruleContext)) {
        return nodeType.cast(ruleContext);
      }
    }

    return null;
  }