mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
[extract method] cleanup: use range marker to track extracted range
GitOrigin-RevId: cf23863e723b305a0024015ab060bb70071f614b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9d6675e877
commit
c89c0bb036
@@ -6,7 +6,6 @@ import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.IntroduceVariableUtil
|
||||
import com.intellij.refactoring.util.RefactoringUtil
|
||||
import com.intellij.util.CommonJavaRefactoringUtil
|
||||
|
||||
class ExtractSelector {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
package com.intellij.refactoring.extractMethod.newImpl
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
|
||||
@@ -34,7 +33,6 @@ class JavaDuplicatesFinder(pattern: List<PsiElement>, private val parametrizedEx
|
||||
|
||||
private fun getElementInPhysicalFile(element: PsiElement): PsiElement? = element.getCopyableUserData(ELEMENT_IN_PHYSICAL_FILE)
|
||||
|
||||
fun textRangeOf(range: List<PsiElement>) = TextRange(range.first().textRange.startOffset, range.last().textRange.endOffset)
|
||||
}
|
||||
|
||||
private val pattern: List<PsiElement> = pattern.filterNot(::isNoise)
|
||||
|
||||
@@ -80,6 +80,10 @@ class MethodExtractor {
|
||||
return
|
||||
}
|
||||
|
||||
readAction {
|
||||
sendRefactoringStartedEvent(elements.toTypedArray())
|
||||
}
|
||||
|
||||
val prepareStart = System.currentTimeMillis()
|
||||
val descriptorsForAllTargetPlaces = prepareDescriptorsForAllTargetPlaces(file.project, editor, elements)
|
||||
if (descriptorsForAllTargetPlaces.isEmpty()) return
|
||||
@@ -121,7 +125,7 @@ class MethodExtractor {
|
||||
try {
|
||||
readAction { findAllOptionsToExtract(elements) }
|
||||
} catch (exception: ExtractException) {
|
||||
InplaceExtractUtils.showExtractErrorHint(editor, exception)
|
||||
InplaceExtractUtils.showExtractErrorHint(editor, exception.message.orEmpty(), exception.problems)
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.intellij.openapi.application.constrainedReadAction
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.command.writeCommandAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.editor.ScrollType
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
@@ -29,7 +30,8 @@ import com.intellij.refactoring.extractMethod.newImpl.*
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodHelper.inputParameterOf
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodHelper.replacePsiRange
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodHelper.replaceWithMethod
|
||||
import com.intellij.refactoring.extractMethod.newImpl.JavaDuplicatesFinder.Companion.textRangeOf
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils.createGreedyRangeMarker
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils.textRangeOf
|
||||
import com.intellij.refactoring.extractMethod.newImpl.structures.ExtractOptions
|
||||
import com.intellij.refactoring.extractMethod.newImpl.structures.InputParameter
|
||||
import com.intellij.refactoring.introduceField.ElementToWorkOn
|
||||
@@ -39,7 +41,14 @@ import com.siyeh.ig.psiutils.SideEffectChecker.mayHaveSideEffects
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DuplicatesMethodExtractor(val extractOptions: ExtractOptions, val targetClass: PsiClass, val elements: List<PsiElement>) {
|
||||
class DuplicatesMethodExtractor(val extractOptions: ExtractOptions, val targetClass: PsiClass, val rangeToReplace: RangeMarker) {
|
||||
|
||||
internal fun getElements(): List<PsiElement> {
|
||||
val file = targetClass.containingFile
|
||||
val range = rangeToReplace.textRange
|
||||
require(rangeToReplace.isValid)
|
||||
return ExtractSelector().suggestElementsToExtract(file, range)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val isSilentMode = ApplicationManager.getApplication().isUnitTestMode
|
||||
@@ -48,6 +57,8 @@ class DuplicatesMethodExtractor(val extractOptions: ExtractOptions, val targetCl
|
||||
|
||||
fun create(targetClass: PsiClass, elements: List<PsiElement>, methodName: String, makeStatic: Boolean): DuplicatesMethodExtractor {
|
||||
val file = targetClass.containingFile
|
||||
val document = file.viewProvider.document ?: throw IllegalStateException()
|
||||
val rangeToReplace = createGreedyRangeMarker(document, textRangeOf(elements.first(), elements.last()))
|
||||
JavaDuplicatesFinder.linkCopiedClassMembersWithOrigin(file)
|
||||
val copiedFile = file.copy() as PsiFile
|
||||
val copiedClass = PsiTreeUtil.findSameElementInCopy(targetClass, copiedFile)
|
||||
@@ -56,19 +67,18 @@ class DuplicatesMethodExtractor(val extractOptions: ExtractOptions, val targetCl
|
||||
val range = virtualExpressionRange ?: TextRange(elements.first().textRange.startOffset, elements.last().textRange.endOffset)
|
||||
val copiedElements = ExtractSelector().suggestElementsToExtract(copiedFile, range)
|
||||
val extractOptions = findExtractOptions(copiedClass, copiedElements, methodName, makeStatic)
|
||||
return DuplicatesMethodExtractor(extractOptions, targetClass, elements)
|
||||
return DuplicatesMethodExtractor(extractOptions, targetClass, rangeToReplace)
|
||||
}
|
||||
}
|
||||
|
||||
private var callsToReplace: List<SmartPsiElementPointer<PsiElement>>? = null
|
||||
|
||||
suspend fun extract(): ExtractedElements {
|
||||
val file = readAction { targetClass.containingFile }
|
||||
val project = file.project
|
||||
val elements = readAction { getElements() }
|
||||
|
||||
val preparedElements = readAction { MethodExtractor().prepareRefactoringElements(extractOptions) }
|
||||
val (callsPointer, methodPointer) = writeCommandAction(project, ExtractMethodHandler.getRefactoringName()) {
|
||||
val (calls, method) = replaceWithMethod(targetClass, this@DuplicatesMethodExtractor.elements, preparedElements)
|
||||
val (calls, method) = replaceWithMethod(targetClass, elements, preparedElements)
|
||||
val methodPointer = SmartPointerManager.createPointer(method)
|
||||
val callsPointer = calls.map(SmartPointerManager::createPointer)
|
||||
Pair(callsPointer, methodPointer)
|
||||
@@ -80,14 +90,13 @@ class DuplicatesMethodExtractor(val extractOptions: ExtractOptions, val targetCl
|
||||
callsPointer.map { it.element ?: throw IllegalStateException() }
|
||||
}
|
||||
|
||||
this.callsToReplace = callsPointer
|
||||
|
||||
return ExtractedElements(replacedCalls, replacedMethod)
|
||||
}
|
||||
|
||||
suspend fun replaceDuplicates(editor: Editor, method: PsiMethod, beforeDuplicateReplaced: (candidate: List<PsiElement>) -> Unit = {}) {
|
||||
val project = readAction { editor.project } ?: return
|
||||
val calls = readAction { callsToReplace?.map { it.element!! } }?: return
|
||||
val calls = readAction { getElements() }
|
||||
if (calls.isEmpty()) return
|
||||
val defaultExtraction = ExtractedElements(calls, method)
|
||||
|
||||
val prepareTimeStart = System.currentTimeMillis()
|
||||
@@ -262,7 +271,7 @@ class DuplicatesMethodExtractor(val extractOptions: ExtractOptions, val targetCl
|
||||
val initialPosition = editor.caretModel.logicalPosition
|
||||
val confirmedDuplicates = mutableListOf<Duplicate>()
|
||||
duplicates.forEach { duplicate ->
|
||||
val highlighters = DuplicatesImpl.previewMatch(project, editor, textRangeOf(duplicate.candidate))
|
||||
val highlighters = DuplicatesImpl.previewMatch(project, editor, textRangeOf(duplicate.candidate.first(), duplicate.candidate.last()))
|
||||
try {
|
||||
val prompt = ReplacePromptDialog(false, JavaRefactoringBundle.message("process.duplicates.title"), project)
|
||||
prompt.show()
|
||||
@@ -343,8 +352,7 @@ fun DuplicatesMethodExtractor.extractInDialog() {
|
||||
if (!passFieldsAsParameters) {
|
||||
JavaRefactoringSettings.getInstance().EXTRACT_STATIC_METHOD = dialogOptions.isStatic
|
||||
}
|
||||
val mappedExtractor = DuplicatesMethodExtractor(dialogOptions, targetClass, elements)
|
||||
MethodExtractor.sendRefactoringStartedEvent(elements.toTypedArray())
|
||||
val mappedExtractor = DuplicatesMethodExtractor(dialogOptions, targetClass, rangeToReplace)
|
||||
//todo avoid blocking, suspend should be propagated further
|
||||
val (_, method) = runWithModalProgressBlocking(extractOptions.project, ExtractMethodHandler.getRefactoringName()) {
|
||||
mappedExtractor.extract()
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.intellij.internal.statistic.eventLog.events.FusInputEvent
|
||||
import com.intellij.java.refactoring.JavaRefactoringBundle
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.diff.DiffColors
|
||||
import com.intellij.openapi.editor.*
|
||||
import com.intellij.openapi.editor.colors.EditorColors
|
||||
@@ -38,10 +39,11 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractException
|
||||
import com.intellij.refactoring.rename.inplace.TemplateInlayUtil
|
||||
import com.intellij.ui.GotItTooltip
|
||||
import com.intellij.util.SmartList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.Point
|
||||
import java.awt.event.KeyEvent
|
||||
@@ -65,14 +67,18 @@ object InplaceExtractUtils {
|
||||
return true
|
||||
}
|
||||
|
||||
fun showExtractErrorHint(editor: Editor, error: @Nls String) {
|
||||
suspend fun showExtractErrorHint(editor: Editor, error: @Nls String) {
|
||||
val message: @Nls String = JavaRefactoringBundle.message("extract.method.error.prefix") + " " + error
|
||||
IdeUiService.getInstance().showErrorHint(editor, message)
|
||||
withContext(Dispatchers.EDT) {
|
||||
IdeUiService.getInstance().showErrorHint(editor, message)
|
||||
}
|
||||
}
|
||||
|
||||
fun showExtractErrorHint(editor: Editor, exception: ExtractException){
|
||||
showExtractErrorHint(editor, exception.message.orEmpty())
|
||||
highlightErrors(editor, exception.problems)
|
||||
suspend fun showExtractErrorHint(editor: Editor, error: @Nls String, highlightedRanges: List<TextRange>){
|
||||
showExtractErrorHint(editor, error)
|
||||
withContext(Dispatchers.EDT) {
|
||||
highlightErrors(editor, highlightedRanges)
|
||||
}
|
||||
}
|
||||
|
||||
private fun highlightErrors(editor: Editor, ranges: List<TextRange>) {
|
||||
@@ -285,13 +291,17 @@ object InplaceExtractUtils {
|
||||
return PsiTreeUtil.findElementOfClassAtOffset(file, offset, T::class.java, false)
|
||||
}
|
||||
|
||||
fun createGreedyRangeMarker(document: Document, range: TextRange): RangeMarker {
|
||||
internal fun createGreedyRangeMarker(document: Document, range: TextRange): RangeMarker {
|
||||
return document.createRangeMarker(range).apply {
|
||||
isGreedyToLeft = true
|
||||
isGreedyToRight = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun textRangeOf(first: PsiElement, last: PsiElement): TextRange {
|
||||
return TextRange(first.textRange.startOffset, last.textRange.endOffset)
|
||||
}
|
||||
|
||||
private fun IntRange.trim(maxLength: Int) = first until first + minOf(maxLength, last - first + 1)
|
||||
|
||||
fun getLinesFromTextRange(document: Document, range: TextRange, maxLength: Int): IntRange {
|
||||
|
||||
@@ -30,7 +30,6 @@ import com.intellij.refactoring.extractMethod.newImpl.CodeFragmentAnalyzer
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodHelper
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodPipeline
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodService
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractSelector
|
||||
import com.intellij.refactoring.extractMethod.newImpl.MethodExtractor
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils.addInlaySettingsElement
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils.checkReferenceIdentifier
|
||||
@@ -78,20 +77,17 @@ internal class InplaceMethodExtractor(private val editor: Editor,
|
||||
private val project = file.project
|
||||
|
||||
private fun createExtractor(): DuplicatesMethodExtractor {
|
||||
val elements = ExtractSelector().suggestElementsToExtract(defaultExtractor.targetClass.containingFile, range)
|
||||
var options = defaultExtractor.extractOptions
|
||||
if (popupProvider.makeStatic == true) {
|
||||
val analyzer = CodeFragmentAnalyzer(options.elements)
|
||||
options = ExtractMethodPipeline.withForcedStatic(analyzer, options) ?: throw IllegalStateException()
|
||||
}
|
||||
return DuplicatesMethodExtractor(options, defaultExtractor.targetClass, elements)
|
||||
val rangeToReplace = createGreedyRangeMarker(editor.document, range)
|
||||
return DuplicatesMethodExtractor(options, defaultExtractor.targetClass, rangeToReplace)
|
||||
}
|
||||
|
||||
suspend fun extractAndRunTemplate(suggestedNames: List<String>) {
|
||||
try {
|
||||
readAction {
|
||||
MethodExtractor.sendRefactoringStartedEvent(extractor.elements.toTypedArray())
|
||||
}
|
||||
ExtractMethodHelper.mergeWriteCommands(editor, disposable, ExtractMethodHandler.getRefactoringName())
|
||||
val (callElements, method) = extractor.extract()
|
||||
|
||||
@@ -208,9 +204,9 @@ internal class InplaceMethodExtractor(private val editor: Editor,
|
||||
val methodName = if (methodRange != null) editor.document.getText(methodRange) else ""
|
||||
InplaceExtractMethodCollector.openExtractDialog.log(project, isLinkUsed)
|
||||
TemplateManagerImpl.getTemplateState(editor)?.gotoEnd(true)
|
||||
val elements = ExtractSelector().suggestElementsToExtract(extractor.targetClass.containingFile, range)
|
||||
val extractOptions = extractor.extractOptions.copy(methodName = methodName)
|
||||
val extractor = DuplicatesMethodExtractor(extractOptions, extractor.targetClass, elements)
|
||||
val rangeToReplace = createGreedyRangeMarker(editor.document, range)
|
||||
val extractor = DuplicatesMethodExtractor(extractOptions, extractor.targetClass, rangeToReplace)
|
||||
extractor.extractInDialog()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ package com.intellij.refactoring.extractMethod.newImpl.parameterObject
|
||||
import com.intellij.codeInsight.hint.EditorCodePreview
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.java.refactoring.JavaRefactoringBundle
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.invokeLater
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.command.writeCommandAction
|
||||
@@ -16,16 +15,14 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import com.intellij.refactoring.extractMethod.ExtractMethodHandler
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractException
|
||||
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodHelper
|
||||
import com.intellij.refactoring.extractMethod.newImpl.MethodExtractor
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.EditorState
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.ExtractMethodTemplateBuilder
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils.createGreedyRangeMarker
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.InplaceExtractUtils.showExtractErrorHint
|
||||
import com.intellij.refactoring.extractMethod.newImpl.inplace.TemplateField
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
private data class IntroduceObjectResult(
|
||||
val introducedClass: PsiClass,
|
||||
@@ -44,9 +41,8 @@ internal object ResultObjectExtractor {
|
||||
|
||||
val affectedReferences = readAction { ParameterObjectUtils.findAffectedReferences(variables, scope) }
|
||||
if (affectedReferences == null) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
InplaceExtractUtils.showExtractErrorHint(editor, ExtractException(JavaRefactoringBundle.message("extract.method.error.many.outputs"), variables))
|
||||
}
|
||||
|
||||
showExtractErrorHint(editor, JavaRefactoringBundle.message("extract.method.error.many.outputs"), variables.map { it.textRange })
|
||||
return
|
||||
}
|
||||
val shouldInsertRecord = readAction { PsiUtil.isAvailable(JavaFeature.RECORDS, variables.first()) }
|
||||
|
||||
Reference in New Issue
Block a user