Rename: Do not silently rename all parameters in function hierarchy

#KT-18325 Fixed
This commit is contained in:
Alexey Sedunov
2017-06-13 18:09:15 +03:00
parent 31d21a14f2
commit 895407f5e3
21 changed files with 311 additions and 33 deletions
+1
View File
@@ -519,6 +519,7 @@
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticInheritorRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticOverloadsRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.KotlinAutomaticTestRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticParameterRenamerFactory"/>
<vetoRenameCondition implementation="org.jetbrains.kotlin.idea.refactoring.KotlinVetoRenameCondition"/>
<renameInputValidator implementation="org.jetbrains.kotlin.idea.refactoring.rename.KotlinDeclarationRenameInputValidator"/>
<rename.inplace.resolveSnapshotProvider
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.rename.naming.AutomaticRenamer
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
class AutomaticParameterRenamer(element: KtParameter, newName: String) : AutomaticRenamer() {
init {
processHierarchy(element, newName)
}
private fun processHierarchy(element: KtParameter, newName: String) {
val function = element.ownerFunction ?: return
for (overrider in HierarchySearchRequest(function, function.useScope).searchOverriders()) {
val callable = overrider.namedUnwrappedElement ?: continue
if (!callable.canRefactor()) continue
val parameter: PsiNamedElement? =
when (callable) {
is KtCallableDeclaration -> callable.valueParameters.firstOrNull { it.name == element.name }
is PsiMethod -> callable.parameterList.parameters.firstOrNull { it.name == element.name }
else -> null
}
if (parameter == null) continue
myElements += parameter
}
suggestAllNames(element.name, newName.quoteIfNeeded())
}
override fun getDialogTitle() = "Rename Parameters"
override fun getDialogDescription() = "Rename parameter in hierarchy to:"
override fun entityName() = "Parameter"
override fun isSelectedByDefault() = true
}
class AutomaticParameterRenamerFactory : AutomaticRenamerFactory {
override fun isApplicable(element: PsiElement) = element is KtParameter && element.ownerFunction is KtNamedFunction
override fun getOptionName() = RefactoringBundle.message("rename.parameters.hierarchy")!!
override fun isEnabled() = JavaRefactoringSettings.getInstance().isRenameParameterInHierarchy
override fun setEnabled(enabled: Boolean) {
JavaRefactoringSettings.getInstance().isRenameParameterInHierarchy = enabled
}
override fun createRenamer(element: PsiElement, newName: String, usages: Collection<UsageInfo>): AutomaticRenamer {
return AutomaticParameterRenamer(element as KtParameter, newName)
}
}
@@ -17,21 +17,12 @@
package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.search.SearchScope
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.refactoring.getAffectedCallables
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtParameter
@@ -63,26 +54,6 @@ class RenameKotlinParameterProcessor : RenameKotlinPsiProcessor() {
result += collisions
}
override fun prepareRenaming(element: PsiElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
super.prepareRenaming(element, newName, allRenames, scope)
if (element !is KtParameter || newName == null) return
val function = element.ownerFunction ?: return
val originalDescriptor = function.resolveToDescriptor() as FunctionDescriptor
val affectedCallables = getAffectedCallables(element.project, originalDescriptor.getDeepestSuperDeclarations())
for (callable in affectedCallables) {
if (!callable.canRefactor()) continue
val parameter: PsiNamedElement? = when (callable) {
is KtCallableDeclaration -> callable.valueParameters.firstOrNull { it.name == element.name }
is PsiMethod -> callable.parameterList.parameters.firstOrNull { it.name == element.name }
else -> null
}
if (parameter == null) continue
allRenames[parameter] = newName.quoteIfNeeded()
}
}
override fun renameElement(element: PsiElement, newName: String?, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
super.renameElement(element, newName, usages, listener)
@@ -1,12 +1,12 @@
package testing
interface Trait {
open fun foo(aa: Int, b: String) {
open fun foo(a: Int, b: String) {
}
}
open class Super {
open fun foo(aa: Int, b: String) {
open fun foo(a: Int, b: String) {
}
}
@@ -1,12 +1,12 @@
package testing
interface Trait {
open fun Int.foo(aa: Int, b: String) {
open fun Int.foo(a: Int, b: String) {
}
}
open class Super {
open fun Int.foo(aa: Int, b: String) {
open fun Int.foo(a: Int, b: String) {
}
}
@@ -0,0 +1,17 @@
class J1 implements Foo {
public void foo(String s) {
}
}
class J2 extends J1 {
public void foo(String s) {
}
}
class J3 extends Foo1 {
public void foo(String s) {
}
}
@@ -0,0 +1,15 @@
interface Foo {
fun foo(s: String)
}
open class Foo1 : Foo {
override fun foo(s: String) { }
}
class Foo2 : Foo {
override fun foo(x: String) { }
}
class Foo3 : Foo1() {
override fun foo(s: String) { }
}
@@ -0,0 +1,17 @@
class J1 implements Foo {
public void foo(String s) {
}
}
class J2 extends J1 {
public void foo(String s) {
}
}
class J3 extends Foo1 {
public void foo(String s) {
}
}
@@ -0,0 +1,15 @@
interface Foo {
fun foo(s: String)
}
open class Foo1 : Foo {
override fun foo(s: String) { }
}
class Foo2 : Foo {
override fun foo(/*rename*/s: String) { }
}
class Foo3 : Foo1() {
override fun foo(s: String) { }
}
@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "x"
}
@@ -0,0 +1,17 @@
class J1 implements Foo {
public void foo(String s) {
}
}
class J2 extends J1 {
public void foo(String s) {
}
}
class J3 extends Foo1 {
public void foo(String x) {
}
}
@@ -0,0 +1,15 @@
interface Foo {
fun foo(s: String)
}
open class Foo1 : Foo {
override fun foo(x: String) { }
}
class Foo2 : Foo {
override fun foo(s: String) { }
}
class Foo3 : Foo1() {
override fun foo(x: String) { }
}
@@ -0,0 +1,17 @@
class J1 implements Foo {
public void foo(String s) {
}
}
class J2 extends J1 {
public void foo(String s) {
}
}
class J3 extends Foo1 {
public void foo(String s) {
}
}
@@ -0,0 +1,15 @@
interface Foo {
fun foo(s: String)
}
open class Foo1 : Foo {
override fun foo(/*rename*/s: String) { }
}
class Foo2 : Foo {
override fun foo(s: String) { }
}
class Foo3 : Foo1() {
override fun foo(s: String) { }
}
@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "x"
}
@@ -0,0 +1,17 @@
class J1 implements Foo {
public void foo(String x) {
}
}
class J2 extends J1 {
public void foo(String x) {
}
}
class J3 extends Foo1 {
public void foo(String x) {
}
}
@@ -0,0 +1,15 @@
interface Foo {
fun foo(x: String)
}
open class Foo1 : Foo {
override fun foo(x: String) { }
}
class Foo2 : Foo {
override fun foo(x: String) { }
}
class Foo3 : Foo1() {
override fun foo(x: String) { }
}
@@ -0,0 +1,17 @@
class J1 implements Foo {
public void foo(String s) {
}
}
class J2 extends J1 {
public void foo(String s) {
}
}
class J3 extends Foo1 {
public void foo(String s) {
}
}
@@ -0,0 +1,15 @@
interface Foo {
fun foo(/*rename*/s: String)
}
open class Foo1 : Foo {
override fun foo(s: String) { }
}
class Foo2 : Foo {
override fun foo(s: String) { }
}
class Foo3 : Foo1() {
override fun foo(s: String) { }
}
@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "x"
}
@@ -414,6 +414,24 @@ public class RenameTestGenerated extends AbstractRenameTest {
doTest(fileName);
}
@TestMetadata("parameterHierarchyLeaf/parameterHierarchyLeaf.test")
public void testParameterHierarchyLeaf_ParameterHierarchyLeaf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/parameterHierarchyLeaf/parameterHierarchyLeaf.test");
doTest(fileName);
}
@TestMetadata("parameterHierarchyMiddle/parameterHierarchyMiddle.test")
public void testParameterHierarchyMiddle_ParameterHierarchyMiddle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/parameterHierarchyMiddle/parameterHierarchyMiddle.test");
doTest(fileName);
}
@TestMetadata("parameterHierarchyRoot/parameterHierarchyRoot.test")
public void testParameterHierarchyRoot_ParameterHierarchyRoot() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/parameterHierarchyRoot/parameterHierarchyRoot.test");
doTest(fileName);
}
@TestMetadata("parameterRedeclaration/parameterRedeclaration.test")
public void testParameterRedeclaration_ParameterRedeclaration() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/parameterRedeclaration/parameterRedeclaration.test");