From 795dcfa8ffdc4812d9fcbc0360be6cbb92451420 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Fri, 5 Jul 2019 15:12:46 +0700 Subject: [PATCH] Minor: clean up some quickfixes & refactorings --- .../idea/quickfix/RemoveUselessCastFix.kt | 18 +- .../DeprecatedSymbolUsageInWholeProjectFix.kt | 32 +- .../AbstractPullPushMembersHandler.kt | 30 +- .../KotlinIntroduceParameterHandler.kt | 408 +++++++++--------- .../refactoring/pullUp/KotlinPullUpHandler.kt | 67 ++- .../pushDown/KotlinPushDownHandler.kt | 43 +- 6 files changed, 269 insertions(+), 329 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUselessCastFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUselessCastFix.kt index 2245804c11c..82188292a42 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUselessCastFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUselessCastFix.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 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. + * 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. */ 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.psiUtil.getNonStrictParentOfType -class RemoveUselessCastFix(element: KtBinaryExpressionWithTypeRHS) : KotlinQuickFixAction(element), CleanupFix { +class RemoveUselessCastFix(element: KtBinaryExpressionWithTypeRHS) : KotlinQuickFixAction(element), + CleanupFix { override fun getFamilyName() = "Remove useless cast" override fun getText(): String = familyName diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt index 9b72f8117f9..ce168c28c59 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt @@ -1,17 +1,6 @@ /* - * 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. + * 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. */ package org.jetbrains.kotlin.idea.quickfix.replaceWith @@ -51,16 +40,13 @@ class DeprecatedSymbolUsageInWholeProjectFix( replacementStrategy.replaceUsagesInWholeProject(psiElement, progressTitle = "Applying '$text'", commandName = text) } - private fun targetPsiElement(): KtDeclaration? { - val referenceTarget = element?.mainReference?.resolve() - return when (referenceTarget) { - is KtNamedFunction -> referenceTarget - is KtProperty -> referenceTarget - is KtTypeAlias -> referenceTarget - is KtConstructor<*> -> referenceTarget.getContainingClassOrObject() //TODO: constructor can be deprecated itself - is KtClass -> referenceTarget.takeIf { it.isAnnotation() } - else -> null - } + private fun targetPsiElement(): KtDeclaration? = when (val referenceTarget = element?.mainReference?.resolve()) { + is KtNamedFunction -> referenceTarget + is KtProperty -> referenceTarget + is KtTypeAlias -> referenceTarget + is KtConstructor<*> -> referenceTarget.getContainingClassOrObject() //TODO: constructor can be deprecated itself + is KtClass -> referenceTarget.takeIf { it.isAnnotation() } + else -> null } companion object : KotlinSingleIntentionActionFactory() { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt index d1d8cd7cc32..3eae651354b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 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. + * 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. */ package org.jetbrains.kotlin.idea.refactoring @@ -34,20 +23,21 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import java.util.* abstract class AbstractPullPushMembersHandler( - private val refactoringName: String, - private val helpId: String, - private val wrongPositionMessage: String + private val refactoringName: String, + private val helpId: String, + private val wrongPositionMessage: String ) : RefactoringActionHandler, ElementsHandler { private fun reportWrongPosition(project: Project, editor: Editor?) { val message = RefactoringBundle.getCannotRefactorMessage(wrongPositionMessage) 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?) { 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) } @@ -64,8 +54,8 @@ abstract class AbstractPullPushMembersHandler( val target = (file.findElementAt(offset) ?: return).parentsWithSelf.firstOrNull { it is KtClassOrObject - || ((it is KtNamedFunction || it is KtProperty) && it.parent is KtClassBody) - || it is KtParameter && it.hasValOrVar() && it.ownerFunction is KtPrimaryConstructor + || ((it is KtNamedFunction || it is KtProperty) && it.parent is KtClassBody) + || it is KtParameter && it.hasValOrVar() && it.ownerFunction is KtPrimaryConstructor } if (target == null) { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt index 6786c1fb0d5..b4500c9c896 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 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. + * 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. */ package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter @@ -66,23 +55,22 @@ import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* data class IntroduceParameterDescriptor( - val originalRange: KotlinPsiRange, - val callable: KtNamedDeclaration, - val callableDescriptor: FunctionDescriptor, - val newParameterName: String, - val newParameterTypeText: String, - val argumentValue: KtExpression, - val withDefaultValue: Boolean, - val parametersUsages: MultiMap, - val occurrencesToReplace: List, - val parametersToRemove: List = getParametersToRemove(withDefaultValue, parametersUsages, occurrencesToReplace), - val occurrenceReplacer: IntroduceParameterDescriptor.(KotlinPsiRange) -> Unit = {} + val originalRange: KotlinPsiRange, + val callable: KtNamedDeclaration, + val callableDescriptor: FunctionDescriptor, + val newParameterName: String, + val newParameterTypeText: String, + val argumentValue: KtExpression, + val withDefaultValue: Boolean, + val parametersUsages: MultiMap, + val occurrencesToReplace: List, + val parametersToRemove: List = getParametersToRemove(withDefaultValue, parametersUsages, occurrencesToReplace), + val occurrenceReplacer: IntroduceParameterDescriptor.(KotlinPsiRange) -> Unit = {} ) { val newArgumentValue: KtExpression by lazy { if (argumentValue.mustBeParenthesizedInInitializerPosition()) { KtPsiFactory(callable).createExpressionByPattern("($0)", argumentValue) - } - else { + } else { argumentValue } } @@ -95,7 +83,7 @@ data class IntroduceParameterDescriptor( valVar = if (callable is KtClass) { val modifierIsUnnecessary: (PsiElement) -> Boolean = { when { - it.parent != callable.getBody() -> + it.parent != callable.body -> false it is KtAnonymousInitializer -> true @@ -106,17 +94,16 @@ data class IntroduceParameterDescriptor( } } if (occurrencesToReplace.all { - PsiTreeUtil.findCommonParent(it.elements)?.parentsWithSelf?.any(modifierIsUnnecessary) ?: false - }) KotlinValVar.None else KotlinValVar.Val - } - else KotlinValVar.None + PsiTreeUtil.findCommonParent(it.elements)?.parentsWithSelf?.any(modifierIsUnnecessary) == true + }) KotlinValVar.None else KotlinValVar.Val + } else KotlinValVar.None } } fun getParametersToRemove( - withDefaultValue: Boolean, - parametersUsages: MultiMap, - occurrencesToReplace: List + withDefaultValue: Boolean, + parametersUsages: MultiMap, + occurrencesToReplace: List ): List { if (withDefaultValue) return Collections.emptyList() @@ -146,15 +133,17 @@ fun IntroduceParameterDescriptor.performRefactoring(onExit: (() -> Unit)? = null } else 0 } .sortedDescending() - .forEach { methodDescriptor.removeParameter(it) } + .forEach { methodDescriptor.removeParameter(it) } } val defaultValue = if (newArgumentValue is KtProperty) (newArgumentValue as KtProperty).initializer else newArgumentValue - val parameterInfo = KotlinParameterInfo(callableDescriptor = callableDescriptor, - name = newParameterName, - defaultValueForCall = if (withDefaultValue) null else defaultValue, - defaultValueForParameter = if (withDefaultValue) defaultValue else null, - valOrVar = valVar) + val parameterInfo = KotlinParameterInfo( + callableDescriptor = callableDescriptor, + name = newParameterName, + defaultValueForCall = if (withDefaultValue) null else defaultValue, + defaultValueForParameter = if (withDefaultValue) defaultValue else null, + valOrVar = valVar + ) parameterInfo.currentTypeInfo = KotlinTypeInfo(false, null, newParameterTypeText) methodDescriptor.addParameter(parameterInfo) } @@ -180,9 +169,9 @@ fun IntroduceParameterDescriptor.performRefactoring(onExit: (() -> Unit)? = null } fun selectNewParameterContext( - editor: Editor, - file: KtFile, - continuation: (elements: List, targetParent: PsiElement) -> Unit + editor: Editor, + file: KtFile, + continuation: (elements: List, targetParent: PsiElement) -> Unit ) { selectElementsWithTargetParent( operationName = INTRODUCE_PARAMETER, @@ -192,24 +181,24 @@ fun selectNewParameterContext( elementKinds = listOf(CodeInsightUtils.ElementKind.EXPRESSION), elementValidator = ::validateExpressionElements, getContainers = { _, parent -> - val parents = parent.parents - val stopAt = (parent.parents.zip(parent.parents.drop(1))) - .firstOrNull { isObjectOrNonInnerClass(it.first) } - ?.second + val parents = parent.parents + val stopAt = (parent.parents.zip(parent.parents.drop(1))) + .firstOrNull { isObjectOrNonInnerClass(it.first) } + ?.second - (if (stopAt != null) parent.parents.takeWhile { it != stopAt } else parents) - .filter { - ((it is KtClass && !it.isInterface() && it !is KtEnumEntry) || it is KtNamedFunction || it is KtSecondaryConstructor) && + (if (stopAt != null) parent.parents.takeWhile { it != stopAt } else parents) + .filter { + ((it is KtClass && !it.isInterface() && it !is KtEnumEntry) || it is KtNamedFunction || it is KtSecondaryConstructor) && ((it as KtNamedDeclaration).getValueParameterList() != null || it.nameIdentifier != null) - } - .toList() - }, + } + .toList() + }, continuation = continuation ) } interface KotlinIntroduceParameterHelper { - object Default: KotlinIntroduceParameterHelper + object Default : KotlinIntroduceParameterHelper fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor = descriptor } @@ -228,8 +217,7 @@ open class KotlinIntroduceParameterHandler( val expressionType = if (physicalExpression is KtProperty && physicalExpression.isLocal) { context[BindingContext.VARIABLE, physicalExpression]?.type - } - else { + } else { expression.extractableSubstringInfo?.type ?: context.getType(physicalExpression) } @@ -240,8 +228,8 @@ open class KotlinIntroduceParameterHandler( if (expressionType.isUnit() || expressionType.isNothing()) { val message = KotlinRefactoringBundle.message( - "cannot.introduce.parameter.of.0.type", - IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(expressionType) + "cannot.introduce.parameter.of.0.type", + IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(expressionType) ) showErrorHint(project, editor, message, INTRODUCE_PARAMETER) return @@ -249,15 +237,18 @@ open class KotlinIntroduceParameterHandler( val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, 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) { is KtFunction -> targetParent.bodyExpression - is KtClass -> targetParent.getBody() + is KtClass -> targetParent.body else -> null } 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 suggestedNames = SmartList().apply { @@ -277,18 +268,16 @@ open class KotlinIntroduceParameterHandler( val occurrencesToReplace = if (expression is KtProperty) { ReferencesSearch.search(expression).mapNotNullTo(SmartList(expression.toRange())) { it.element.toRange() } - } - else { + } else { expression.toRange() .match(targetParent, KotlinPsiUnifier.DEFAULT) .asSequence() .filterNot { val textRange = it.range.getPhysicalTextRange() - forbiddenRanges.any { it.intersects(textRange) } + forbiddenRanges.any { range -> range.intersects(textRange) } } .mapNotNull { - val matchedElement = it.range.elements.singleOrNull() - val matchedExpr = when (matchedElement) { + val matchedExpr = when (val matchedElement = it.range.elements.singleOrNull()) { is KtExpression -> matchedElement is KtStringTemplateEntryWithExpression -> matchedElement.expression else -> null @@ -299,80 +288,82 @@ open class KotlinIntroduceParameterHandler( } project.executeCommand( - INTRODUCE_PARAMETER, - null, - fun() { - val isTestMode = ApplicationManager.getApplication().isUnitTestMode - val haveLambdaArgumentsToReplace = occurrencesToReplace.any { - it.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()!! - .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() + INTRODUCE_PARAMETER, + null, + fun() { + val isTestMode = ApplicationManager.getApplication().isUnitTestMode + val haveLambdaArgumentsToReplace = occurrencesToReplace.any { range -> + 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()!! + .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() if (expression is KtExpression) { invoke(project, editor, expression, targetParent as KtNamedDeclaration) - } - else { + } else { showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PARAMETER) } } @@ -412,74 +402,75 @@ open class KotlinIntroduceParameterHandler( private fun DeclarationDescriptor?.toFunctionDescriptor(targetParent: KtNamedDeclaration): FunctionDescriptor { val functionDescriptor: FunctionDescriptor? = - when (this) { - is FunctionDescriptor -> this - is ClassDescriptor -> this.unsubstitutedPrimaryConstructor - else -> null - } + when (this) { + is FunctionDescriptor -> this + is ClassDescriptor -> this.unsubstitutedPrimaryConstructor + else -> null + } return functionDescriptor ?: throw AssertionError("Unexpected element type: ${targetParent.getElementTextWithContext()}") } private fun findInternalUsagesOfParametersAndReceiver( - targetParent: KtNamedDeclaration, - targetDescriptor: FunctionDescriptor + targetParent: KtNamedDeclaration, + targetDescriptor: FunctionDescriptor ): MultiMap? { val usages = MultiMap() val searchComplete = targetParent.project.runSynchronouslyWithProgress("Searching usages of '${targetParent.name}' parameter", true) { runReadAction { targetParent.getValueParameters() - .filter { !it.hasValOrVar() } - .forEach { - val paramUsages = ReferencesSearch.search(it).map { it.element as KtElement } - if (paramUsages.isNotEmpty()) { - usages.put(it, paramUsages) - } + .filter { !it.hasValOrVar() } + .forEach { + val paramUsages = ReferencesSearch.search(it).map { reference -> reference.element as KtElement } + if (paramUsages.isNotEmpty()) { + usages.put(it, paramUsages) } + } } } != null if (!searchComplete) return null val receiverTypeRef = (targetParent as? KtFunction)?.receiverTypeReference if (receiverTypeRef != null) { targetParent.acceptChildren( - object : KtTreeVisitorVoid() { - override fun visitThisExpression(expression: KtThisExpression) { - super.visitThisExpression(expression) + object : KtTreeVisitorVoid() { + override fun visitThisExpression(expression: KtThisExpression) { + super.visitThisExpression(expression) - if (expression.instanceReference.mainReference.resolve() == targetDescriptor) { - 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) - } + if (expression.instanceReference.mainReference.resolve() == targetDescriptor) { + 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) + } + } + } ) } return usages } -interface KotlinIntroduceLambdaParameterHelper: KotlinIntroduceParameterHelper { - object Default: KotlinIntroduceLambdaParameterHelper +interface KotlinIntroduceLambdaParameterHelper : KotlinIntroduceParameterHelper { + object Default : KotlinIntroduceLambdaParameterHelper fun configureExtractLambda(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor = descriptor } open class KotlinIntroduceLambdaParameterHandler( - helper: KotlinIntroduceLambdaParameterHelper = KotlinIntroduceLambdaParameterHelper.Default -): KotlinIntroduceParameterHandler(helper) { - private val extractLambdaHelper = object: ExtractionEngineHelper(INTRODUCE_LAMBDA_PARAMETER) { + helper: KotlinIntroduceLambdaParameterHelper = KotlinIntroduceLambdaParameterHelper.Default +) : KotlinIntroduceParameterHandler(helper) { + private val extractLambdaHelper = object : ExtractionEngineHelper(INTRODUCE_LAMBDA_PARAMETER) { private fun createDialog( - project: Project, - editor: Editor, - lambdaExtractionDescriptor: ExtractableCodeDescriptor + project: Project, + editor: Editor, + lambdaExtractionDescriptor: ExtractableCodeDescriptor ): KotlinIntroduceParameterDialog? { val callable = lambdaExtractionDescriptor.extractionData.targetSibling as KtNamedDeclaration val descriptor = callable.unsafeResolveToDescriptor() @@ -487,26 +478,26 @@ open class KotlinIntroduceLambdaParameterHandler( val originalRange = lambdaExtractionDescriptor.extractionData.originalRange val parametersUsages = findInternalUsagesOfParametersAndReceiver(callable, callableDescriptor) ?: return null val introduceParameterDescriptor = IntroduceParameterDescriptor( - originalRange = originalRange, - callable = callable, - callableDescriptor = callableDescriptor, - newParameterName = "", // to be chosen in the dialog - newParameterTypeText = "", // to be chosen in the dialog - argumentValue = KtPsiFactory(project).createExpression("{}"), // substituted later - withDefaultValue = false, - parametersUsages = parametersUsages, - occurrencesToReplace = listOf(originalRange), - parametersToRemove = listOf() + originalRange = originalRange, + callable = callable, + callableDescriptor = callableDescriptor, + newParameterName = "", // to be chosen in the dialog + newParameterTypeText = "", // to be chosen in the dialog + argumentValue = KtPsiFactory(project).createExpression("{}"), // substituted later + withDefaultValue = false, + parametersUsages = parametersUsages, + occurrencesToReplace = listOf(originalRange), + parametersToRemove = listOf() ) return KotlinIntroduceParameterDialog(project, editor, introduceParameterDescriptor, lambdaExtractionDescriptor, helper) } override fun configureAndRun( - project: Project, - editor: Editor, - descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts, - onFinish: (ExtractionResult) -> Unit + project: Project, + editor: Editor, + descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts, + onFinish: (ExtractionResult) -> Unit ) { val lambdaExtractionDescriptor = helper.configureExtractLambda(descriptorWithConflicts.descriptor) if (!ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION.isAvailable(lambdaExtractionDescriptor)) { @@ -517,8 +508,7 @@ open class KotlinIntroduceLambdaParameterHandler( val dialog = createDialog(project, editor, lambdaExtractionDescriptor) ?: return if (ApplicationManager.getApplication()!!.isUnitTestMode) { dialog.performRefactoring() - } - else { + } else { dialog.showWithTransaction() } } @@ -526,21 +516,23 @@ open class KotlinIntroduceLambdaParameterHandler( override fun invoke(project: Project, editor: Editor, expression: KtExpression, targetParent: KtNamedDeclaration) { val duplicateContainer = - when (targetParent) { - is KtFunction -> targetParent.bodyExpression - is KtClass -> targetParent.getBody() - else -> null - } ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}") - val extractionData = ExtractionData(targetParent.containingKtFile, - expression.toRange(), - targetParent, - duplicateContainer, - ExtractionOptions.DEFAULT) + when (targetParent) { + is KtFunction -> targetParent.bodyExpression + is KtClass -> targetParent.body + else -> null + } ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}") + val extractionData = ExtractionData( + targetParent.containingKtFile, + expression.toRange(), + targetParent, + duplicateContainer, + ExtractionOptions.DEFAULT + ) 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" -val INTRODUCE_LAMBDA_PARAMETER: String = "Introduce Lambda Parameter" +const val INTRODUCE_PARAMETER: String = "Introduce Parameter" +const val INTRODUCE_LAMBDA_PARAMETER: String = "Introduce Lambda Parameter" diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHandler.kt index d654a782a91..eeb22297890 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHandler.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 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. + * 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. */ 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.project.Project import com.intellij.psi.PsiClass -import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiNamedElement import com.intellij.refactoring.HelpID @@ -44,12 +32,12 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.types.typeUtil.supertypes class KotlinPullUpHandler : AbstractPullPushMembersHandler( - refactoringName = PULL_MEMBERS_UP, - helpId = HelpID.MEMBERS_PULL_UP, - wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.pull.members.from") + refactoringName = PULL_MEMBERS_UP, + helpId = HelpID.MEMBERS_PULL_UP, + wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.pull.members.from") ) { 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 { @@ -59,17 +47,21 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler( private fun reportNoSuperClasses(project: Project, editor: Editor?, classOrObject: KtClassOrObject) { val message = RefactoringBundle.getCannotRefactorMessage( - RefactoringBundle.message("class.does.not.have.base.classes.interfaces.in.current.project", - classOrObject.qualifiedClassNameForRendering()) + RefactoringBundle.message( + "class.does.not.have.base.classes.interfaces.in.current.project", + classOrObject.qualifiedClassNameForRendering() + ) ) CommonRefactoringUtil.showErrorHint(project, editor, message, PULL_MEMBERS_UP, HelpID.MEMBERS_PULL_UP) } - override fun invoke(project: Project, - editor: Editor?, - classOrObject: KtClassOrObject?, - member: KtNamedDeclaration?, - dataContext: DataContext?) { + override fun invoke( + project: Project, + editor: Editor?, + classOrObject: KtClassOrObject?, + member: KtNamedDeclaration?, + dataContext: DataContext? + ) { if (classOrObject == null) { reportWrongContext(project, editor) return @@ -77,21 +69,23 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler( val classDescriptor = classOrObject.unsafeResolveToDescriptor() as ClassDescriptor val superClasses = classDescriptor.defaultType - .supertypes() - .mapNotNull { - val descriptor = it.constructor.declarationDescriptor - val declaration = descriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) } - if ((declaration is KtClass || declaration is PsiClass) - && declaration.canRefactor()) declaration as PsiNamedElement else null + .supertypes() + .mapNotNull { + val descriptor = it.constructor.declarationDescriptor + val declaration = descriptor?.let { classifierDescriptor -> + DescriptorToSourceUtilsIde.getAnyDeclaration(project, classifierDescriptor) } - .sortedBy { it.qualifiedClassNameForRendering() } + if ((declaration is KtClass || declaration is PsiClass) + && declaration.canRefactor() + ) declaration as PsiNamedElement else null + } + .sortedBy { it.qualifiedClassNameForRendering() } if (superClasses.isEmpty()) { val containingClass = classOrObject.getStrictParentOfType() if (containingClass != null) { invoke(project, editor, containingClass, classOrObject, dataContext) - } - else { + } else { reportNoSuperClasses(project, editor, classOrObject) } return @@ -107,8 +101,7 @@ class KotlinPullUpHandler : AbstractPullPushMembersHandler( checkConflicts(project, classOrObject, targetClass, selectedMembers) { KotlinPullUpDialog.createProcessor(classOrObject, targetClass, selectedMembers).run() } - } - else { + } else { val manager = classOrObject.manager 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" \ No newline at end of file +const val PULL_MEMBERS_UP = "Pull Members Up" \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt index a6fe3a4bfb4..18856e22589 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 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. + * 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. */ 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.editor.Editor import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager 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.KtParameter -val PUSH_MEMBERS_DOWN = "Push Members Down" +const val PUSH_MEMBERS_DOWN = "Push Members Down" class KotlinPushDownHandler : AbstractPullPushMembersHandler( - refactoringName = PUSH_MEMBERS_DOWN, - helpId = HelpID.MEMBERS_PUSH_DOWN, - wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.push.members.from") + refactoringName = PUSH_MEMBERS_DOWN, + helpId = HelpID.MEMBERS_PUSH_DOWN, + wrongPositionMessage = RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.push.members.from") ) { 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 { @@ -56,16 +44,18 @@ class KotlinPushDownHandler : AbstractPullPushMembersHandler( private fun reportFinalClassOrObject(project: Project, editor: Editor?, classOrObject: KtClassOrObject) { 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) } - override fun invoke(project: Project, - editor: Editor?, - classOrObject: KtClassOrObject?, - member: KtNamedDeclaration?, - dataContext: DataContext?) { + override fun invoke( + project: Project, + editor: Editor?, + classOrObject: KtClassOrObject?, + member: KtNamedDeclaration?, + dataContext: DataContext? + ) { if (classOrObject == null) { reportWrongContext(project, editor) return @@ -81,8 +71,7 @@ class KotlinPushDownHandler : AbstractPullPushMembersHandler( val helper = dataContext?.getData(PUSH_DOWN_TEST_HELPER_KEY) as TestHelper val selectedMembers = helper.adjustMembers(members) KotlinPushDownProcessor(project, classOrObject, selectedMembers).run() - } - else { + } else { val manager = PsiManager.getInstance(project) members.filter { manager.areElementsEquivalent(it.member, member) }.forEach { it.isChecked = true } KotlinPushDownDialog(project, members, classOrObject).show()