diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/inplace/ExtractMethodTemplateBuilder.kt b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/inplace/ExtractMethodTemplateBuilder.kt index a5ccf138828e..5390f01a1cee 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/inplace/ExtractMethodTemplateBuilder.kt +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/inplace/ExtractMethodTemplateBuilder.kt @@ -9,7 +9,6 @@ import com.intellij.codeInsight.template.TemplateManager import com.intellij.codeInsight.template.impl.ConstantNode import com.intellij.codeInsight.template.impl.TemplateState import com.intellij.openapi.Disposable -import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project @@ -80,8 +79,8 @@ data class ExtractMethodTemplateBuilder( val methodMarker = document.createRangeMarker(methodIdentifier).apply { isGreedyToRight = true } val callMarker = document.createRangeMarker(callIdentifier).apply { isGreedyToRight = true } - fun setMethodName(text: String){ - runWriteAction { + fun setMethodName(text: String) { + WriteCommandAction.writeCommandAction(project).run { callMarker.range?.also { range -> editor.document.replaceString(range.startOffset, range.endOffset, text) } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ExtractKotlinFunctionHandler.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ExtractKotlinFunctionHandler.kt index 0f3b4897af26..783e03ad6343 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ExtractKotlinFunctionHandler.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ExtractKotlinFunctionHandler.kt @@ -16,6 +16,7 @@ import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.registry.Registry import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import com.intellij.psi.SmartPointerManager import com.intellij.psi.util.PsiTreeUtil import com.intellij.refactoring.RefactoringActionHandler import com.intellij.refactoring.extractMethod.ExtractMethodHandler @@ -26,16 +27,17 @@ import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.base.psi.unifier.toRange import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils -import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.refactoring.KotlinNamesValidator import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinExtractFunctionDialog +import org.jetbrains.kotlin.idea.refactoring.introduce.extractableSubstringInfo import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetSibling import org.jetbrains.kotlin.idea.refactoring.introduce.validateExpressionElements import org.jetbrains.kotlin.idea.util.nonBlocking import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -91,8 +93,8 @@ class ExtractKotlinFunctionHandler( val descriptor = descriptorWithConflicts.descriptor.copy(suggestedNames = listOf("extracted")) val elements = descriptor.extractionData.originalElements val file = descriptor.extractionData.originalFile - val callRange = editor.document.createRangeMarker(elements.first().textRange.startOffset, elements.last().textRange.endOffset) - .apply { isGreedyToLeft = true; isGreedyToRight = true } + val callTextRange = TextRange(rangeOf(elements.first()).startOffset, rangeOf(elements.last()).endOffset) + val callRangeProvider: () -> TextRange? = createSmartRangeProvider(descriptor.extractionData.commonParent, callTextRange) val editorState = EditorState(editor) val disposable = Disposer.newDisposable() WriteCommandAction.writeCommandAction(project).run { @@ -100,12 +102,13 @@ class ExtractKotlinFunctionHandler( Disposer.register(disposable) { FinishMarkAction.finish(project, editor, startMarkAction) } } fun afterFinish(extraction: ExtractionResult){ - val callIdentifier = findSingleCallExpression(file, callRange.range)?.calleeExpression ?: throw IllegalStateException() + val callRange: TextRange = callRangeProvider.invoke() ?: throw IllegalStateException() + val callIdentifier = findSingleCallExpression(file, callRange)?.calleeExpression ?: throw IllegalStateException() val methodIdentifier = extraction.declaration.nameIdentifier ?: throw IllegalStateException() val methodRange = extraction.declaration.textRange val methodOffset = extraction.declaration.navigationElement.textRange.endOffset val callOffset = callIdentifier.textRange.endOffset - val preview = InplaceExtractUtils.createPreview(editor, methodRange, methodOffset, callRange.range!!, callOffset) + val preview = InplaceExtractUtils.createPreview(editor, methodRange, methodOffset, callRange, callOffset) Disposer.register(disposable, preview) ExtractMethodTemplateBuilder(editor, EXTRACT_FUNCTION) .withCompletionNames(descriptor.suggestedNames) @@ -135,6 +138,21 @@ class ExtractKotlinFunctionHandler( } } + private fun rangeOf(element: PsiElement): TextRange { + return (element as? KtExpression)?.extractableSubstringInfo?.contentRange ?: element.textRange + } + + private fun createSmartRangeProvider(container: PsiElement, range: TextRange): () -> TextRange? { + val offsetFromStart = range.startOffset - container.textRange.startOffset + val offsetFromEnd = container.textRange.endOffset - range.endOffset + val pointer = SmartPointerManager.createPointer(container) + fun findRange(): TextRange? { + val containerRange = pointer.range ?: return null + return TextRange(containerRange.startOffset + offsetFromStart, containerRange.endOffset - offsetFromEnd) + } + return ::findRange + } + @Nls private fun getIdentifierError(file: PsiFile, variableRange: TextRange): String? { val call = PsiTreeUtil.findElementOfClassAtOffset(file, variableRange.startOffset, KtCallExpression::class.java, false)