Drop resolve on 'collectTransferableData' and reworked MoveDeclarations QuickFix (EA-210670)
This commit is contained in:
+3
-4
@@ -29,7 +29,6 @@ import com.intellij.psi.PsiComment
|
|||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.KtClassBody
|
import org.jetbrains.kotlin.psi.KtClassBody
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
@@ -73,10 +72,10 @@ class MoveDeclarationsCopyPasteProcessor : CopyPastePostProcessor<MoveDeclaratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (declarations.any { it.name == null }) return emptyList()
|
if (declarations.any { it.name == null }) return emptyList()
|
||||||
val declarationNames = declarations.asSequence().map { it.name!! }.toSet()
|
|
||||||
|
|
||||||
val stubTexts = declarations.map { MoveDeclarationsTransferableData.STUB_RENDERER.render(it.unsafeResolveToDescriptor()) }
|
val imports = file.importDirectives.map { it.text }
|
||||||
return listOf(MoveDeclarationsTransferableData(file.virtualFile.url, sourceObjectFqName, stubTexts, declarationNames))
|
|
||||||
|
return listOf(MoveDeclarationsTransferableData(file.virtualFile.url, sourceObjectFqName, declarations, imports))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun extractTransferableData(content: Transferable): List<MoveDeclarationsTransferableData> {
|
override fun extractTransferableData(content: Transferable): List<MoveDeclarationsTransferableData> {
|
||||||
|
|||||||
+82
-23
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
|||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.runRefactoringAndKeepDelayedRequests
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.runRefactoringAndKeepDelayedRequests
|
||||||
import org.jetbrains.kotlin.idea.core.util.range
|
import org.jetbrains.kotlin.idea.core.util.range
|
||||||
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
|
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsTransferableData.Companion.STUB_RENDERER
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
@@ -42,7 +43,8 @@ class MoveDeclarationsProcessor(
|
|||||||
private val sourceContainer: KtDeclarationContainer,
|
private val sourceContainer: KtDeclarationContainer,
|
||||||
private val targetPsiFile: KtFile,
|
private val targetPsiFile: KtFile,
|
||||||
val pastedDeclarations: List<KtNamedDeclaration>,
|
val pastedDeclarations: List<KtNamedDeclaration>,
|
||||||
private val stubTexts: List<String>
|
private val imports: List<String>,
|
||||||
|
private val sourceDeclarationsText: List<String>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun build(editor: Editor, cookie: MoveDeclarationsEditorCookie): MoveDeclarationsProcessor? {
|
fun build(editor: Editor, cookie: MoveDeclarationsEditorCookie): MoveDeclarationsProcessor? {
|
||||||
@@ -74,11 +76,17 @@ class MoveDeclarationsProcessor(
|
|||||||
if (sourceContainer == sourcePsiFile && sourcePsiFile.packageFqName == targetPsiFile.packageFqName) return null
|
if (sourceContainer == sourcePsiFile && sourcePsiFile.packageFqName == targetPsiFile.packageFqName) return null
|
||||||
|
|
||||||
// check that declarations were cut (not copied)
|
// check that declarations were cut (not copied)
|
||||||
val filteredDeclarations = sourceContainer.declarations.filter { it.name in data.declarationNames }
|
val filteredDeclarations = sourceContainer.declarations.filter { it in data.declarations }
|
||||||
val stubs = data.stubTexts.toSet()
|
if (filteredDeclarations.isNotEmpty()) return null
|
||||||
if (filteredDeclarations.any { MoveDeclarationsTransferableData.STUB_RENDERER.render(it.unsafeResolveToDescriptor()) in stubs }) return null
|
|
||||||
|
|
||||||
return MoveDeclarationsProcessor(project, sourceContainer, targetPsiFile, declarations, data.stubTexts)
|
return MoveDeclarationsProcessor(
|
||||||
|
project,
|
||||||
|
sourceContainer,
|
||||||
|
targetPsiFile,
|
||||||
|
declarations,
|
||||||
|
data.imports,
|
||||||
|
data.declarations.map { it.text }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,16 +100,47 @@ class MoveDeclarationsProcessor(
|
|||||||
val commandName = "Usage update"
|
val commandName = "Usage update"
|
||||||
val commandGroupId = Any() // we need to group both commands for undo
|
val commandGroupId = Any() // we need to group both commands for undo
|
||||||
|
|
||||||
val insertedRange = project.executeWriteCommand<RangeMarker>(commandName, commandGroupId) {
|
// temporary revert imports to the state before they have been changed
|
||||||
//TODO: can stub declarations interfere with pasted declarations? I could not find such cases
|
val importsSubstitution = if (sourcePsiFile.importDirectives.size != imports.size) {
|
||||||
insertStubDeclarations()
|
val startOffset = sourcePsiFile.importDirectives.map { it.startOffset }.min() ?: 0
|
||||||
|
val endOffset = sourcePsiFile.importDirectives.map { it.endOffset }.min() ?: 0
|
||||||
|
val importsDeclarationsText = sourceDocument.getText(TextRange(startOffset, endOffset))
|
||||||
|
|
||||||
|
val tempImportsText = imports.joinToString(separator = "\n")
|
||||||
|
project.executeWriteCommand(commandName, commandGroupId) {
|
||||||
|
sourceDocument.deleteString(startOffset, endOffset)
|
||||||
|
sourceDocument.insertString(startOffset, tempImportsText)
|
||||||
|
}
|
||||||
|
psiDocumentManager.commitDocument(sourceDocument)
|
||||||
|
|
||||||
|
ImportsSubstitution(importsDeclarationsText, tempImportsText, startOffset)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val tmpRangeAndDeclarations = insertStubDeclarations(commandName, commandGroupId, sourceDeclarationsText)
|
||||||
|
assert(tmpRangeAndDeclarations.second.size == pastedDeclarations.size)
|
||||||
|
|
||||||
|
val stubTexts = tmpRangeAndDeclarations.second.map { STUB_RENDERER.render(it.unsafeResolveToDescriptor()) }
|
||||||
|
|
||||||
|
project.executeWriteCommand(commandName, commandGroupId) {
|
||||||
|
sourceDocument.deleteString(tmpRangeAndDeclarations.first.startOffset, tmpRangeAndDeclarations.first.endOffset)
|
||||||
}
|
}
|
||||||
psiDocumentManager.commitDocument(sourceDocument)
|
psiDocumentManager.commitDocument(sourceDocument)
|
||||||
|
|
||||||
val stubDeclarations = MoveDeclarationsCopyPasteProcessor.rangeToDeclarations(sourcePsiFile, insertedRange.startOffset, insertedRange.endOffset)
|
val stubRangeAndDeclarations = insertStubDeclarations(commandName, commandGroupId, stubTexts)
|
||||||
assert(stubDeclarations.size == pastedDeclarations.size) //TODO: can they ever differ?
|
val stubDeclarations = stubRangeAndDeclarations.second
|
||||||
|
assert(stubDeclarations.size == pastedDeclarations.size)
|
||||||
|
|
||||||
val mover = object: Mover {
|
importsSubstitution?.let {
|
||||||
|
project.executeWriteCommand(commandName, commandGroupId) {
|
||||||
|
sourceDocument.deleteString(it.startOffset, it.startOffset + it.tempImportsText.length)
|
||||||
|
sourceDocument.insertString(it.startOffset, it.originalImportsText)
|
||||||
|
}
|
||||||
|
psiDocumentManager.commitDocument(sourceDocument)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mover = object : Mover {
|
||||||
override fun invoke(declaration: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
|
override fun invoke(declaration: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
|
||||||
val index = stubDeclarations.indexOf(declaration)
|
val index = stubDeclarations.indexOf(declaration)
|
||||||
assert(index >= 0)
|
assert(index >= 0)
|
||||||
@@ -130,20 +169,40 @@ class MoveDeclarationsProcessor(
|
|||||||
project.runRefactoringAndKeepDelayedRequests { declarationProcessor.execute(declarationUsages) }
|
project.runRefactoringAndKeepDelayedRequests { declarationProcessor.execute(declarationUsages) }
|
||||||
|
|
||||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(sourceDocument)
|
psiDocumentManager.doPostponedOperationsAndUnblockDocument(sourceDocument)
|
||||||
assert(insertedRange.isValid)
|
val insertedStubRange = stubRangeAndDeclarations.first
|
||||||
sourceDocument.deleteString(insertedRange.startOffset, insertedRange.endOffset)
|
assert(insertedStubRange.isValid)
|
||||||
|
sourceDocument.deleteString(insertedStubRange.startOffset, insertedStubRange.endOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertStubDeclarations(): RangeMarker {
|
private data class ImportsSubstitution(val originalImportsText: String, val tempImportsText: String, val startOffset: Int)
|
||||||
val insertionOffset = sourceContainer.declarations.firstOrNull()?.startOffset
|
|
||||||
?: when (sourceContainer) {
|
private fun insertStubDeclarations(
|
||||||
is KtFile -> sourceContainer.textLength
|
commandName: String,
|
||||||
is KtObjectDeclaration -> sourceContainer.getBody()?.rBrace?.startOffset ?: sourceContainer.endOffset
|
commandGroupId: Any?,
|
||||||
else -> error("Unknown sourceContainer: $sourceContainer")
|
values: List<String>
|
||||||
}
|
): Pair<RangeMarker, List<KtNamedDeclaration>> {
|
||||||
val textToInsert = "\n//start\n\n" + stubTexts.joinToString(separator = "\n") + "\n//end\n"
|
val insertedRange = project.executeWriteCommand(commandName, commandGroupId) {
|
||||||
sourceDocument.insertString(insertionOffset, textToInsert)
|
val insertionOffset = sourceContainer.declarations.firstOrNull()?.startOffset
|
||||||
return sourceDocument.createRangeMarker(TextRange(insertionOffset, insertionOffset + textToInsert.length))
|
?: when (sourceContainer) {
|
||||||
|
is KtFile -> sourceContainer.textLength
|
||||||
|
is KtObjectDeclaration -> sourceContainer.getBody()?.rBrace?.startOffset ?: sourceContainer.endOffset
|
||||||
|
else -> error("Unknown sourceContainer: $sourceContainer")
|
||||||
|
}
|
||||||
|
val textToInsert = "\n//start\n\n${values.joinToString(separator = "\n")}\n//end\n"
|
||||||
|
sourceDocument.insertString(insertionOffset, textToInsert)
|
||||||
|
sourceDocument.createRangeMarker(TextRange(insertionOffset, insertionOffset + textToInsert.length))
|
||||||
|
}
|
||||||
|
psiDocumentManager.commitDocument(sourceDocument)
|
||||||
|
|
||||||
|
val declarations =
|
||||||
|
MoveDeclarationsCopyPasteProcessor.rangeToDeclarations(
|
||||||
|
sourcePsiFile,
|
||||||
|
insertedRange.startOffset,
|
||||||
|
insertedRange.endOffset
|
||||||
|
)
|
||||||
|
|
||||||
|
return Pair(insertedRange, declarations)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+5
-4
@@ -18,13 +18,14 @@ package org.jetbrains.kotlin.idea.refactoring.cutPaste
|
|||||||
|
|
||||||
import com.intellij.codeInsight.editorActions.TextBlockTransferableData
|
import com.intellij.codeInsight.editorActions.TextBlockTransferableData
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
import java.awt.datatransfer.DataFlavor
|
import java.awt.datatransfer.DataFlavor
|
||||||
|
|
||||||
class MoveDeclarationsTransferableData(
|
class MoveDeclarationsTransferableData(
|
||||||
val sourceFileUrl: String,
|
val sourceFileUrl: String,
|
||||||
val sourceObjectFqName: String?,
|
val sourceObjectFqName: String?,
|
||||||
val stubTexts: List<String>,
|
val declarations: List<KtNamedDeclaration>,
|
||||||
val declarationNames: Set<String>
|
val imports: List<String>
|
||||||
) : TextBlockTransferableData {
|
) : TextBlockTransferableData {
|
||||||
|
|
||||||
override fun getFlavor() = DATA_FLAVOR
|
override fun getFlavor() = DATA_FLAVOR
|
||||||
|
|||||||
Reference in New Issue
Block a user