Minor: clean up some quickfixes & refactorings
This commit is contained in:
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.quickfix
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
@@ -25,7 +14,8 @@ import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
|
||||||
class RemoveUselessCastFix(element: KtBinaryExpressionWithTypeRHS) : KotlinQuickFixAction<KtBinaryExpressionWithTypeRHS>(element), CleanupFix {
|
class RemoveUselessCastFix(element: KtBinaryExpressionWithTypeRHS) : KotlinQuickFixAction<KtBinaryExpressionWithTypeRHS>(element),
|
||||||
|
CleanupFix {
|
||||||
override fun getFamilyName() = "Remove useless cast"
|
override fun getFamilyName() = "Remove useless cast"
|
||||||
|
|
||||||
override fun getText(): String = familyName
|
override fun getText(): String = familyName
|
||||||
|
|||||||
+9
-23
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.quickfix.replaceWith
|
package org.jetbrains.kotlin.idea.quickfix.replaceWith
|
||||||
@@ -51,16 +40,13 @@ class DeprecatedSymbolUsageInWholeProjectFix(
|
|||||||
replacementStrategy.replaceUsagesInWholeProject(psiElement, progressTitle = "Applying '$text'", commandName = text)
|
replacementStrategy.replaceUsagesInWholeProject(psiElement, progressTitle = "Applying '$text'", commandName = text)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun targetPsiElement(): KtDeclaration? {
|
private fun targetPsiElement(): KtDeclaration? = when (val referenceTarget = element?.mainReference?.resolve()) {
|
||||||
val referenceTarget = element?.mainReference?.resolve()
|
is KtNamedFunction -> referenceTarget
|
||||||
return when (referenceTarget) {
|
is KtProperty -> referenceTarget
|
||||||
is KtNamedFunction -> referenceTarget
|
is KtTypeAlias -> referenceTarget
|
||||||
is KtProperty -> referenceTarget
|
is KtConstructor<*> -> referenceTarget.getContainingClassOrObject() //TODO: constructor can be deprecated itself
|
||||||
is KtTypeAlias -> referenceTarget
|
is KtClass -> referenceTarget.takeIf { it.isAnnotation() }
|
||||||
is KtConstructor<*> -> referenceTarget.getContainingClassOrObject() //TODO: constructor can be deprecated itself
|
else -> null
|
||||||
is KtClass -> referenceTarget.takeIf { it.isAnnotation() }
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring
|
||||||
@@ -34,20 +23,21 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class AbstractPullPushMembersHandler(
|
abstract class AbstractPullPushMembersHandler(
|
||||||
private val refactoringName: String,
|
private val refactoringName: String,
|
||||||
private val helpId: String,
|
private val helpId: String,
|
||||||
private val wrongPositionMessage: String
|
private val wrongPositionMessage: String
|
||||||
) : RefactoringActionHandler, ElementsHandler {
|
) : RefactoringActionHandler, ElementsHandler {
|
||||||
private fun reportWrongPosition(project: Project, editor: Editor?) {
|
private fun reportWrongPosition(project: Project, editor: Editor?) {
|
||||||
val message = RefactoringBundle.getCannotRefactorMessage(wrongPositionMessage)
|
val message = RefactoringBundle.getCannotRefactorMessage(wrongPositionMessage)
|
||||||
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId)
|
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtParameter.getContainingClass() = if (hasValOrVar()) (ownerFunction as? KtPrimaryConstructor)?.containingClassOrObject else null
|
private fun KtParameter.getContainingClass() =
|
||||||
|
if (hasValOrVar()) (ownerFunction as? KtPrimaryConstructor)?.containingClassOrObject else null
|
||||||
|
|
||||||
protected fun reportWrongContext(project: Project, editor: Editor?) {
|
protected fun reportWrongContext(project: Project, editor: Editor?) {
|
||||||
val message = RefactoringBundle.getCannotRefactorMessage(
|
val message = RefactoringBundle.getCannotRefactorMessage(
|
||||||
RefactoringBundle.message("is.not.supported.in.the.current.context", refactoringName)
|
RefactoringBundle.message("is.not.supported.in.the.current.context", refactoringName)
|
||||||
)
|
)
|
||||||
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId)
|
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId)
|
||||||
}
|
}
|
||||||
@@ -64,8 +54,8 @@ abstract class AbstractPullPushMembersHandler(
|
|||||||
|
|
||||||
val target = (file.findElementAt(offset) ?: return).parentsWithSelf.firstOrNull {
|
val target = (file.findElementAt(offset) ?: return).parentsWithSelf.firstOrNull {
|
||||||
it is KtClassOrObject
|
it is KtClassOrObject
|
||||||
|| ((it is KtNamedFunction || it is KtProperty) && it.parent is KtClassBody)
|
|| ((it is KtNamedFunction || it is KtProperty) && it.parent is KtClassBody)
|
||||||
|| it is KtParameter && it.hasValOrVar() && it.ownerFunction is KtPrimaryConstructor
|
|| it is KtParameter && it.hasValOrVar() && it.ownerFunction is KtPrimaryConstructor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
|
|||||||
+200
-208
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.introduce.introduceParameter
|
package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter
|
||||||
@@ -66,23 +55,22 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class IntroduceParameterDescriptor(
|
data class IntroduceParameterDescriptor(
|
||||||
val originalRange: KotlinPsiRange,
|
val originalRange: KotlinPsiRange,
|
||||||
val callable: KtNamedDeclaration,
|
val callable: KtNamedDeclaration,
|
||||||
val callableDescriptor: FunctionDescriptor,
|
val callableDescriptor: FunctionDescriptor,
|
||||||
val newParameterName: String,
|
val newParameterName: String,
|
||||||
val newParameterTypeText: String,
|
val newParameterTypeText: String,
|
||||||
val argumentValue: KtExpression,
|
val argumentValue: KtExpression,
|
||||||
val withDefaultValue: Boolean,
|
val withDefaultValue: Boolean,
|
||||||
val parametersUsages: MultiMap<KtElement, KtElement>,
|
val parametersUsages: MultiMap<KtElement, KtElement>,
|
||||||
val occurrencesToReplace: List<KotlinPsiRange>,
|
val occurrencesToReplace: List<KotlinPsiRange>,
|
||||||
val parametersToRemove: List<KtElement> = getParametersToRemove(withDefaultValue, parametersUsages, occurrencesToReplace),
|
val parametersToRemove: List<KtElement> = getParametersToRemove(withDefaultValue, parametersUsages, occurrencesToReplace),
|
||||||
val occurrenceReplacer: IntroduceParameterDescriptor.(KotlinPsiRange) -> Unit = {}
|
val occurrenceReplacer: IntroduceParameterDescriptor.(KotlinPsiRange) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val newArgumentValue: KtExpression by lazy {
|
val newArgumentValue: KtExpression by lazy {
|
||||||
if (argumentValue.mustBeParenthesizedInInitializerPosition()) {
|
if (argumentValue.mustBeParenthesizedInInitializerPosition()) {
|
||||||
KtPsiFactory(callable).createExpressionByPattern("($0)", argumentValue)
|
KtPsiFactory(callable).createExpressionByPattern("($0)", argumentValue)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
argumentValue
|
argumentValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +83,7 @@ data class IntroduceParameterDescriptor(
|
|||||||
valVar = if (callable is KtClass) {
|
valVar = if (callable is KtClass) {
|
||||||
val modifierIsUnnecessary: (PsiElement) -> Boolean = {
|
val modifierIsUnnecessary: (PsiElement) -> Boolean = {
|
||||||
when {
|
when {
|
||||||
it.parent != callable.getBody() ->
|
it.parent != callable.body ->
|
||||||
false
|
false
|
||||||
it is KtAnonymousInitializer ->
|
it is KtAnonymousInitializer ->
|
||||||
true
|
true
|
||||||
@@ -106,17 +94,16 @@ data class IntroduceParameterDescriptor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (occurrencesToReplace.all {
|
if (occurrencesToReplace.all {
|
||||||
PsiTreeUtil.findCommonParent(it.elements)?.parentsWithSelf?.any(modifierIsUnnecessary) ?: false
|
PsiTreeUtil.findCommonParent(it.elements)?.parentsWithSelf?.any(modifierIsUnnecessary) == true
|
||||||
}) KotlinValVar.None else KotlinValVar.Val
|
}) KotlinValVar.None else KotlinValVar.Val
|
||||||
}
|
} else KotlinValVar.None
|
||||||
else KotlinValVar.None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getParametersToRemove(
|
fun getParametersToRemove(
|
||||||
withDefaultValue: Boolean,
|
withDefaultValue: Boolean,
|
||||||
parametersUsages: MultiMap<KtElement, KtElement>,
|
parametersUsages: MultiMap<KtElement, KtElement>,
|
||||||
occurrencesToReplace: List<KotlinPsiRange>
|
occurrencesToReplace: List<KotlinPsiRange>
|
||||||
): List<KtElement> {
|
): List<KtElement> {
|
||||||
if (withDefaultValue) return Collections.emptyList()
|
if (withDefaultValue) return Collections.emptyList()
|
||||||
|
|
||||||
@@ -146,15 +133,17 @@ fun IntroduceParameterDescriptor.performRefactoring(onExit: (() -> Unit)? = null
|
|||||||
} else 0
|
} else 0
|
||||||
}
|
}
|
||||||
.sortedDescending()
|
.sortedDescending()
|
||||||
.forEach { methodDescriptor.removeParameter(it) }
|
.forEach { methodDescriptor.removeParameter(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultValue = if (newArgumentValue is KtProperty) (newArgumentValue as KtProperty).initializer else newArgumentValue
|
val defaultValue = if (newArgumentValue is KtProperty) (newArgumentValue as KtProperty).initializer else newArgumentValue
|
||||||
val parameterInfo = KotlinParameterInfo(callableDescriptor = callableDescriptor,
|
val parameterInfo = KotlinParameterInfo(
|
||||||
name = newParameterName,
|
callableDescriptor = callableDescriptor,
|
||||||
defaultValueForCall = if (withDefaultValue) null else defaultValue,
|
name = newParameterName,
|
||||||
defaultValueForParameter = if (withDefaultValue) defaultValue else null,
|
defaultValueForCall = if (withDefaultValue) null else defaultValue,
|
||||||
valOrVar = valVar)
|
defaultValueForParameter = if (withDefaultValue) defaultValue else null,
|
||||||
|
valOrVar = valVar
|
||||||
|
)
|
||||||
parameterInfo.currentTypeInfo = KotlinTypeInfo(false, null, newParameterTypeText)
|
parameterInfo.currentTypeInfo = KotlinTypeInfo(false, null, newParameterTypeText)
|
||||||
methodDescriptor.addParameter(parameterInfo)
|
methodDescriptor.addParameter(parameterInfo)
|
||||||
}
|
}
|
||||||
@@ -180,9 +169,9 @@ fun IntroduceParameterDescriptor.performRefactoring(onExit: (() -> Unit)? = null
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun selectNewParameterContext(
|
fun selectNewParameterContext(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
continuation: (elements: List<PsiElement>, targetParent: PsiElement) -> Unit
|
continuation: (elements: List<PsiElement>, targetParent: PsiElement) -> Unit
|
||||||
) {
|
) {
|
||||||
selectElementsWithTargetParent(
|
selectElementsWithTargetParent(
|
||||||
operationName = INTRODUCE_PARAMETER,
|
operationName = INTRODUCE_PARAMETER,
|
||||||
@@ -192,24 +181,24 @@ fun selectNewParameterContext(
|
|||||||
elementKinds = listOf(CodeInsightUtils.ElementKind.EXPRESSION),
|
elementKinds = listOf(CodeInsightUtils.ElementKind.EXPRESSION),
|
||||||
elementValidator = ::validateExpressionElements,
|
elementValidator = ::validateExpressionElements,
|
||||||
getContainers = { _, parent ->
|
getContainers = { _, parent ->
|
||||||
val parents = parent.parents
|
val parents = parent.parents
|
||||||
val stopAt = (parent.parents.zip(parent.parents.drop(1)))
|
val stopAt = (parent.parents.zip(parent.parents.drop(1)))
|
||||||
.firstOrNull { isObjectOrNonInnerClass(it.first) }
|
.firstOrNull { isObjectOrNonInnerClass(it.first) }
|
||||||
?.second
|
?.second
|
||||||
|
|
||||||
(if (stopAt != null) parent.parents.takeWhile { it != stopAt } else parents)
|
(if (stopAt != null) parent.parents.takeWhile { it != stopAt } else parents)
|
||||||
.filter {
|
.filter {
|
||||||
((it is KtClass && !it.isInterface() && it !is KtEnumEntry) || it is KtNamedFunction || it is KtSecondaryConstructor) &&
|
((it is KtClass && !it.isInterface() && it !is KtEnumEntry) || it is KtNamedFunction || it is KtSecondaryConstructor) &&
|
||||||
((it as KtNamedDeclaration).getValueParameterList() != null || it.nameIdentifier != null)
|
((it as KtNamedDeclaration).getValueParameterList() != null || it.nameIdentifier != null)
|
||||||
}
|
}
|
||||||
.toList()
|
.toList()
|
||||||
},
|
},
|
||||||
continuation = continuation
|
continuation = continuation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KotlinIntroduceParameterHelper {
|
interface KotlinIntroduceParameterHelper {
|
||||||
object Default: KotlinIntroduceParameterHelper
|
object Default : KotlinIntroduceParameterHelper
|
||||||
|
|
||||||
fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor = descriptor
|
fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor = descriptor
|
||||||
}
|
}
|
||||||
@@ -228,8 +217,7 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
|
|
||||||
val expressionType = if (physicalExpression is KtProperty && physicalExpression.isLocal) {
|
val expressionType = if (physicalExpression is KtProperty && physicalExpression.isLocal) {
|
||||||
context[BindingContext.VARIABLE, physicalExpression]?.type
|
context[BindingContext.VARIABLE, physicalExpression]?.type
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
expression.extractableSubstringInfo?.type ?: context.getType(physicalExpression)
|
expression.extractableSubstringInfo?.type ?: context.getType(physicalExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,8 +228,8 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
|
|
||||||
if (expressionType.isUnit() || expressionType.isNothing()) {
|
if (expressionType.isUnit() || expressionType.isNothing()) {
|
||||||
val message = KotlinRefactoringBundle.message(
|
val message = KotlinRefactoringBundle.message(
|
||||||
"cannot.introduce.parameter.of.0.type",
|
"cannot.introduce.parameter.of.0.type",
|
||||||
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(expressionType)
|
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(expressionType)
|
||||||
)
|
)
|
||||||
showErrorHint(project, editor, message, INTRODUCE_PARAMETER)
|
showErrorHint(project, editor, message, INTRODUCE_PARAMETER)
|
||||||
return
|
return
|
||||||
@@ -249,15 +237,18 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
|
|
||||||
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, targetParent]
|
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, targetParent]
|
||||||
val functionDescriptor = descriptor.toFunctionDescriptor(targetParent)
|
val functionDescriptor = descriptor.toFunctionDescriptor(targetParent)
|
||||||
val replacementType = expressionType.approximateWithResolvableType(targetParent.getResolutionScope(context, targetParent.getResolutionFacade()), false)
|
val replacementType = expressionType.approximateWithResolvableType(
|
||||||
|
targetParent.getResolutionScope(context, targetParent.getResolutionFacade()),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
val body = when (targetParent) {
|
val body = when (targetParent) {
|
||||||
is KtFunction -> targetParent.bodyExpression
|
is KtFunction -> targetParent.bodyExpression
|
||||||
is KtClass -> targetParent.getBody()
|
is KtClass -> targetParent.body
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
val bodyValidator: ((String) -> Boolean)? =
|
val bodyValidator: ((String) -> Boolean)? =
|
||||||
body?.let { NewDeclarationNameValidator(it, sequenceOf(it), NewDeclarationNameValidator.Target.VARIABLES) }
|
body?.let { NewDeclarationNameValidator(it, sequenceOf(it), NewDeclarationNameValidator.Target.VARIABLES) }
|
||||||
val nameValidator = CollectingNameValidator(targetParent.getValueParameters().mapNotNull { it.name }, bodyValidator ?: { true })
|
val nameValidator = CollectingNameValidator(targetParent.getValueParameters().mapNotNull { it.name }, bodyValidator ?: { true })
|
||||||
|
|
||||||
val suggestedNames = SmartList<String>().apply {
|
val suggestedNames = SmartList<String>().apply {
|
||||||
@@ -277,18 +268,16 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
|
|
||||||
val occurrencesToReplace = if (expression is KtProperty) {
|
val occurrencesToReplace = if (expression is KtProperty) {
|
||||||
ReferencesSearch.search(expression).mapNotNullTo(SmartList(expression.toRange())) { it.element.toRange() }
|
ReferencesSearch.search(expression).mapNotNullTo(SmartList(expression.toRange())) { it.element.toRange() }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
expression.toRange()
|
expression.toRange()
|
||||||
.match(targetParent, KotlinPsiUnifier.DEFAULT)
|
.match(targetParent, KotlinPsiUnifier.DEFAULT)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filterNot {
|
.filterNot {
|
||||||
val textRange = it.range.getPhysicalTextRange()
|
val textRange = it.range.getPhysicalTextRange()
|
||||||
forbiddenRanges.any { it.intersects(textRange) }
|
forbiddenRanges.any { range -> range.intersects(textRange) }
|
||||||
}
|
}
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
val matchedElement = it.range.elements.singleOrNull()
|
val matchedExpr = when (val matchedElement = it.range.elements.singleOrNull()) {
|
||||||
val matchedExpr = when (matchedElement) {
|
|
||||||
is KtExpression -> matchedElement
|
is KtExpression -> matchedElement
|
||||||
is KtStringTemplateEntryWithExpression -> matchedElement.expression
|
is KtStringTemplateEntryWithExpression -> matchedElement.expression
|
||||||
else -> null
|
else -> null
|
||||||
@@ -299,80 +288,82 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
project.executeCommand(
|
project.executeCommand(
|
||||||
INTRODUCE_PARAMETER,
|
INTRODUCE_PARAMETER,
|
||||||
null,
|
null,
|
||||||
fun() {
|
fun() {
|
||||||
val isTestMode = ApplicationManager.getApplication().isUnitTestMode
|
val isTestMode = ApplicationManager.getApplication().isUnitTestMode
|
||||||
val haveLambdaArgumentsToReplace = occurrencesToReplace.any {
|
val haveLambdaArgumentsToReplace = occurrencesToReplace.any { range ->
|
||||||
it.elements.any { it is KtLambdaExpression && it.parent is KtLambdaArgument }
|
range.elements.any { it is KtLambdaExpression && it.parent is KtLambdaArgument }
|
||||||
}
|
|
||||||
val inplaceIsAvailable = editor.settings.isVariableInplaceRenameEnabled
|
|
||||||
&& !isTestMode
|
|
||||||
&& !haveLambdaArgumentsToReplace
|
|
||||||
&& expression.extractableSubstringInfo == null
|
|
||||||
&& !expression.mustBeParenthesizedInInitializerPosition()
|
|
||||||
|
|
||||||
val originalExpression = KtPsiUtil.safeDeparenthesize(expression)
|
|
||||||
val psiFactory = KtPsiFactory(project)
|
|
||||||
val introduceParameterDescriptor =
|
|
||||||
helper.configure(
|
|
||||||
IntroduceParameterDescriptor(
|
|
||||||
originalRange = originalExpression.toRange(),
|
|
||||||
callable = targetParent,
|
|
||||||
callableDescriptor = functionDescriptor,
|
|
||||||
newParameterName = suggestedNames.first().quoteIfNeeded(),
|
|
||||||
newParameterTypeText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(replacementType),
|
|
||||||
argumentValue = originalExpression,
|
|
||||||
withDefaultValue = false,
|
|
||||||
parametersUsages = parametersUsages,
|
|
||||||
occurrencesToReplace = occurrencesToReplace,
|
|
||||||
occurrenceReplacer = replacer@ {
|
|
||||||
val expressionToReplace = it.elements.single() as KtExpression
|
|
||||||
val replacingExpression = psiFactory.createExpression(newParameterName)
|
|
||||||
val substringInfo = expressionToReplace.extractableSubstringInfo
|
|
||||||
val result = when {
|
|
||||||
expressionToReplace is KtProperty -> return@replacer expressionToReplace.delete()
|
|
||||||
expressionToReplace.isLambdaOutsideParentheses() -> {
|
|
||||||
expressionToReplace
|
|
||||||
.getStrictParentOfType<KtLambdaArgument>()!!
|
|
||||||
.moveInsideParenthesesAndReplaceWith(replacingExpression, context)
|
|
||||||
}
|
|
||||||
substringInfo != null -> substringInfo.replaceWith(replacingExpression)
|
|
||||||
else -> expressionToReplace.replaced(replacingExpression)
|
|
||||||
}
|
|
||||||
result.removeTemplateEntryBracesIfPossible()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (isTestMode) {
|
|
||||||
introduceParameterDescriptor.performRefactoring()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inplaceIsAvailable) {
|
|
||||||
with(PsiDocumentManager.getInstance(project)) {
|
|
||||||
commitDocument(editor.document)
|
|
||||||
doPostponedOperationsAndUnblockDocument(editor.document)
|
|
||||||
}
|
|
||||||
|
|
||||||
val introducer = KotlinInplaceParameterIntroducer(introduceParameterDescriptor,
|
|
||||||
replacementType,
|
|
||||||
suggestedNames.toTypedArray(),
|
|
||||||
project,
|
|
||||||
editor)
|
|
||||||
if (introducer.startInplaceIntroduceTemplate()) return
|
|
||||||
}
|
|
||||||
|
|
||||||
val dialog = KotlinIntroduceParameterDialog(
|
|
||||||
project,
|
|
||||||
editor,
|
|
||||||
introduceParameterDescriptor,
|
|
||||||
suggestedNames.toTypedArray(),
|
|
||||||
listOf(replacementType) + replacementType.supertypes(),
|
|
||||||
helper
|
|
||||||
)
|
|
||||||
dialog.showWithTransaction()
|
|
||||||
}
|
}
|
||||||
|
val inplaceIsAvailable = editor.settings.isVariableInplaceRenameEnabled
|
||||||
|
&& !isTestMode
|
||||||
|
&& !haveLambdaArgumentsToReplace
|
||||||
|
&& expression.extractableSubstringInfo == null
|
||||||
|
&& !expression.mustBeParenthesizedInInitializerPosition()
|
||||||
|
|
||||||
|
val originalExpression = KtPsiUtil.safeDeparenthesize(expression)
|
||||||
|
val psiFactory = KtPsiFactory(project)
|
||||||
|
val introduceParameterDescriptor =
|
||||||
|
helper.configure(
|
||||||
|
IntroduceParameterDescriptor(
|
||||||
|
originalRange = originalExpression.toRange(),
|
||||||
|
callable = targetParent,
|
||||||
|
callableDescriptor = functionDescriptor,
|
||||||
|
newParameterName = suggestedNames.first().quoteIfNeeded(),
|
||||||
|
newParameterTypeText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(replacementType),
|
||||||
|
argumentValue = originalExpression,
|
||||||
|
withDefaultValue = false,
|
||||||
|
parametersUsages = parametersUsages,
|
||||||
|
occurrencesToReplace = occurrencesToReplace,
|
||||||
|
occurrenceReplacer = replacer@{
|
||||||
|
val expressionToReplace = it.elements.single() as KtExpression
|
||||||
|
val replacingExpression = psiFactory.createExpression(newParameterName)
|
||||||
|
val substringInfo = expressionToReplace.extractableSubstringInfo
|
||||||
|
val result = when {
|
||||||
|
expressionToReplace is KtProperty -> return@replacer expressionToReplace.delete()
|
||||||
|
expressionToReplace.isLambdaOutsideParentheses() -> {
|
||||||
|
expressionToReplace
|
||||||
|
.getStrictParentOfType<KtLambdaArgument>()!!
|
||||||
|
.moveInsideParenthesesAndReplaceWith(replacingExpression, context)
|
||||||
|
}
|
||||||
|
substringInfo != null -> substringInfo.replaceWith(replacingExpression)
|
||||||
|
else -> expressionToReplace.replaced(replacingExpression)
|
||||||
|
}
|
||||||
|
result.removeTemplateEntryBracesIfPossible()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (isTestMode) {
|
||||||
|
introduceParameterDescriptor.performRefactoring()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inplaceIsAvailable) {
|
||||||
|
with(PsiDocumentManager.getInstance(project)) {
|
||||||
|
commitDocument(editor.document)
|
||||||
|
doPostponedOperationsAndUnblockDocument(editor.document)
|
||||||
|
}
|
||||||
|
|
||||||
|
val introducer = KotlinInplaceParameterIntroducer(
|
||||||
|
introduceParameterDescriptor,
|
||||||
|
replacementType,
|
||||||
|
suggestedNames.toTypedArray(),
|
||||||
|
project,
|
||||||
|
editor
|
||||||
|
)
|
||||||
|
if (introducer.startInplaceIntroduceTemplate()) return
|
||||||
|
}
|
||||||
|
|
||||||
|
val dialog = KotlinIntroduceParameterDialog(
|
||||||
|
project,
|
||||||
|
editor,
|
||||||
|
introduceParameterDescriptor,
|
||||||
|
suggestedNames.toTypedArray(),
|
||||||
|
listOf(replacementType) + replacementType.supertypes(),
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
dialog.showWithTransaction()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,8 +389,7 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
val expression = ((elements.singleOrNull() as? KtBlockExpression)?.statements ?: elements).singleOrNull()
|
val expression = ((elements.singleOrNull() as? KtBlockExpression)?.statements ?: elements).singleOrNull()
|
||||||
if (expression is KtExpression) {
|
if (expression is KtExpression) {
|
||||||
invoke(project, editor, expression, targetParent as KtNamedDeclaration)
|
invoke(project, editor, expression, targetParent as KtNamedDeclaration)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PARAMETER)
|
showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PARAMETER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -412,74 +402,75 @@ open class KotlinIntroduceParameterHandler(
|
|||||||
|
|
||||||
private fun DeclarationDescriptor?.toFunctionDescriptor(targetParent: KtNamedDeclaration): FunctionDescriptor {
|
private fun DeclarationDescriptor?.toFunctionDescriptor(targetParent: KtNamedDeclaration): FunctionDescriptor {
|
||||||
val functionDescriptor: FunctionDescriptor? =
|
val functionDescriptor: FunctionDescriptor? =
|
||||||
when (this) {
|
when (this) {
|
||||||
is FunctionDescriptor -> this
|
is FunctionDescriptor -> this
|
||||||
is ClassDescriptor -> this.unsubstitutedPrimaryConstructor
|
is ClassDescriptor -> this.unsubstitutedPrimaryConstructor
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
return functionDescriptor ?: throw AssertionError("Unexpected element type: ${targetParent.getElementTextWithContext()}")
|
return functionDescriptor ?: throw AssertionError("Unexpected element type: ${targetParent.getElementTextWithContext()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findInternalUsagesOfParametersAndReceiver(
|
private fun findInternalUsagesOfParametersAndReceiver(
|
||||||
targetParent: KtNamedDeclaration,
|
targetParent: KtNamedDeclaration,
|
||||||
targetDescriptor: FunctionDescriptor
|
targetDescriptor: FunctionDescriptor
|
||||||
): MultiMap<KtElement, KtElement>? {
|
): MultiMap<KtElement, KtElement>? {
|
||||||
val usages = MultiMap<KtElement, KtElement>()
|
val usages = MultiMap<KtElement, KtElement>()
|
||||||
val searchComplete = targetParent.project.runSynchronouslyWithProgress("Searching usages of '${targetParent.name}' parameter", true) {
|
val searchComplete = targetParent.project.runSynchronouslyWithProgress("Searching usages of '${targetParent.name}' parameter", true) {
|
||||||
runReadAction {
|
runReadAction {
|
||||||
targetParent.getValueParameters()
|
targetParent.getValueParameters()
|
||||||
.filter { !it.hasValOrVar() }
|
.filter { !it.hasValOrVar() }
|
||||||
.forEach {
|
.forEach {
|
||||||
val paramUsages = ReferencesSearch.search(it).map { it.element as KtElement }
|
val paramUsages = ReferencesSearch.search(it).map { reference -> reference.element as KtElement }
|
||||||
if (paramUsages.isNotEmpty()) {
|
if (paramUsages.isNotEmpty()) {
|
||||||
usages.put(it, paramUsages)
|
usages.put(it, paramUsages)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} != null
|
} != null
|
||||||
if (!searchComplete) return null
|
if (!searchComplete) return null
|
||||||
val receiverTypeRef = (targetParent as? KtFunction)?.receiverTypeReference
|
val receiverTypeRef = (targetParent as? KtFunction)?.receiverTypeReference
|
||||||
if (receiverTypeRef != null) {
|
if (receiverTypeRef != null) {
|
||||||
targetParent.acceptChildren(
|
targetParent.acceptChildren(
|
||||||
object : KtTreeVisitorVoid() {
|
object : KtTreeVisitorVoid() {
|
||||||
override fun visitThisExpression(expression: KtThisExpression) {
|
override fun visitThisExpression(expression: KtThisExpression) {
|
||||||
super.visitThisExpression(expression)
|
super.visitThisExpression(expression)
|
||||||
|
|
||||||
if (expression.instanceReference.mainReference.resolve() == targetDescriptor) {
|
if (expression.instanceReference.mainReference.resolve() == targetDescriptor) {
|
||||||
usages.putValue(receiverTypeRef, expression)
|
usages.putValue(receiverTypeRef, expression)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitKtElement(element: KtElement) {
|
|
||||||
super.visitKtElement(element)
|
|
||||||
|
|
||||||
val resolvedCall = element.resolveToCall() ?: return
|
|
||||||
|
|
||||||
if ((resolvedCall.extensionReceiver as? ImplicitReceiver)?.declarationDescriptor == targetDescriptor ||
|
|
||||||
(resolvedCall.dispatchReceiver as? ImplicitReceiver)?.declarationDescriptor == targetDescriptor) {
|
|
||||||
usages.putValue(receiverTypeRef, resolvedCall.call.callElement)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitKtElement(element: KtElement) {
|
||||||
|
super.visitKtElement(element)
|
||||||
|
|
||||||
|
val resolvedCall = element.resolveToCall() ?: return
|
||||||
|
|
||||||
|
if ((resolvedCall.extensionReceiver as? ImplicitReceiver)?.declarationDescriptor == targetDescriptor ||
|
||||||
|
(resolvedCall.dispatchReceiver as? ImplicitReceiver)?.declarationDescriptor == targetDescriptor
|
||||||
|
) {
|
||||||
|
usages.putValue(receiverTypeRef, resolvedCall.call.callElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return usages
|
return usages
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KotlinIntroduceLambdaParameterHelper: KotlinIntroduceParameterHelper {
|
interface KotlinIntroduceLambdaParameterHelper : KotlinIntroduceParameterHelper {
|
||||||
object Default: KotlinIntroduceLambdaParameterHelper
|
object Default : KotlinIntroduceLambdaParameterHelper
|
||||||
|
|
||||||
fun configureExtractLambda(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor = descriptor
|
fun configureExtractLambda(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor = descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
open class KotlinIntroduceLambdaParameterHandler(
|
open class KotlinIntroduceLambdaParameterHandler(
|
||||||
helper: KotlinIntroduceLambdaParameterHelper = KotlinIntroduceLambdaParameterHelper.Default
|
helper: KotlinIntroduceLambdaParameterHelper = KotlinIntroduceLambdaParameterHelper.Default
|
||||||
): KotlinIntroduceParameterHandler(helper) {
|
) : KotlinIntroduceParameterHandler(helper) {
|
||||||
private val extractLambdaHelper = object: ExtractionEngineHelper(INTRODUCE_LAMBDA_PARAMETER) {
|
private val extractLambdaHelper = object : ExtractionEngineHelper(INTRODUCE_LAMBDA_PARAMETER) {
|
||||||
private fun createDialog(
|
private fun createDialog(
|
||||||
project: Project,
|
project: Project,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
lambdaExtractionDescriptor: ExtractableCodeDescriptor
|
lambdaExtractionDescriptor: ExtractableCodeDescriptor
|
||||||
): KotlinIntroduceParameterDialog? {
|
): KotlinIntroduceParameterDialog? {
|
||||||
val callable = lambdaExtractionDescriptor.extractionData.targetSibling as KtNamedDeclaration
|
val callable = lambdaExtractionDescriptor.extractionData.targetSibling as KtNamedDeclaration
|
||||||
val descriptor = callable.unsafeResolveToDescriptor()
|
val descriptor = callable.unsafeResolveToDescriptor()
|
||||||
@@ -487,26 +478,26 @@ open class KotlinIntroduceLambdaParameterHandler(
|
|||||||
val originalRange = lambdaExtractionDescriptor.extractionData.originalRange
|
val originalRange = lambdaExtractionDescriptor.extractionData.originalRange
|
||||||
val parametersUsages = findInternalUsagesOfParametersAndReceiver(callable, callableDescriptor) ?: return null
|
val parametersUsages = findInternalUsagesOfParametersAndReceiver(callable, callableDescriptor) ?: return null
|
||||||
val introduceParameterDescriptor = IntroduceParameterDescriptor(
|
val introduceParameterDescriptor = IntroduceParameterDescriptor(
|
||||||
originalRange = originalRange,
|
originalRange = originalRange,
|
||||||
callable = callable,
|
callable = callable,
|
||||||
callableDescriptor = callableDescriptor,
|
callableDescriptor = callableDescriptor,
|
||||||
newParameterName = "", // to be chosen in the dialog
|
newParameterName = "", // to be chosen in the dialog
|
||||||
newParameterTypeText = "", // to be chosen in the dialog
|
newParameterTypeText = "", // to be chosen in the dialog
|
||||||
argumentValue = KtPsiFactory(project).createExpression("{}"), // substituted later
|
argumentValue = KtPsiFactory(project).createExpression("{}"), // substituted later
|
||||||
withDefaultValue = false,
|
withDefaultValue = false,
|
||||||
parametersUsages = parametersUsages,
|
parametersUsages = parametersUsages,
|
||||||
occurrencesToReplace = listOf(originalRange),
|
occurrencesToReplace = listOf(originalRange),
|
||||||
parametersToRemove = listOf()
|
parametersToRemove = listOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
return KotlinIntroduceParameterDialog(project, editor, introduceParameterDescriptor, lambdaExtractionDescriptor, helper)
|
return KotlinIntroduceParameterDialog(project, editor, introduceParameterDescriptor, lambdaExtractionDescriptor, helper)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun configureAndRun(
|
override fun configureAndRun(
|
||||||
project: Project,
|
project: Project,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts,
|
descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts,
|
||||||
onFinish: (ExtractionResult) -> Unit
|
onFinish: (ExtractionResult) -> Unit
|
||||||
) {
|
) {
|
||||||
val lambdaExtractionDescriptor = helper.configureExtractLambda(descriptorWithConflicts.descriptor)
|
val lambdaExtractionDescriptor = helper.configureExtractLambda(descriptorWithConflicts.descriptor)
|
||||||
if (!ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION.isAvailable(lambdaExtractionDescriptor)) {
|
if (!ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION.isAvailable(lambdaExtractionDescriptor)) {
|
||||||
@@ -517,8 +508,7 @@ open class KotlinIntroduceLambdaParameterHandler(
|
|||||||
val dialog = createDialog(project, editor, lambdaExtractionDescriptor) ?: return
|
val dialog = createDialog(project, editor, lambdaExtractionDescriptor) ?: return
|
||||||
if (ApplicationManager.getApplication()!!.isUnitTestMode) {
|
if (ApplicationManager.getApplication()!!.isUnitTestMode) {
|
||||||
dialog.performRefactoring()
|
dialog.performRefactoring()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dialog.showWithTransaction()
|
dialog.showWithTransaction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -526,21 +516,23 @@ open class KotlinIntroduceLambdaParameterHandler(
|
|||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor, expression: KtExpression, targetParent: KtNamedDeclaration) {
|
override fun invoke(project: Project, editor: Editor, expression: KtExpression, targetParent: KtNamedDeclaration) {
|
||||||
val duplicateContainer =
|
val duplicateContainer =
|
||||||
when (targetParent) {
|
when (targetParent) {
|
||||||
is KtFunction -> targetParent.bodyExpression
|
is KtFunction -> targetParent.bodyExpression
|
||||||
is KtClass -> targetParent.getBody()
|
is KtClass -> targetParent.body
|
||||||
else -> null
|
else -> null
|
||||||
} ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}")
|
} ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}")
|
||||||
val extractionData = ExtractionData(targetParent.containingKtFile,
|
val extractionData = ExtractionData(
|
||||||
expression.toRange(),
|
targetParent.containingKtFile,
|
||||||
targetParent,
|
expression.toRange(),
|
||||||
duplicateContainer,
|
targetParent,
|
||||||
ExtractionOptions.DEFAULT)
|
duplicateContainer,
|
||||||
|
ExtractionOptions.DEFAULT
|
||||||
|
)
|
||||||
ExtractionEngine(extractLambdaHelper).run(editor, extractionData)
|
ExtractionEngine(extractLambdaHelper).run(editor, extractionData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val INTRODUCE_PARAMETER_REFACTORING_ID: String = "kotlin.refactoring.introduceParameter"
|
const val INTRODUCE_PARAMETER_REFACTORING_ID: String = "kotlin.refactoring.introduceParameter"
|
||||||
|
|
||||||
val INTRODUCE_PARAMETER: String = "Introduce Parameter"
|
const val INTRODUCE_PARAMETER: String = "Introduce Parameter"
|
||||||
val INTRODUCE_LAMBDA_PARAMETER: String = "Introduce Lambda Parameter"
|
const val INTRODUCE_LAMBDA_PARAMETER: String = "Introduce Lambda Parameter"
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.pullUp
|
package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||||
@@ -21,7 +10,6 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
import com.intellij.refactoring.HelpID
|
import com.intellij.refactoring.HelpID
|
||||||
@@ -44,12 +32,12 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||||
|
|
||||||
class KotlinPullUpHandler : AbstractPullPushMembersHandler(
|
class KotlinPullUpHandler : AbstractPullPushMembersHandler(
|
||||||
refactoringName = PULL_MEMBERS_UP,
|
refactoringName = PULL_MEMBERS_UP,
|
||||||
helpId = HelpID.MEMBERS_PULL_UP,
|
helpId = HelpID.MEMBERS_PULL_UP,
|
||||||
wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.pull.members.from")
|
wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.pull.members.from")
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val PULL_UP_TEST_HELPER_KEY = "PULL_UP_TEST_HELPER_KEY"
|
const val PULL_UP_TEST_HELPER_KEY = "PULL_UP_TEST_HELPER_KEY"
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TestHelper {
|
interface TestHelper {
|
||||||
@@ -59,17 +47,21 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler(
|
|||||||
|
|
||||||
private fun reportNoSuperClasses(project: Project, editor: Editor?, classOrObject: KtClassOrObject) {
|
private fun reportNoSuperClasses(project: Project, editor: Editor?, classOrObject: KtClassOrObject) {
|
||||||
val message = RefactoringBundle.getCannotRefactorMessage(
|
val message = RefactoringBundle.getCannotRefactorMessage(
|
||||||
RefactoringBundle.message("class.does.not.have.base.classes.interfaces.in.current.project",
|
RefactoringBundle.message(
|
||||||
classOrObject.qualifiedClassNameForRendering())
|
"class.does.not.have.base.classes.interfaces.in.current.project",
|
||||||
|
classOrObject.qualifiedClassNameForRendering()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
CommonRefactoringUtil.showErrorHint(project, editor, message, PULL_MEMBERS_UP, HelpID.MEMBERS_PULL_UP)
|
CommonRefactoringUtil.showErrorHint(project, editor, message, PULL_MEMBERS_UP, HelpID.MEMBERS_PULL_UP)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(project: Project,
|
override fun invoke(
|
||||||
editor: Editor?,
|
project: Project,
|
||||||
classOrObject: KtClassOrObject?,
|
editor: Editor?,
|
||||||
member: KtNamedDeclaration?,
|
classOrObject: KtClassOrObject?,
|
||||||
dataContext: DataContext?) {
|
member: KtNamedDeclaration?,
|
||||||
|
dataContext: DataContext?
|
||||||
|
) {
|
||||||
if (classOrObject == null) {
|
if (classOrObject == null) {
|
||||||
reportWrongContext(project, editor)
|
reportWrongContext(project, editor)
|
||||||
return
|
return
|
||||||
@@ -77,21 +69,23 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler(
|
|||||||
|
|
||||||
val classDescriptor = classOrObject.unsafeResolveToDescriptor() as ClassDescriptor
|
val classDescriptor = classOrObject.unsafeResolveToDescriptor() as ClassDescriptor
|
||||||
val superClasses = classDescriptor.defaultType
|
val superClasses = classDescriptor.defaultType
|
||||||
.supertypes()
|
.supertypes()
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
val descriptor = it.constructor.declarationDescriptor
|
val descriptor = it.constructor.declarationDescriptor
|
||||||
val declaration = descriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
val declaration = descriptor?.let { classifierDescriptor ->
|
||||||
if ((declaration is KtClass || declaration is PsiClass)
|
DescriptorToSourceUtilsIde.getAnyDeclaration(project, classifierDescriptor)
|
||||||
&& declaration.canRefactor()) declaration as PsiNamedElement else null
|
|
||||||
}
|
}
|
||||||
.sortedBy { it.qualifiedClassNameForRendering() }
|
if ((declaration is KtClass || declaration is PsiClass)
|
||||||
|
&& declaration.canRefactor()
|
||||||
|
) declaration as PsiNamedElement else null
|
||||||
|
}
|
||||||
|
.sortedBy { it.qualifiedClassNameForRendering() }
|
||||||
|
|
||||||
if (superClasses.isEmpty()) {
|
if (superClasses.isEmpty()) {
|
||||||
val containingClass = classOrObject.getStrictParentOfType<KtClassOrObject>()
|
val containingClass = classOrObject.getStrictParentOfType<KtClassOrObject>()
|
||||||
if (containingClass != null) {
|
if (containingClass != null) {
|
||||||
invoke(project, editor, containingClass, classOrObject, dataContext)
|
invoke(project, editor, containingClass, classOrObject, dataContext)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reportNoSuperClasses(project, editor, classOrObject)
|
reportNoSuperClasses(project, editor, classOrObject)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -107,8 +101,7 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler(
|
|||||||
checkConflicts(project, classOrObject, targetClass, selectedMembers) {
|
checkConflicts(project, classOrObject, targetClass, selectedMembers) {
|
||||||
KotlinPullUpDialog.createProcessor(classOrObject, targetClass, selectedMembers).run()
|
KotlinPullUpDialog.createProcessor(classOrObject, targetClass, selectedMembers).run()
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val manager = classOrObject.manager
|
val manager = classOrObject.manager
|
||||||
members.filter { manager.areElementsEquivalent(it.member, member) }.forEach { it.isChecked = true }
|
members.filter { manager.areElementsEquivalent(it.member, member) }.forEach { it.isChecked = true }
|
||||||
|
|
||||||
@@ -122,4 +115,4 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val PULL_MEMBERS_UP = "Pull Members Up"
|
const val PULL_MEMBERS_UP = "Pull Members Up"
|
||||||
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.pushDown
|
package org.jetbrains.kotlin.idea.refactoring.pushDown
|
||||||
@@ -20,7 +9,6 @@ import com.intellij.openapi.actionSystem.DataContext
|
|||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
import com.intellij.refactoring.HelpID
|
import com.intellij.refactoring.HelpID
|
||||||
@@ -39,15 +27,15 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
|||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
|
|
||||||
val PUSH_MEMBERS_DOWN = "Push Members Down"
|
const val PUSH_MEMBERS_DOWN = "Push Members Down"
|
||||||
|
|
||||||
class KotlinPushDownHandler : AbstractPullPushMembersHandler(
|
class KotlinPushDownHandler : AbstractPullPushMembersHandler(
|
||||||
refactoringName = PUSH_MEMBERS_DOWN,
|
refactoringName = PUSH_MEMBERS_DOWN,
|
||||||
helpId = HelpID.MEMBERS_PUSH_DOWN,
|
helpId = HelpID.MEMBERS_PUSH_DOWN,
|
||||||
wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.push.members.from")
|
wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.push.members.from")
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val PUSH_DOWN_TEST_HELPER_KEY = "PUSH_DOWN_TEST_HELPER_KEY"
|
const val PUSH_DOWN_TEST_HELPER_KEY = "PUSH_DOWN_TEST_HELPER_KEY"
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TestHelper {
|
interface TestHelper {
|
||||||
@@ -56,16 +44,18 @@ class KotlinPushDownHandler : AbstractPullPushMembersHandler(
|
|||||||
|
|
||||||
private fun reportFinalClassOrObject(project: Project, editor: Editor?, classOrObject: KtClassOrObject) {
|
private fun reportFinalClassOrObject(project: Project, editor: Editor?, classOrObject: KtClassOrObject) {
|
||||||
val message = RefactoringBundle.getCannotRefactorMessage(
|
val message = RefactoringBundle.getCannotRefactorMessage(
|
||||||
"${RefactoringUIUtil.getDescription(classOrObject, false)} is final".capitalize()
|
"${RefactoringUIUtil.getDescription(classOrObject, false)} is final".capitalize()
|
||||||
)
|
)
|
||||||
CommonRefactoringUtil.showErrorHint(project, editor, message, PULL_MEMBERS_UP, HelpID.MEMBERS_PULL_UP)
|
CommonRefactoringUtil.showErrorHint(project, editor, message, PULL_MEMBERS_UP, HelpID.MEMBERS_PULL_UP)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(project: Project,
|
override fun invoke(
|
||||||
editor: Editor?,
|
project: Project,
|
||||||
classOrObject: KtClassOrObject?,
|
editor: Editor?,
|
||||||
member: KtNamedDeclaration?,
|
classOrObject: KtClassOrObject?,
|
||||||
dataContext: DataContext?) {
|
member: KtNamedDeclaration?,
|
||||||
|
dataContext: DataContext?
|
||||||
|
) {
|
||||||
if (classOrObject == null) {
|
if (classOrObject == null) {
|
||||||
reportWrongContext(project, editor)
|
reportWrongContext(project, editor)
|
||||||
return
|
return
|
||||||
@@ -81,8 +71,7 @@ class KotlinPushDownHandler : AbstractPullPushMembersHandler(
|
|||||||
val helper = dataContext?.getData(PUSH_DOWN_TEST_HELPER_KEY) as TestHelper
|
val helper = dataContext?.getData(PUSH_DOWN_TEST_HELPER_KEY) as TestHelper
|
||||||
val selectedMembers = helper.adjustMembers(members)
|
val selectedMembers = helper.adjustMembers(members)
|
||||||
KotlinPushDownProcessor(project, classOrObject, selectedMembers).run()
|
KotlinPushDownProcessor(project, classOrObject, selectedMembers).run()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val manager = PsiManager.getInstance(project)
|
val manager = PsiManager.getInstance(project)
|
||||||
members.filter { manager.areElementsEquivalent(it.member, member) }.forEach { it.isChecked = true }
|
members.filter { manager.areElementsEquivalent(it.member, member) }.forEach { it.isChecked = true }
|
||||||
KotlinPushDownDialog(project, members, classOrObject).show()
|
KotlinPushDownDialog(project, members, classOrObject).show()
|
||||||
|
|||||||
Reference in New Issue
Block a user