Fix ExtractDeclarationFromCurrentFileIntention assertion
Refactorings should be invoked inside transaction 'exception occurs when extracting sealed class from file with the same name assertion failed when refactoring tries to use MoveKotlinTopLevelDeclarationsDialog + move refactorings + small improvement of applicability range calculation Fixed #KT-33357
This commit is contained in:
+59
-41
@@ -11,7 +11,10 @@ import com.intellij.codeInsight.navigation.NavigationUtil
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -22,7 +25,9 @@ import org.jetbrains.kotlin.idea.core.moveCaret
|
||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
||||
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.showWithTransaction
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
@@ -47,11 +52,10 @@ class ExtractDeclarationFromCurrentFileIntention :
|
||||
}
|
||||
|
||||
override fun applicabilityRange(element: KtClassOrObject): TextRange? {
|
||||
if (element.name == null) return null
|
||||
element.name ?: return null
|
||||
if (element.parent !is KtFile) return null
|
||||
if (element.hasModifier(KtTokens.PRIVATE_KEYWORD)) return null
|
||||
if (element.containingKtFile.declarations.size == 1) return null
|
||||
|
||||
if (element.containingKtFile.run { declarations.size == 1 || containingDirectory === null }) return null
|
||||
val extraClassesToMove = element.tryGetExtraClassesToMove() ?: return null
|
||||
|
||||
val startOffset = when (element) {
|
||||
@@ -71,7 +75,7 @@ class ExtractDeclarationFromCurrentFileIntention :
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun applyTo(element: KtClassOrObject, editor: Editor?) {
|
||||
if (editor == null) throw IllegalArgumentException("This intention requires an editor")
|
||||
requireNotNull(editor) { "This intention requires an editor" }
|
||||
val file = element.containingKtFile
|
||||
val project = file.project
|
||||
val originalOffset = editor.caretModel.offset - element.startOffset
|
||||
@@ -79,38 +83,17 @@ class ExtractDeclarationFromCurrentFileIntention :
|
||||
val packageName = file.packageFqName
|
||||
val targetFileName = "${element.name}.kt"
|
||||
val targetFile = directory.findFile(targetFileName)
|
||||
if (targetFile != null) {
|
||||
|
||||
if (targetFile !== null) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
throw CommonRefactoringUtil.RefactoringErrorHintException("File $targetFileName already exists")
|
||||
}
|
||||
|
||||
// If automatic move is not possible, fall back to full-fledged Move Declarations refactoring
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
MoveKotlinTopLevelDeclarationsDialog(
|
||||
project,
|
||||
setOf(element),
|
||||
packageName.asString(),
|
||||
directory,
|
||||
targetFile as? KtFile,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
MoveCallback {
|
||||
runBlocking {
|
||||
withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) {
|
||||
OptimizeImportsProcessor(
|
||||
project,
|
||||
file
|
||||
).run()
|
||||
}
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
runFullFledgedMoveRefactoring(project, element, packageName, directory, targetFile, file)
|
||||
return
|
||||
}
|
||||
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory, null) {
|
||||
|
||||
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory, targetFile = null) {
|
||||
createKotlinFile(targetFileName, directory, packageName.asString())
|
||||
}
|
||||
|
||||
@@ -120,22 +103,57 @@ class ExtractDeclarationFromCurrentFileIntention :
|
||||
}
|
||||
?: MoveSource(element)
|
||||
|
||||
val moveCallBack = MoveCallback {
|
||||
val newFile = directory.findFile(targetFileName) as KtFile
|
||||
val newDeclaration = newFile.declarations.first()
|
||||
NavigationUtil.activateFileWithPsiElement(newFile)
|
||||
FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset)
|
||||
runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } }
|
||||
}
|
||||
|
||||
val descriptor = MoveDeclarationsDescriptor(
|
||||
project = project,
|
||||
moveSource = moveSource,
|
||||
moveTarget = moveTarget,
|
||||
delegate = MoveDeclarationsDelegate.TopLevel,
|
||||
project,
|
||||
moveSource,
|
||||
moveTarget,
|
||||
MoveDeclarationsDelegate.TopLevel,
|
||||
searchInCommentsAndStrings = false,
|
||||
searchInNonCode = false,
|
||||
moveCallback = MoveCallback {
|
||||
val newFile = directory.findFile(targetFileName) as KtFile
|
||||
val newDeclaration = newFile.declarations.first()
|
||||
NavigationUtil.activateFileWithPsiElement(newFile)
|
||||
FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset)
|
||||
runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } }
|
||||
}
|
||||
moveCallback = moveCallBack
|
||||
)
|
||||
|
||||
MoveKotlinDeclarationsProcessor(descriptor).run()
|
||||
}
|
||||
|
||||
private fun runFullFledgedMoveRefactoring(
|
||||
project: Project,
|
||||
element: KtClassOrObject,
|
||||
packageName: FqName,
|
||||
directory: PsiDirectory,
|
||||
targetFile: PsiFile?,
|
||||
file: KtFile
|
||||
) {
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
|
||||
val callBack = MoveCallback {
|
||||
runBlocking {
|
||||
withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) {
|
||||
OptimizeImportsProcessor(project, file).run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoveKotlinTopLevelDeclarationsDialog(
|
||||
project,
|
||||
setOf(element),
|
||||
packageName.asString(),
|
||||
directory,
|
||||
targetFile as? KtFile,
|
||||
/* moveToPackage = */ true,
|
||||
/* searchInComments = */ true,
|
||||
/* searchForTextOccurrences = */ true,
|
||||
/* deleteEmptySourceFiles = */ true,
|
||||
callBack
|
||||
).showWithTransaction()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user