override fun inlineElement()

in src/org/jetbrains/r/refactoring/inline/RInlineAssignmentHandler.kt [46:103]


  override fun inlineElement(project: Project, editor: Editor?, psiElement: PsiElement) {
    if (!CommonRefactoringUtil.checkReadOnlyStatus(project, psiElement)) return

    if (PsiTreeUtil.hasErrorElements(psiElement)) RInlineUtil.showErrorAndExit(project, editor, RBundle.message(
      "inline.assignment.handler.error.rule.with.errors.description")) { return }

    val targetElement = if (editor != null) TargetElementUtil.findTargetElement(editor, TargetElementUtil.getInstance().getAllAccepted()) else null
    if (targetElement is RIdentifierExpression && RPsiUtil.isNamedArgument(targetElement)) return

    if (ReferencesSearch.search(psiElement, LocalSearchScope(RRefactoringUtil.getRScope(psiElement))).findFirst() == null) {
      RInlineUtil.showErrorAndExit(project, editor, RBundle.message(
        "inline.assignment.handler.error.rule.never.used.description")) { return }
    }

    // needed to allow for for current caret element only inlining
    var reference = if (editor != null) TargetElementUtil.findReference(editor) else null
    if (reference != null && reference.element.parent != psiElement) {
      val targets = (reference as RReferenceBase<*>).multiResolve(false).map { it.element }
      if (psiElement !in targets) reference = null
    }

    val assignmentStatement = psiElement as? RAssignmentStatement ?: psiElement.parent as RAssignmentStatement
    val name = assignmentStatement.name
    val controlFlow = RRefactoringUtil.getRScope(assignmentStatement).controlFlow

    val lastDefs = RInlineUtil.getLatestDefs(controlFlow, name, reference?.element)
    if (lastDefs.size > 1) RInlineUtil.showErrorAndExit(project, editor, RBundle.message(
      "inline.assignment.handler.error.no.dominating.definition")) { return }

    val realAssignmentStatement = lastDefs.firstOrNull() as? RAssignmentStatement ?: assignmentStatement
    var refElement = reference?.element as? RIdentifierExpression

    // To prevent inlining left part of assignments
    if (refElement == (refElement?.parent as? RAssignmentStatement)?.assignee) {
      refElement = null
    }

    val isFunction = realAssignmentStatement.isFunctionDeclaration
    if (isFunction) {
      val errorMessage = when {
        hasFunctionInside(realAssignmentStatement) -> RBundle.message("inline.assignment.handler.error.fun.in.fun")
        hasRecursiveCall(realAssignmentStatement) -> RBundle.message("inline.assignment.handler.error.fun.self.ref")
        hasInterruptIfs(project, realAssignmentStatement) -> RBundle.message("inline.assignment.handler.error.interrupts.flow")
        hasUseMethod(realAssignmentStatement) -> RBundle.message("inline.assignment.handler.error.has.use.method")
        else -> null
      }
      if (errorMessage != null) {
        RInlineUtil.showErrorAndExit(project, editor, errorMessage) { return }
      }
    }

    if (ApplicationManager.getApplication().isUnitTestMode) {
      RInlineAssignmentProcessor(project, editor, realAssignmentStatement, refElement, inlineThisOnly, isFunction, removeDefinition).run()
    }
    else {
      RInlineAssignmentDialog(project, editor, isFunction, realAssignmentStatement, refElement).show()
    }
  }