private boolean isMovable(PsiExpression expression) {
    expression = PsiUtil.skipParenthesizedExprDown(expression);
    if (expression == null) {
      return true;
    }
    if (PsiUtil.isConstantExpression(expression) || ExpressionUtils.isNullLiteral(expression)) {
      return true;
    }
    if (expression instanceof PsiArrayInitializerExpression arrayInitializerExpression) {
      for (PsiExpression initializer : arrayInitializerExpression.getInitializers()) {
        if (!isMovable(initializer)) {
          return false;
        }
      }
      return true;
    }
    if (expression instanceof PsiNewExpression newExpression) {
      final PsiExpression[] arrayDimensions = newExpression.getArrayDimensions();
      if (arrayDimensions.length > 0) {
        for (PsiExpression arrayDimension : arrayDimensions) {
          if (!isMovable(arrayDimension)) {
            return false;
          }
        }
        return true;
      }
      final PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer();
      if (arrayInitializer != null) {
        final PsiExpression[] initializers = arrayInitializer.getInitializers();
        for (final PsiExpression initializerExpression : initializers) {
          if (!isMovable(initializerExpression)) {
            return false;
          }
        }
        return true;
      }
      final PsiType type = newExpression.getType();
      if (type == null) {
        return false;
      }
      else if (!m_allowConstructorAsInitializer) {
        if (!isAllowedType(type)) {
          return false;
        }
      }
      final PsiExpressionList argumentList = newExpression.getArgumentList();
      if (argumentList == null) {
        return false;
      }
      final PsiExpression[] expressions = argumentList.getExpressions();
      for (final PsiExpression argumentExpression : expressions) {
        if (!isMovable(argumentExpression)) {
          return false;
        }
      }
      return true;
    }
    if (expression instanceof PsiReferenceExpression referenceExpression) {
      final PsiExpression qualifier = referenceExpression.getQualifierExpression();
      if (!isMovable(qualifier)) {
        return false;
      }
      final PsiElement target = referenceExpression.resolve();
      if (target instanceof PsiClass) {
        return true;
      }
      if (!(target instanceof PsiVariable variable)) {
        return false;
      }
      if (!ClassUtils.isImmutable(variable.getType()) && !CollectionUtils.isEmptyArray(variable)) {
        return false;
      }
      if (variable.hasModifierProperty(PsiModifier.FINAL)) {
        return true;
      }
      final PsiElement context = PsiUtil.getVariableCodeBlock(variable, referenceExpression);
      return context != null && !(variable instanceof PsiField) &&
             HighlightControlFlowUtil.isEffectivelyFinal(variable, context, referenceExpression);
    }
    if (expression instanceof PsiPolyadicExpression polyadicExpression) {
      for (PsiExpression operand : polyadicExpression.getOperands()) {
        if (!isMovable(operand)) {
          return false;
        }
      }
      return true;
    }
    if (expression instanceof PsiMethodCallExpression methodCallExpression) {
      if (!isAllowedType(expression.getType())) {
        return false;
      }
      final PsiMethod method = methodCallExpression.resolveMethod();
      if (!isAllowedMethod(method)) {
        return false;
      }
      final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
      final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
      if (qualifierExpression != null) {
        if (!isMovable(qualifierExpression)) {
          return false;
        }
      }
      else {
        if (method.getContainingFile() != expression.getContainingFile()) {
          return false;
        }
        final PsiClass aClass = method.getContainingClass();
        if (aClass == null || !ClassUtils.isImmutableClass(aClass)) {
          return false;
        }
      }
      final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
      for (PsiExpression argument : argumentList.getExpressions()) {
        if (!isMovable(argument)) {
          return false;
        }
      }
      return true;
    }
    return false;
  }
private boolean isMovable(PsiExpression expression)