public static @NotNull UExpression goUp(@NotNull UExpression expression,
                                          boolean allowStringTransformation,
                                          @NotNull RestrictionInfoFactory<?> factory) {
    UExpression parent = expression;
    while (true) {
      UElement parentElement = parent.getUastParent();
      if (parentElement instanceof ULocalVariable && parentElement.getUastParent() instanceof UDeclarationsExpression) {
        // Kotlin has strange hierarchy for elvis operator
        UExpressionList elvis = ObjectUtils.tryCast(parentElement.getUastParent().getUastParent(), UExpressionList.class);
        if (elvis != null) {
          parentElement = elvis;
        }
      }
      if (parentElement instanceof UExpressionList) {
        UExpression lastExpression = ContainerUtil.getLastItem(((UExpressionList)parentElement).getExpressions());
        if (lastExpression != null && AnnotationContext.expressionsAreEquivalent(parent, lastExpression)) {
          // Result of expression list is the last expression in the list in Kotlin
          parentElement = parentElement.getUastParent();
        }
      }
      UExpression next = ObjectUtils.tryCast(parentElement, UExpression.class);
      if (next == null || next instanceof UNamedExpression) return parent;
      if (next instanceof USwitchClauseExpression switchClause) {
        List<UExpression> caseValues = ContainerUtil.map(switchClause.getCaseValues(), caseValue -> AnnotationContext.normalize(caseValue));
        if (caseValues.contains(AnnotationContext.normalize(parent))) return parent;
        UExpressionList switchBody = ObjectUtils.tryCast(next.getUastParent(), UExpressionList.class);
        if (switchBody == null) return parent;
        USwitchExpression switchExpression = ObjectUtils.tryCast(switchBody.getUastParent(), USwitchExpression.class);
        if (switchExpression == null) return parent;
        next = switchExpression;
      }
      ULambdaExpression lambda = ObjectUtils.tryCast(next, ULambdaExpression.class);
      if (next instanceof UReturnExpression) {
        lambda = ObjectUtils.tryCast(((UReturnExpression)next).getJumpTarget(), ULambdaExpression.class);
        if (lambda == null) return parent;
      }
      if (lambda != null) {
        UCallExpression uastParent = ObjectUtils.tryCast(lambda.getUastParent(), UCallExpression.class);
        if (uastParent == null) return parent;
        PsiMethod method = uastParent.resolve();
        if (method == null || !isPassthroughMethod(method, uastParent, lambda, factory)) return parent;
        next = uastParent;
      }
      if (next instanceof UQualifiedReferenceExpression && !TypeUtils.isJavaLangString(next.getExpressionType())
          && !TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_CHAR_SEQUENCE, next.getExpressionType())) {
        return parent;
      }
      if (next instanceof UPolyadicExpression &&
          (!allowStringTransformation || ((UPolyadicExpression)next).getOperator() != UastBinaryOperator.PLUS)) {
        return parent;
      }
      if (next instanceof UCallExpression) {
        if (!UastExpressionUtils.isArrayInitializer(next) && !UastExpressionUtils.isNewArrayWithInitializer(next)) {
          PsiMethod method = ((UCallExpression)next).resolve();
          boolean shouldGoThroughCall =
            TypeUtils.isJavaLangString(next.getExpressionType()) &&
            (allowStringTransformation && isStringProcessingMethod(method, factory) ||
             isPassthroughMethod(method, (UCallExpression)next, parent, factory));
          if (!shouldGoThroughCall) return parent;
        }
      }
      if (next instanceof UIfExpression && AnnotationContext.expressionsAreEquivalent(parent, ((UIfExpression)next).getCondition())) {
        return parent;
      }
      if (next instanceof USwitchExpression) {
        final UExpression condExpression = ((USwitchExpression)next).getExpression();
        if (condExpression != null && AnnotationContext.expressionsAreEquivalent(parent, condExpression)) {
          return parent;
        }
      }
      if (next instanceof UArrayAccessExpression) {
        return parent;
      }
      parent = next;
    }
  }
public static @NotNull UExpression goUp(@NotNull UExpression expression,
                                          boolean allowStringTransformation,
                                          @NotNull RestrictionInfoFactory<?> factory)