private static @NotNull ModCommand inlineLocal(@NotNull ActionContext context,
                                                 @NotNull PsiLocalVariable local,
                                                 @Nullable PsiReferenceExpression refExpr,
                                                 @NotNull List<PsiReferenceExpression> allRefs,
                                                 @NotNull InlineMode mode) {
    final String localName = local.getName();

    InnerClassUsages innerClassUses = InnerClassUsages.getUsages(local, allRefs);
    final PsiCodeBlock containerBlock = PsiTreeUtil.getParentOfType(local, PsiCodeBlock.class);
    if (containerBlock == null) {
      return ModCommand.error(JavaRefactoringBundle.message("inline.local.variable.declared.outside.cannot.refactor.message"));
    }

    final PsiExpression defToInline;
    try {
      List<PsiElement> innerClassesWithUsages = innerClassUses.innerClassesWithUsages();
      defToInline = getDefToInline(local, innerClassesWithUsages.isEmpty() ? refExpr : innerClassesWithUsages.get(0), containerBlock, true);
      if (defToInline == null) {
        final String key = refExpr == null ? "variable.has.no.initializer" : "variable.has.no.dominating.definition";
        String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, localName));
        return ModCommand.error(message);
      }
    }
    catch (RuntimeException e) {
      return processWrappedAnalysisCanceledException(e);
    }

    List<PsiElement> refsToInlineList = new ArrayList<>();
    boolean simpleInlining = false;
    if (mode == InlineMode.INLINE_ONE && refExpr != null) {
      refsToInlineList.add(refExpr);
    } else {
      if (defToInline == local.getInitializer()) {
        // Do not rely on ref-def analysis in a simple case when we inline an initializer and there are no subsequent writes.
        // This allows inlining in the presense of syntax errors.
        List<PsiReferenceExpression> refs = VariableAccessUtils.getVariableReferences(local);
        if (!ContainerUtil.exists(refs, ref -> PsiUtil.isAccessedForWriting(ref))) {
          simpleInlining = true;
          refsToInlineList.addAll(refs);
        }
      }
      if (!simpleInlining) {
        try {
          Collections.addAll(refsToInlineList, DefUseUtil.getRefs(containerBlock, local, defToInline, true));
        }
        catch (RuntimeException e) {
          return processWrappedAnalysisCanceledException(e);
        }
      }
      for (PsiElement innerClassUsage : innerClassUses.innerClassUsages()) {
        if (!refsToInlineList.contains(innerClassUsage)) {
          refsToInlineList.add(innerClassUsage);
        }
      }
    }
    if (refsToInlineList.isEmpty()) {
      return ModCommand.error(JavaRefactoringBundle.message("variable.is.never.used.before.modification", localName));
    }

    if (mode == InlineMode.CHECK_CONFLICTS) {
      Map<PsiElement, PsiVariable> conflicts = InlineUtil.getChangedBeforeLastAccessMap(defToInline, local);
      if (conflicts.isEmpty()) {
        mode = InlineMode.ASK;
      } else {
        return createConflictChooser(local, refExpr, conflicts);
      }
    }

    if (mode == InlineMode.ASK && refExpr != null && refsToInlineList.size() > 1 && refsToInlineList.contains(refExpr) &&
        EditorSettingsExternalizable.getInstance().isShowInlineLocalDialog()) {
      return createChooser(local, refExpr, refsToInlineList);
    }

    final PsiElement[] refsToInline = PsiUtilCore.toPsiElementArray(refsToInlineList);

    if (refExpr != null && PsiUtil.isAccessedForReading(refExpr) && ArrayUtil.find(refsToInline, refExpr) < 0) {
      final PsiElement[] defs = DefUseUtil.getDefs(containerBlock, local, refExpr);
      LOG.assertTrue(defs.length > 0);
      return ModCommand.highlight(defs).andThen(
        ModCommand.error(
          RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("variable.is.accessed.for.writing", localName))));
    }

    PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(defToInline, PsiTryStatement.class);
    if (tryStatement != null) {
      if (ExceptionUtil.getThrownExceptions(defToInline).isEmpty()) {
        tryStatement = null;
      }
    }
    PsiFile workingFile = local.getContainingFile();
    for (PsiElement ref : refsToInline) {
      final PsiFile otherFile = ref.getContainingFile();
      if (!otherFile.equals(workingFile)) {
        return ModCommand.error(RefactoringBundle.message("variable.is.referenced.in.multiple.files", localName));
      }
      if (tryStatement != null && !PsiTreeUtil.isAncestor(tryStatement, ref, false)) {
        return ModCommand.error(JavaRefactoringBundle.message("inline.local.unable.try.catch.warning.message"));
      }
    }

    for (final PsiElement ref : refsToInline) {
      final PsiElement[] defs = DefUseUtil.getDefs(containerBlock, local, ref);
      boolean isSameDefinition = true;
      for (PsiElement def : defs) {
        isSameDefinition &= isSameDefinition(def, defToInline);
      }
      if (!isSameDefinition) {
        String message =
          RefactoringBundle.getCannotRefactorMessage(
            RefactoringBundle.message("variable.is.accessed.for.writing.and.used.with.inlined", localName));
        return ModCommand.highlight(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES, defs)
          .andThen(ModCommand.highlight(ref))
          .andThen(ModCommand.error(message));
      }
    }

    final PsiElement writeAccess = checkRefsInAugmentedAssignmentOrUnaryModified(refsToInline, defToInline);
    if (writeAccess != null && !
      (writeAccess.getParent() instanceof PsiAssignmentExpression assignment && assignment.getLExpression() == writeAccess &&
       ArrayUtil.contains(writeAccess, refsToInline))) {
      String message =
        RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("variable.is.accessed.for.writing", localName));
      return ModCommand.highlight(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES, writeAccess)
        .andThen(ModCommand.error(message));
    }

    if (ContainerUtil.exists(refsToInline, ref -> ref.getParent() instanceof PsiResourceExpression)) {
      return ModCommand.error(
        RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("inline.local.used.as.resource.cannot.refactor.message")));
    }
    Project project = context.project();

    boolean inlineAll = mode != InlineMode.INLINE_ONE;
    return ModCommand.psiUpdate(context, updater -> {
      PsiExpression writableDef = updater.getWritable(defToInline);
      PsiLocalVariable writableLocal = updater.getWritable(local);
      List<PsiElement> writableRefs = StreamEx.of(refsToInline).without(writeAccess).map(updater::getWritable).toList();
      PsiElement writableWrite = updater.getWritable(writeAccess);
      List<SmartPsiElementPointer<PsiExpression>> pointers = inlineOccurrences(project, writableLocal, writableDef, writableRefs);
      if (writableWrite != null && writableWrite.isValid()) {
        PsiAssignmentExpression newAssignment =
          PsiReplacementUtil.replaceOperatorAssignmentWithAssignmentExpression((PsiAssignmentExpression)writableWrite.getParent());
        for (PsiReferenceExpression ref : VariableAccessUtils.getVariableReferences(writableLocal, newAssignment.getRExpression())) {
          pointers.add(SmartPointerManager.createPointer(InlineUtil.inlineVariable(local, defToInline, ref)));
        }
      }
      if (inlineAll) {
        if (!isInliningVariableInitializer(writableDef)) {
          deleteInitializer(writableDef);
        }
        else {
          writableDef.delete();
        }
      }

      if (inlineAll &&
          !VariableAccessUtils.variableIsUsed(writableLocal, PsiUtil.getVariableCodeBlock(writableLocal, null))) {
        writableLocal.normalizeDeclaration();
        new CommentTracker().deleteAndRestoreComments(writableLocal);
      }

      highlightOccurrences(updater, pointers);

      for (SmartPsiElementPointer<PsiExpression> expr : pointers) {
        CommonJavaRefactoringUtil.tryToInlineArrayCreationForVarargs(expr.getElement());
      }
    });
  }
private static @NotNull ModCommand inlineLocal(@NotNull ActionContext context,
                                                 @NotNull PsiLocalVariable local,
                                                 @Nullable PsiReferenceExpression refExpr,
                                                 @NotNull List<PsiReferenceExpression> allRefs,
                                                 @NotNull InlineMode mode)