Rename: Conflict detection for type parameters
#KT-13254 Fixed
This commit is contained in:
@@ -261,6 +261,7 @@ Using 'this' as function argument in constructor of non-final class
|
||||
- [`KT-13128`](https://youtrack.jetbrains.com/issue/KT-13128) Introduce Variable: Retain entered name after changing "Specify type explicitly" option
|
||||
- [`KT-13054`](https://youtrack.jetbrains.com/issue/KT-13054) Introduce Variable: Skip leading/trailing comments inside selection
|
||||
- [`KT-13277`](https://youtrack.jetbrains.com/issue/KT-13277) Change Signature: Fix usage processing to prevent interfering with Python support plugin
|
||||
- [`KT-13254`](https://youtrack.jetbrains.com/issue/KT-13254) Rename: Conflict detection for type parameters
|
||||
|
||||
##### New features
|
||||
|
||||
|
||||
@@ -440,6 +440,8 @@
|
||||
<renamePsiElementProcessor implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinFileProcessor"
|
||||
id="KotlinFile"
|
||||
order="first"/>
|
||||
<renamePsiElementProcessor implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinTypeParameterProcessor"
|
||||
id="KotlinTypeParameter"/>
|
||||
<renamePsiElementProcessor implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameJavaSyntheticPropertyHandler$Processor"
|
||||
id="JavaSyntheticPropertyFromKotlin"/>
|
||||
<renameHandler implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter"/>
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.rename
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtTypeParameter
|
||||
|
||||
class RenameKotlinTypeParameterProcessor : RenameKotlinPsiProcessor() {
|
||||
override fun canProcessElement(element: PsiElement) = element is KtTypeParameter
|
||||
|
||||
override fun findCollisions(
|
||||
element: PsiElement,
|
||||
newName: String?,
|
||||
allRenames: MutableMap<out PsiElement, String>,
|
||||
result: MutableList<UsageInfo>
|
||||
) {
|
||||
if (newName == null) return
|
||||
val declaration = element as? KtTypeParameter ?: return
|
||||
val descriptor = declaration.resolveToDescriptor()
|
||||
checkRedeclarations(descriptor, newName, result)
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||
import org.jetbrains.kotlin.idea.core.copied
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.refactoring.explicateAsText
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.refactoring.getThisLabelName
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.search.and
|
||||
@@ -83,11 +82,28 @@ internal fun checkRedeclarations(
|
||||
result: MutableList<UsageInfo>
|
||||
) {
|
||||
fun getSiblingWithNewName(): DeclarationDescriptor? {
|
||||
val containingDescriptor = descriptor.containingDeclaration
|
||||
|
||||
if (descriptor is ValueParameterDescriptor) {
|
||||
return descriptor.containingDeclaration.valueParameters.firstOrNull { it.name.asString() == newName }
|
||||
return (containingDescriptor as CallableDescriptor).valueParameters.firstOrNull { it.name.asString() == newName }
|
||||
}
|
||||
|
||||
if (descriptor is TypeParameterDescriptor) {
|
||||
val typeParameters = when (containingDescriptor) {
|
||||
is ClassDescriptor -> containingDescriptor.declaredTypeParameters
|
||||
is CallableDescriptor -> containingDescriptor.typeParameters
|
||||
else -> emptyList()
|
||||
}
|
||||
typeParameters.firstOrNull { it.name.asString() == newName }?.let { return it }
|
||||
|
||||
val containingDeclaration = (containingDescriptor as? DeclarationDescriptorWithSource)?.source?.getPsi() as? KtDeclaration
|
||||
?: return null
|
||||
val dummyVar = KtPsiFactory(containingDeclaration).createProperty("val foo: $newName")
|
||||
val outerScope = containingDeclaration.getResolutionScope()
|
||||
val context = dummyVar.analyzeInContext(outerScope, containingDeclaration)
|
||||
return context[BindingContext.VARIABLE, dummyVar]?.type?.constructor?.declarationDescriptor
|
||||
}
|
||||
|
||||
val containingDescriptor = descriptor.containingDeclaration
|
||||
val containingScope = when (containingDescriptor) {
|
||||
is ClassDescriptor -> containingDescriptor.unsubstitutedMemberScope
|
||||
is PackageFragmentDescriptor -> containingDescriptor.getMemberScope()
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
class A</*rename*/U, V>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test.kt",
|
||||
"newName": "V",
|
||||
"hint": "Type parameter 'V' is already declared in class 'A'"
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
class A<T> {
|
||||
inner class B</*rename*/U, V>
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test.kt",
|
||||
"newName": "T",
|
||||
"hint": "Type parameter 'T' is already declared in class 'A'"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun </*rename*/U, V> foo() {
|
||||
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test.kt",
|
||||
"newName": "V",
|
||||
"hint": "Type parameter 'V' is already declared in function 'foo'"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class A<T> {
|
||||
fun </*rename*/U, V> foo() {
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test.kt",
|
||||
"newName": "T",
|
||||
"hint": "Type parameter 'T' is already declared in class 'A'"
|
||||
}
|
||||
@@ -281,6 +281,18 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameClassTypeParameterRedeclaration/renameClassTypeParameterRedeclaration.test")
|
||||
public void testRenameClassTypeParameterRedeclaration_RenameClassTypeParameterRedeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/renameClassTypeParameterRedeclaration.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameClassTypeParameterRedeclarationWithOuterScope/renameClassTypeParameterRedeclarationWithOuterScope.test")
|
||||
public void testRenameClassTypeParameterRedeclarationWithOuterScope_RenameClassTypeParameterRedeclarationWithOuterScope() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/renameClassTypeParameterRedeclarationWithOuterScope.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameClassWithAutoVarConventions/renameClassWithAutoVarConventions.test")
|
||||
public void testRenameClassWithAutoVarConventions_RenameClassWithAutoVarConventions() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameClassWithAutoVarConventions/renameClassWithAutoVarConventions.test");
|
||||
@@ -353,6 +365,18 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameFunctionTypeParameterRedeclaration/renameFunctionTypeParameterRedeclaration.test")
|
||||
public void testRenameFunctionTypeParameterRedeclaration_RenameFunctionTypeParameterRedeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/renameFunctionTypeParameterRedeclaration.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameFunctionTypeParameterRedeclarationWithOuterScope/renameFunctionTypeParameterRedeclarationWithOuterScope.test")
|
||||
public void testRenameFunctionTypeParameterRedeclarationWithOuterScope_RenameFunctionTypeParameterRedeclarationWithOuterScope() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/renameFunctionTypeParameterRedeclarationWithOuterScope.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameGet/get.test")
|
||||
public void testRenameGet_Get() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameGet/get.test");
|
||||
|
||||
Reference in New Issue
Block a user