[kotlin] Added AutomaticFileRenamer

#KTIJ-27509
#KTIJ-25076

GitOrigin-RevId: b5cf0ea3a926a049c7db996ccc86775ff6856166
This commit is contained in:
Vladimir Dolzhenko
2023-10-26 18:56:37 +02:00
committed by intellij-monorepo-bot
parent 762eb1749e
commit e3b2a4775e
10 changed files with 79 additions and 43 deletions

View File

@@ -1298,8 +1298,11 @@ rename.base.0=Rename base {0,choice,1#function|2#property|3#member|4#method|11#f
rename.declaration.title.0.implements.1.2.of.3={0} {1,choice,1#implements|2#overrides} {2} of {3}
rename.searching.for.all.overrides=Searching for all overrides
rename.searching.for.super.declaration=Searching for the deepest super declaration
rename.file.name=Rename File Name
title.rename.file.name=Rename File Name
file.entity=File
rename.file.name=Rename file name
rename.file.name.0=Rename File Name to ''{0}''
title.rename.file.name.to=Rename File Name To:
wrap.with.coroutine.scope.fix.text=Wrap function body with 'coroutineScope { ... }'
wrap.with.coroutine.scope.fix.text2=Wrap call with 'coroutineScope { ... }'
wrap.with.coroutine.scope.fix.text3=Remove receiver \\& wrap with 'coroutineScope { ... }'

View File

@@ -48,6 +48,9 @@ internal class K1CommonRefactoringSettings : KotlinCommonRefactoringSettingsBase
override var INTRODUCE_SPECIFY_TYPE_EXPLICITLY: Boolean
by delegateTo { it::INTRODUCE_SPECIFY_TYPE_EXPLICITLY }
override var renameFileNames: Boolean
by delegateTo { it::renameFileNames }
override var renameVariables: Boolean
by delegateTo { it::renameVariables }

View File

@@ -85,6 +85,7 @@ class KotlinRefactoringSettings : PersistentStateComponent<KotlinRefactoringSett
var renameInheritors = true
var renameParameterInHierarchy = true
var renameFileNames = true
var renameVariables = true
var renameTests = true
var renameOverloads = true

View File

@@ -36,6 +36,7 @@
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticVariableRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticVariableRenamerFactoryForJavaClass"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticVariableInJavaRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticFileRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.KotlinAutomaticTestMethodRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticParameterRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticInheritorRenamerFactory"/>

View File

@@ -27,6 +27,11 @@ interface KotlinCommonRefactoringSettings {
var INTRODUCE_DECLARE_WITH_VAR: Boolean
var INTRODUCE_SPECIFY_TYPE_EXPLICITLY: Boolean
/**
* Indicates whether automatic file rename based on changed type name is suggested
*/
var renameFileNames: Boolean
/**
* Indicates whether automatic variable rename based on changed type name is suggested
*/

View File

@@ -0,0 +1,60 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.openapi.util.NlsContexts.Button
import com.intellij.openapi.util.NlsContexts.ColumnName
import com.intellij.openapi.util.NlsContexts.DialogTitle
import com.intellij.psi.PsiElement
import com.intellij.refactoring.rename.naming.AutomaticRenamer
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.refactoring.KotlinCommonRefactoringSettings
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtVariableDeclaration
class AutomaticFileRenamer(
file: KtFile,
newFileName: String,
) : AutomaticRenamer() {
init {
myElements.add(file)
suggestAllNames(file.name, "$newFileName.${file.virtualFile.extension ?: KotlinFileType.EXTENSION}")
}
override fun allowChangeSuggestedName(): Boolean = false
override fun getDialogTitle(): @DialogTitle String? = KotlinBundle.message("title.rename.file.name")
override fun getDialogDescription(): @Button String? = KotlinBundle.message("title.rename.file.name.to")
override fun entityName(): @ColumnName String? = KotlinBundle.message("file.entity")
override fun isSelectedByDefault(): Boolean = true
}
open class AutomaticFileRenamerFactory : AutomaticRenamerFactory {
override fun isApplicable(element: PsiElement): Boolean {
if (!(element is KtNamedFunction || element is KtVariableDeclaration)) return false
val file = element.containingFile as? KtFile ?: return false
val declaration = file.declarations.singleOrNull() as? KtNamedDeclaration ?: return false
return declaration.name == file.virtualFile.nameWithoutExtension && element == declaration
}
override fun createRenamer(element: PsiElement, newName: String, usages: Collection<UsageInfo>): AutomaticFileRenamer {
return AutomaticFileRenamer(element.containingFile as KtFile, newName)
}
override fun isEnabled() = KotlinCommonRefactoringSettings.getInstance().renameFileNames
override fun setEnabled(enabled: Boolean) {
KotlinCommonRefactoringSettings.getInstance().renameFileNames = enabled
}
override fun getOptionName(): String? = KotlinBundle.message("rename.file.name")
}

View File

@@ -5,9 +5,7 @@ package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.Pass
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.refactoring.listeners.RefactoringElementListener
@@ -16,7 +14,6 @@ import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.refactoring.util.RefactoringUtil
import com.intellij.usageView.UsageInfo
import com.intellij.util.SmartList
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
@@ -29,7 +26,6 @@ import org.jetbrains.kotlin.idea.refactoring.conflicts.checkRedeclarationConflic
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport
import org.jetbrains.kotlin.idea.search.declarationsSearch.findDeepestSuperMethodsKotlinAware
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
import org.jetbrains.kotlin.psi.*
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
@@ -235,8 +231,6 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
}
}
renameRefactoringSupport.prepareForeignUsagesRenaming(element, newName, allRenames, scope)
element.renameFileIfSingleDeclaration(originalName, newName, allRenames)
}
override fun renameElement(element: PsiElement, newName: String, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
@@ -289,35 +283,4 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
return processFoundReferences(element, references)
}
}
@ApiStatus.Internal
internal fun PsiElement.renameFileIfSingleDeclaration(
originalName: String,
newName: String,
allRenames: MutableMap<PsiElement, String>
) {
val file = containingFile as? KtFile ?: return
if (file.declarations.singleOrNull() == this) {
file.virtualFile?.let { virtualFile ->
val nameWithoutExtensions = virtualFile.nameWithoutExtension
if (nameWithoutExtensions == originalName) {
if (!isUnitTestMode() && newName.isNotEmpty() && Messages.showYesNoDialog(
project,
KotlinBundle.message("rename.file.name.0", newName),
KotlinBundle.message("rename.file.name"),
Messages.getYesButton(),
Messages.getCancelButton(),
Messages.getQuestionIcon()
) == Messages.NO
) {
return
}
val newFileName = newName + "." + virtualFile.extension
allRenames[file] = newFileName
RenamePsiElementProcessor.forElement(file).prepareRenaming(file, newFileName, allRenames)
}
}
}
}
}

View File

@@ -250,10 +250,6 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
}
renameRefactoringSupport.prepareForeignUsagesRenaming(element, newName, allRenames, scope)
originalName?.let {
element.renameFileIfSingleDeclaration(it, newName, allRenames)
}
}
protected enum class UsageKind {

View File

@@ -50,6 +50,9 @@ internal class K2CommonRefactoringSettings : KotlinCommonRefactoringSettingsBase
override var INTRODUCE_SPECIFY_TYPE_EXPLICITLY: Boolean
by delegateTo { it::INTRODUCE_SPECIFY_TYPE_EXPLICITLY }
override var renameFileNames: Boolean
by delegateTo { it::renameFileNames }
override var renameVariables: Boolean
by delegateTo { it::renameVariables }

View File

@@ -17,6 +17,7 @@ class KotlinFirRefactoringsSettings : PersistentStateComponent<KotlinFirRefactor
var RENAME_SEARCH_IN_COMMENTS_FOR_CLASS: Boolean = false
var RENAME_SEARCH_IN_COMMENTS_FOR_PARAMETER: Boolean = false
var renameFileNames: Boolean = true
var renameVariables: Boolean = true
var renameParameterInHierarchy: Boolean = true
var renameInheritors: Boolean = true