public boolean invokeImpl(final Project project,
                            final PsiExpression expr,
                            @Nullable PsiElement targetContainer,
                            @Nullable JavaReplaceChoice replaceChoice,
                            final Editor editor) {
    if (expr != null) {
      final String errorMessage = IntroduceVariableUtil.getErrorMessage(expr);
      if (errorMessage != null) {
        showErrorMessage(project, editor, RefactoringBundle.getCannotRefactorMessage(errorMessage));
        return false;
      }
    }

    if (expr != null && expr.getParent() instanceof PsiExpressionStatement) {
      FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.introduceVariable.incompleteStatement");
    }
    if (IntroduceVariableUtil.LOG.isDebugEnabled()) {
      IntroduceVariableUtil.LOG.debug("expression:" + expr);
    }

    if (expr == null || !expr.isPhysical()) {
      if (ReassignVariableUtil.reassign(editor)) return false;
      if (expr == null) {
        String message = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("selected.block.should.represent.an.expression"));
        showErrorMessage(project, editor, message);
        return false;
      }
    }

    String enumInSwitchError = RefactoringUtil.checkEnumConstantInSwitchLabel(expr);
    if (enumInSwitchError != null) {
      showErrorMessage(project, editor, enumInSwitchError);
      return false;
    }


    DumbService dumbService = DumbService.getInstance(project);
    final PsiType originalType =
      dumbService.computeWithAlternativeResolveEnabled(() -> CommonJavaRefactoringUtil.getTypeByExpressionWithExpectedType(expr));
    if (originalType == null || LambdaUtil.notInferredType(originalType)) {
      String message = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("unknown.expression.type"));
      showErrorMessage(project, editor, message);
      return false;
    }

    if (PsiTypes.voidType().equals(originalType)) {
      String message = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("selected.expression.has.void.type"));
      showErrorMessage(project, editor, message);
      return false;
    }

    try {
      String typeText = DumbService.getInstance(project)
        .computeWithAlternativeResolveEnabled(() -> GenericsUtil.getVariableTypeByExpressionType(originalType).getCanonicalText());
      JavaPsiFacade.getElementFactory(project).createTypeElementFromText(typeText, expr);
    }
    catch (IncorrectOperationException ignore) {
      String message = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("unknown.expression.type"));
      showErrorMessage(project, editor, message);
      return false;
    }

    for (PsiPatternVariable variable : JavaPsiPatternUtil.getExposedPatternVariables(expr)) {
      if (ContainerUtil.exists(VariableAccessUtils.getVariableReferences(variable),
                               ref -> !PsiTreeUtil.isAncestor(expr, ref, true))) {
        String message = RefactoringBundle.getCannotRefactorMessage(
          JavaRefactoringBundle.message("selected.expression.introduces.pattern.variable", variable.getName()));
        showErrorMessage(project, editor, message);
        return false;
      }
    }

    final PsiElement anchorStatement = getAnchor(expr);

    PsiElement tempContainer = checkAnchorStatement(project, editor, anchorStatement);
    if (tempContainer == null) return false;

    final PsiFile file = anchorStatement.getContainingFile();
    IntroduceVariableUtil.LOG.assertTrue(file != null, "expr.getContainingFile() == null");
    final PsiElement nameSuggestionContext = editor == null ? null : file.findElementAt(editor.getCaretModel().getOffset());
    final RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.INSTANCE.forContext(expr);
    final boolean isInplaceAvailableOnDataContext =
      supportProvider != null &&
      editor.getSettings().isVariableInplaceRenameEnabled() &&
      supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) &&
      !isInJspHolderMethod(expr);

    if (isInplaceAvailableOnDataContext) {
      final MultiMap<PsiElement, String> conflicts = new MultiMap<>();
      checkInLoopCondition(expr, conflicts);
      if (!conflicts.isEmpty()) {
        showErrorMessage(project, editor, StringUtil.join(new TreeSet<>(conflicts.values()), "<br>"));
        return false;
      }
    }

    final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer);
    final PsiExpression[] occurrences = occurrenceManager.getOccurrences();

    OccurrencesInfo occurrencesInfo = new OccurrencesInfo(occurrences);

    if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return false;

    final LinkedHashMap<JavaReplaceChoice, List<PsiExpression>> occurrencesMap = occurrencesInfo.buildOccurrencesMap(expr);

    class IntroduceVariablePass implements Consumer<JavaReplaceChoice> {
      boolean wasSucceed = true;

      @Override
      public void accept(JavaReplaceChoice choice) {
        Consumer<JavaReplaceChoice> dialogIntroduce = c -> CommandProcessor.getInstance().executeCommand(project, () -> introduce(c), getRefactoringName(), null);
        if (choice == null) {
          dialogIntroduce.accept(null);
        }
        else {
          SlowOperations.allowSlowOperations(
            () -> dumbService.runWithAlternativeResolveEnabled(
              () -> inplaceIntroduce(project, editor, choice, targetContainer, occurrenceManager, originalType, dialogIntroduce)));
        }
      }

      private void introduce(@Nullable JavaReplaceChoice choice) {
        if (!anchorStatement.isValid()) {
          return;
        }
        final Editor topLevelEditor;
        if (!InjectedLanguageManager.getInstance(project).isInjectedFragment(anchorStatement.getContainingFile())) {
          topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(editor);
        }
        else {
          topLevelEditor = editor;
        }

        PsiVariable variable = null;
        try {
          boolean hasWriteAccess = occurrencesInfo.myHasWriteAccess;
          final InputValidator validator = new InputValidator(IntroduceVariableBase.this, project, occurrenceManager);

          final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences);
          boolean inFinalContext = occurrenceManager.isInFinalContext();
          final IntroduceVariableSettings settings =
            getSettings(project, topLevelEditor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator,
                        anchorStatement, choice);
          if (!settings.isOK()) {
            wasSucceed = false;
            return;
          }
          JavaReplaceChoice finalChoice = settings.getReplaceChoice();
          PsiExpression[] selectedOccurrences = finalChoice.filter(occurrenceManager);
          if (selectedOccurrences.length == 0) {
            showErrorMessage(project, editor, JavaRefactoringBundle.message("introduce.variable.no.matching.occurrences"));
            wasSucceed = false;
            return;
          }
          final PsiElement chosenAnchor = getAnchor(selectedOccurrences);
          if (chosenAnchor == null) {
            String text = file.getText();
            String textWithOccurrences = StreamEx.of(selectedOccurrences)
              .map(e -> getPhysicalElement(e).getTextRange())
              .flatMapToEntry(range -> EntryStream.of(range.getStartOffset(), "[", range.getEndOffset(), "]").toMap())
              .sortedBy(Map.Entry::getKey)
              .prepend(0, "")
              .append(text.length(), "")
              .map(Function.identity())
              .pairMap((prev, next) -> text.substring(prev.getKey(), next.getKey()) + next.getValue())
              .joining();
            IntroduceVariableUtil.LOG.error("Unable to find anchor for a new variable; selectedOccurrences.length = " + selectedOccurrences.length,
                                            new Attachment("source.java", textWithOccurrences));
            return;
          }

          final RefactoringEventData beforeData = new RefactoringEventData();
          beforeData.addElement(expr);
          project.getMessageBus()
            .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(REFACTORING_ID, beforeData);

          variable = VariableExtractor.introduce(project, expr, topLevelEditor, chosenAnchor, selectedOccurrences, settings);
        }
        finally {
          final RefactoringEventData afterData = new RefactoringEventData();
          afterData.addElement(variable);
          project.getMessageBus()
            .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringDone(REFACTORING_ID, afterData);
        }
      }
    }
    final IntroduceVariablePass callback = new IntroduceVariablePass();

    if (replaceChoice != null) {
      callback.accept(findChoice(occurrencesMap, replaceChoice));
    }
    else if (!isInplaceAvailableOnDataContext) {
      callback.accept(null);
    }
    else {
      String title = occurrencesInfo.myChainMethodName != null && occurrences.length == 1
                     ? JavaRefactoringBundle.message("replace.lambda.chain.detected")
                     : RefactoringBundle.message("replace.multiple.occurrences.found");
      createOccurrencesChooser(editor).showChooser(occurrencesMap, title, callback);
    }
    return callback.wasSucceed;
  }
public boolean invokeImpl(final Project project,
                            final PsiExpression expr,
                            @Nullable PsiElement targetContainer,
                            @Nullable JavaReplaceChoice replaceChoice,
                            final Editor editor)