From dd7bd2b869ff2f1e4022b96943f9d22c662053ea Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 24 Jun 2016 16:24:58 +0300 Subject: [PATCH] Inline Property: Support "Do not show this dialog" and "Inline this occurrence" options #KT-12017 Fixed (cherry picked from commit b53d8da) --- ChangeLog.md | 4 ++ .../inline/KotlinInlineValDialog.kt | 64 +++++++++++++++++++ .../inline/KotlinInlineValHandler.kt | 42 +++++++++--- 3 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValDialog.kt diff --git a/ChangeLog.md b/ChangeLog.md index a6c2ec99431..cf718dd4ed4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -121,6 +121,10 @@ These artifacts include extensions for the types available in the latter JDKs, s - [`KT-12413`](https://youtrack.jetbrains.com/issue/KT-12413) Change Signature: Fix bogus warning about unresolved type parameters/invalid functional type replacement - [`KT-12084`](https://youtrack.jetbrains.com/issue/KT-12084) Introduce Property: Do not skip outer classes if extractable expression is contained in object literal +###### New features + +- [`KT-12017`](https://youtrack.jetbrains.com/issue/KT-12017) Inline Property: Support "Do not show this dialog" and "Inline this occurrence" options + ## 1.0.3 ### Compiler diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValDialog.kt new file mode 100644 index 00000000000..cb895c93e11 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValDialog.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring.inline + +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiReference +import com.intellij.refactoring.JavaRefactoringSettings +import com.intellij.refactoring.inline.AbstractInlineLocalDialog +import org.jetbrains.kotlin.psi.KtProperty + +class KotlinInlineValDialog( + element: KtProperty, + ref: PsiReference?, + private val occurrenceCount: Int +) : AbstractInlineLocalDialog(element.project, element, ref, occurrenceCount) { + private val property: KtProperty get() = myElement as KtProperty + + private val kind = if (property.isLocal) "local variable" else "property" + + private val refactoringName = "Inline ${StringUtil.capitalizeWords(kind, true)}" + + init { + myInvokedOnReference = ref != null + title = refactoringName + init() + } + + override fun getBorderTitle() = refactoringName + + override fun getNameLabelText() = "${kind.capitalize()} ${property.name}" + + override fun getInlineAllText(): String? { + val occurrencesString = if (occurrenceCount >= 0) { + " (" + occurrenceCount + " occurrence" + (if (occurrenceCount == 1) ")" else "s)") + } else "" + return "Inline all references and remove the $kind" + occurrencesString + } + + override fun isInlineThis() = JavaRefactoringSettings.getInstance().INLINE_LOCAL_THIS + + override fun getInlineThisText() = "Inline this occurrence and leave the $kind" + + override fun doAction() { + val settings = JavaRefactoringSettings.getInstance() + if (myRbInlineThisOnly.isEnabled && myRbInlineAll.isEnabled) { + settings.INLINE_LOCAL_THIS = isInlineThisOnly + } + close(OK_EXIT_CODE) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt index 5abf2bff458..bb97bffa891 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt @@ -19,13 +19,17 @@ package org.jetbrains.kotlin.idea.refactoring.inline import com.google.common.collect.Sets import com.intellij.lang.Language import com.intellij.lang.refactoring.InlineActionHandler +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.ex.EditorSettingsExternalizable import com.intellij.openapi.project.Project import com.intellij.openapi.wm.WindowManager import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.refactoring.HelpID +import com.intellij.refactoring.JavaRefactoringSettings import com.intellij.refactoring.RefactoringBundle import com.intellij.refactoring.util.CommonRefactoringUtil import com.intellij.util.containers.MultiMap @@ -55,6 +59,10 @@ import org.jetbrains.kotlin.utils.sure import java.util.* class KotlinInlineValHandler : InlineActionHandler() { + enum class InlineMode { + ALL, PRIMARY, NONE + } + override fun isEnabledForLanguage(l: Language) = l == KotlinLanguage.INSTANCE override fun canInlineElement(element: PsiElement): Boolean { @@ -152,12 +160,15 @@ class KotlinInlineValHandler : InlineActionHandler() { } fun performRefactoring() { - if (!showDialog(project, - name, - RefactoringBundle.message("inline.variable.title"), - declaration, - referenceExpressions, - HelpID.INLINE_VARIABLE)) { + val primaryExpression = if (editor != null) { + val offset = editor.caretModel.offset + referenceExpressions.firstOrNull { it.textRange.contains(offset) } + } + else null + val primaryRef = primaryExpression?.mainReference + + val inlineMode = showDialog(declaration, primaryRef, referenceExpressions.size) + if (inlineMode == InlineMode.NONE) { if (isHighlighting) { val statusBar = WindowManager.getInstance().getStatusBar(project) statusBar?.info = RefactoringBundle.message("press.escape.to.remove.the.highlighting") @@ -165,8 +176,10 @@ class KotlinInlineValHandler : InlineActionHandler() { return } + val chosenExpressions = if (inlineMode == InlineMode.ALL) referenceExpressions else listOf(primaryExpression) + project.executeWriteCommand(RefactoringBundle.message("inline.command", name)) { - val inlinedExpressions = referenceExpressions + val inlinedExpressions = chosenExpressions .flatMap { referenceExpression -> if (assignments.contains(referenceExpression.parent)) return@flatMap emptyList() @@ -184,8 +197,10 @@ class KotlinInlineValHandler : InlineActionHandler() { } .mapNotNull { postProcessInternalReferences(it) } - assignments.forEach { it.delete() } - declaration.delete() + if (inlineMode == InlineMode.ALL) { + assignments.forEach { it.delete() } + declaration.delete() + } if (inlinedExpressions.isNotEmpty()) { if (typeArgumentsForCall != null) { @@ -224,6 +239,15 @@ class KotlinInlineValHandler : InlineActionHandler() { CommonRefactoringUtil.showErrorHint(project, editor, message, RefactoringBundle.message("inline.variable.title"), HelpID.INLINE_VARIABLE) } + private fun showDialog(property: KtProperty, ref: PsiReference?, occurrenceCount: Int): InlineMode { + if (ApplicationManager.getApplication().isUnitTestMode) return InlineMode.ALL + if ((ref == null || occurrenceCount <= 1) && !EditorSettingsExternalizable.getInstance().isShowInlineLocalDialog) return InlineMode.ALL + + val dialog = KotlinInlineValDialog(property, ref, occurrenceCount) + if (!dialog.showAndGet()) return InlineMode.NONE + return if (JavaRefactoringSettings.getInstance().INLINE_LOCAL_THIS) InlineMode.PRIMARY else InlineMode.ALL + } + private fun getParametersForFunctionLiteral(initializer: KtExpression): String? { val functionLiteralExpression = initializer.unpackFunctionLiteral(true) ?: return null val context = initializer.analyze(BodyResolveMode.PARTIAL)