@Contract("null, _ -> null; !null, _ -> !null")
  public static <T extends PsiElement> T findSameElementInCopy(@Nullable T element, @NotNull PsiFile copy) throws IllegalStateException {
    if (element == null) return null;
    if (element instanceof SyntheticElement) {
      //noinspection unchecked
      return (T)((SyntheticElement)element).findSameElementInCopy(copy);
    }
    IntArrayList offsets = new IntArrayList();
    PsiElement cur = element;
    while (!cur.getClass().equals(copy.getClass())) {
      int pos = 0;
      for (PsiElement sibling = cur.getPrevSibling(); sibling != null; sibling = sibling.getPrevSibling()) {
        pos++;
      }
      offsets.add(pos);
      cur = cur.getParent();
      if (cur == null) {
        throw new IllegalStateException("Cannot find parent file; element class: " + element.getClass());
      }
    }

    cur = copy;
    for (int level = offsets.size() - 1; level >= 0; level--) {
      int pos = offsets.get(level);
      cur = cur.getFirstChild();
      if (cur == null) {
        throw new IllegalStateException("File structure differs: no child");
      }
      for (int i = 0; i < pos; i++) {
        cur = cur.getNextSibling();
        if (cur == null) {
          throw new IllegalStateException("File structure differs: number of siblings is less than " + pos);
        }
      }
    }
    if (!cur.getClass().equals(element.getClass())) {
      throw new IllegalStateException("File structure differs: " + cur.getClass() + " != " + element.getClass());
    }
    //noinspection unchecked
    return (T)cur;
  }
@Contract("null, _ -> null; !null, _ -> !null")
  public static <T extends PsiElement> T findSameElementInCopy(@Nullable T element, @NotNull PsiFile copy)