fixup! Introduce Type Parameter
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
cannot.refactor.not.expression=Cannot find an expression to introduce
|
cannot.refactor.not.expression=Cannot find an expression to introduce
|
||||||
cannot.refactor.not.expression.to.extract=Cannot find an expression to extract
|
cannot.refactor.not.expression.to.extract=Cannot find an expression to extract
|
||||||
expressions.title=Expressions
|
|
||||||
introduce.variable=Introduce Variable
|
introduce.variable=Introduce Variable
|
||||||
introduce.property=Introduce Property
|
introduce.property=Introduce Property
|
||||||
introduce.parameter=Introduce Parameter
|
introduce.parameter=Introduce Parameter
|
||||||
@@ -25,7 +24,7 @@ cannot.refactor.synthesized.function=Cannot refactor synthesized function ''{0}'
|
|||||||
error.types.in.generated.function=Cannot generate function with erroneous return type
|
error.types.in.generated.function=Cannot generate function with erroneous return type
|
||||||
cannot.introduce.parameter.of.0.type=Cannot introduce parameter of type ''{0}''
|
cannot.introduce.parameter.of.0.type=Cannot introduce parameter of type ''{0}''
|
||||||
|
|
||||||
0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.declaration={0} has detected {1} code {1,choice,1#fragment|2#fragments} in this file that can be replaced with a usage of extracted declaration. Would you like to review and replace {1,choice,1#it|2#them}?
|
0.has.detected.1.code.fragments.in.2.that.can.be.replaced.with.3={0} has detected {1} code {1,choice,1#fragment|2#fragments} in {2} that can be replaced with {3}. Would you like to review and replace {1,choice,1#it|2#them}?
|
||||||
|
|
||||||
error.wrong.caret.position.function.or.constructor.name=The caret should be positioned at the name of the function or constructor to be refactored.
|
error.wrong.caret.position.function.or.constructor.name=The caret should be positioned at the name of the function or constructor to be refactored.
|
||||||
error.cant.refactor.vararg.functions=Can't refactor the function with variable arguments
|
error.cant.refactor.vararg.functions=Can't refactor the function with variable arguments
|
||||||
|
|||||||
@@ -522,8 +522,21 @@ public class KotlinRefactoringUtil {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
String title = "Elements";
|
||||||
|
if (elementKinds.size() == 1) {
|
||||||
|
switch (elementKinds.iterator().next()) {
|
||||||
|
case EXPRESSION:
|
||||||
|
title = "Expressions";
|
||||||
|
break;
|
||||||
|
case TYPE_ELEMENT:
|
||||||
|
case TYPE_CONSTRUCTOR:
|
||||||
|
title = "Types";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JBPopupFactory.getInstance().createListPopupBuilder(list).
|
JBPopupFactory.getInstance().createListPopupBuilder(list).
|
||||||
setTitle(KotlinRefactoringBundle.message("expressions.title")).setMovable(false).setResizable(false).
|
setTitle(title).setMovable(false).setResizable(false).
|
||||||
setRequestFocus(true).setItemChoosenCallback(new Runnable() {
|
setRequestFocus(true).setItemChoosenCallback(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|||||||
+7
-3
@@ -66,7 +66,9 @@ fun KotlinPsiRange.preview(project: Project, editor: Editor): RangeHighlighter?
|
|||||||
fun processDuplicates(
|
fun processDuplicates(
|
||||||
duplicateReplacers: Map<KotlinPsiRange, () -> Unit>,
|
duplicateReplacers: Map<KotlinPsiRange, () -> Unit>,
|
||||||
project: Project,
|
project: Project,
|
||||||
editor: Editor
|
editor: Editor,
|
||||||
|
scopeDescription: String = "this file",
|
||||||
|
usageDescription: String = "a usage of extracted declaration"
|
||||||
) {
|
) {
|
||||||
val size = duplicateReplacers.size
|
val size = duplicateReplacers.size
|
||||||
if (size == 0) return
|
if (size == 0) return
|
||||||
@@ -81,9 +83,11 @@ fun processDuplicates(
|
|||||||
Messages.showYesNoDialog(
|
Messages.showYesNoDialog(
|
||||||
project,
|
project,
|
||||||
KotlinRefactoringBundle.message(
|
KotlinRefactoringBundle.message(
|
||||||
"0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.declaration",
|
"0.has.detected.1.code.fragments.in.2.that.can.be.replaced.with.3",
|
||||||
ApplicationNamesInfo.getInstance().productName,
|
ApplicationNamesInfo.getInstance().productName,
|
||||||
duplicateReplacers.size
|
duplicateReplacers.size,
|
||||||
|
scopeDescription,
|
||||||
|
usageDescription
|
||||||
),
|
),
|
||||||
"Process Duplicates",
|
"Process Duplicates",
|
||||||
Messages.getQuestionIcon()
|
Messages.getQuestionIcon()
|
||||||
|
|||||||
+63
-31
@@ -24,12 +24,14 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.ex.EditorEx
|
import com.intellij.openapi.editor.ex.EditorEx
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.ElementDescriptionUtil
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.refactoring.RefactoringActionHandler
|
import com.intellij.refactoring.RefactoringActionHandler
|
||||||
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
|
import com.intellij.usageView.UsageViewTypeLocation
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
|
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterByRefActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterByRefActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterFromUsageFix
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterFromUsageFix
|
||||||
@@ -39,6 +41,7 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.processD
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeAlias.KotlinIntroduceTypeAliasHandler
|
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeAlias.KotlinIntroduceTypeAliasHandler
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent
|
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
|
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.rename.VariableInplaceRenameHandlerWithFinishHook
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
@@ -50,6 +53,10 @@ import org.jetbrains.kotlin.psi.KtFile
|
|||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.psi.KtTypeElement
|
import org.jetbrains.kotlin.psi.KtTypeElement
|
||||||
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||||
@@ -77,10 +84,15 @@ object KotlinIntroduceTypeParameterHandler : RefactoringActionHandler {
|
|||||||
val typeElementToExtract = elements.singleOrNull() as? KtTypeElement
|
val typeElementToExtract = elements.singleOrNull() as? KtTypeElement
|
||||||
?: return showErrorHint(project, editor, "No type to refactor", REFACTORING_NAME)
|
?: return showErrorHint(project, editor, "No type to refactor", REFACTORING_NAME)
|
||||||
|
|
||||||
|
val typeElementToExtractPointer = typeElementToExtract.createSmartPointer()
|
||||||
|
|
||||||
val scope = targetOwner.getResolutionScope()
|
val scope = targetOwner.getResolutionScope()
|
||||||
val suggestedNames = KotlinNameSuggester.suggestNamesForTypeParameters(1) {
|
val suggestedNames = KotlinNameSuggester.suggestNamesForTypeParameters(
|
||||||
scope.findClassifier(Name.identifier(it), NoLookupLocation.FROM_IDE) == null
|
1,
|
||||||
}
|
CollectingNameValidator(targetOwner.typeParameters.mapNotNull { it.name }) {
|
||||||
|
scope.findClassifier(Name.identifier(it), NoLookupLocation.FROM_IDE) == null
|
||||||
|
}
|
||||||
|
)
|
||||||
val defaultName = suggestedNames.single()
|
val defaultName = suggestedNames.single()
|
||||||
|
|
||||||
val context = typeElementToExtract.analyze(BodyResolveMode.PARTIAL)
|
val context = typeElementToExtract.analyze(BodyResolveMode.PARTIAL)
|
||||||
@@ -91,40 +103,60 @@ object KotlinIntroduceTypeParameterHandler : RefactoringActionHandler {
|
|||||||
?.copy(upperBoundType = originalType, declaration = targetOwner)
|
?.copy(upperBoundType = originalType, declaration = targetOwner)
|
||||||
?: return showErrorHint(project, editor, "Refactoring is not applicable in the current context", REFACTORING_NAME)
|
?: return showErrorHint(project, editor, "Refactoring is not applicable in the current context", REFACTORING_NAME)
|
||||||
|
|
||||||
val parameterRefElement = KtPsiFactory(project).createType(defaultName).typeElement!!
|
|
||||||
|
|
||||||
val duplicateRanges = typeElementToExtract
|
|
||||||
.toRange()
|
|
||||||
.match(targetParent, KotlinPsiUnifier.DEFAULT)
|
|
||||||
.filterNot {
|
|
||||||
val textRange = it.range.getTextRange()
|
|
||||||
typeElementToExtract.textRange.intersects(textRange) || targetOwner.typeParameterList?.textRange?.intersects(textRange) ?: false
|
|
||||||
}
|
|
||||||
.mapNotNull { it.range.elements.toRange() }
|
|
||||||
|
|
||||||
project.executeCommand(REFACTORING_NAME) {
|
project.executeCommand(REFACTORING_NAME) {
|
||||||
runWriteAction {
|
|
||||||
typeElementToExtract.replace(parameterRefElement)
|
|
||||||
|
|
||||||
processDuplicates(
|
|
||||||
duplicateRanges.keysToMap {
|
|
||||||
{
|
|
||||||
it.elements.singleOrNull()?.replace(parameterRefElement)
|
|
||||||
Unit
|
|
||||||
}
|
|
||||||
},
|
|
||||||
project,
|
|
||||||
editor
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val newTypeParameter = CreateTypeParameterFromUsageFix(typeElementToExtract, createTypeParameterData).doInvoke()
|
val newTypeParameter = CreateTypeParameterFromUsageFix(typeElementToExtract, createTypeParameterData).doInvoke()
|
||||||
?: return@executeCommand
|
?: return@executeCommand
|
||||||
|
val newTypeParameterPointer = newTypeParameter.createSmartPointer()
|
||||||
|
|
||||||
|
val postRename = postRename@ {
|
||||||
|
val restoredTypeParameter = newTypeParameterPointer.element ?: return@postRename
|
||||||
|
val restoredOwner = restoredTypeParameter.getStrictParentOfType<KtTypeParameterListOwner>() ?: return@postRename
|
||||||
|
val restoredOriginalTypeElement = typeElementToExtractPointer.element ?: return@postRename
|
||||||
|
|
||||||
|
runWriteAction {
|
||||||
|
val parameterRefElement = KtPsiFactory(project).createType(restoredTypeParameter.name ?: "_").typeElement!!
|
||||||
|
|
||||||
|
val duplicateRanges = restoredOriginalTypeElement
|
||||||
|
.toRange()
|
||||||
|
.match(restoredOwner, KotlinPsiUnifier.DEFAULT)
|
||||||
|
.filterNot {
|
||||||
|
val textRange = it.range.getTextRange()
|
||||||
|
restoredOriginalTypeElement.textRange.intersects(textRange)
|
||||||
|
|| restoredOwner.typeParameterList?.textRange?.intersects(textRange) ?: false
|
||||||
|
}
|
||||||
|
.mapNotNull { it.range.elements.toRange() }
|
||||||
|
|
||||||
|
restoredOriginalTypeElement.replace(parameterRefElement)
|
||||||
|
|
||||||
|
processDuplicates(
|
||||||
|
duplicateRanges.keysToMap {
|
||||||
|
{
|
||||||
|
it.elements.singleOrNull()?.replace(parameterRefElement)
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
},
|
||||||
|
project,
|
||||||
|
editor,
|
||||||
|
ElementDescriptionUtil.getElementDescription(restoredOwner, UsageViewTypeLocation.INSTANCE) + " '${restoredOwner.name}'",
|
||||||
|
"a reference to extracted type parameter"
|
||||||
|
)
|
||||||
|
|
||||||
|
restoredTypeParameter.extendsBound?.let {
|
||||||
|
editor.selectionModel.setSelection(it.startOffset, it.endOffset)
|
||||||
|
editor.caretModel.moveToOffset(it.startOffset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
val dataContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PSI_ELEMENT.name, newTypeParameter,
|
val dataContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PSI_ELEMENT.name, newTypeParameter,
|
||||||
(editor as? EditorEx)?.dataContext)
|
(editor as? EditorEx)?.dataContext)
|
||||||
VariableInplaceRenameHandler().doRename(newTypeParameter, editor, dataContext)
|
editor.selectionModel.removeSelection()
|
||||||
|
editor.caretModel.moveToOffset(newTypeParameter.startOffset)
|
||||||
|
VariableInplaceRenameHandlerWithFinishHook(postRename).doRename(newTypeParameter, editor, dataContext)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
postRename()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||||
|
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
|
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
|
||||||
|
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer
|
||||||
|
|
||||||
|
class VariableInplaceRenameHandlerWithFinishHook(private val onFinish: () -> Unit) : VariableInplaceRenameHandler() {
|
||||||
|
override fun createRenamer(elementToRename: PsiElement, editor: Editor?): VariableInplaceRenamer? {
|
||||||
|
return object : VariableInplaceRenamer(elementToRename as PsiNamedElement, editor) {
|
||||||
|
override fun performRefactoring(): Boolean {
|
||||||
|
try {
|
||||||
|
return super.performRefactoring()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
onFinish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user