diff --git a/ChangeLog.md b/ChangeLog.md
index f4bf25d4199..fe49fd98202 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -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
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index a2ea5319343..f2e95d85d40 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -440,6 +440,8 @@
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinTypeParameterProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinTypeParameterProcessor.kt
new file mode 100644
index 00000000000..b6dc2adb45a
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinTypeParameterProcessor.kt
@@ -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,
+ result: MutableList
+ ) {
+ if (newName == null) return
+ val declaration = element as? KtTypeParameter ?: return
+ val descriptor = declaration.resolveToDescriptor()
+ checkRedeclarations(descriptor, newName, result)
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/renameConflictUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/renameConflictUtils.kt
index 0dfae8c7c18..86c632985fb 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/renameConflictUtils.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/renameConflictUtils.kt
@@ -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
) {
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()
diff --git a/idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/before/test.kt b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/before/test.kt
new file mode 100644
index 00000000000..22ab0732dfb
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/before/test.kt
@@ -0,0 +1 @@
+class A*rename*/U, V>
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/renameClassTypeParameterRedeclaration.test b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/renameClassTypeParameterRedeclaration.test
new file mode 100644
index 00000000000..ba2ae803f6b
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclaration/renameClassTypeParameterRedeclaration.test
@@ -0,0 +1,6 @@
+{
+ "type": "MARKED_ELEMENT",
+ "mainFile": "test.kt",
+ "newName": "V",
+ "hint": "Type parameter 'V' is already declared in class 'A'"
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/before/test.kt b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/before/test.kt
new file mode 100644
index 00000000000..7e7a8028448
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/before/test.kt
@@ -0,0 +1,3 @@
+class A {
+ inner class B*rename*/U, V>
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/renameClassTypeParameterRedeclarationWithOuterScope.test b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/renameClassTypeParameterRedeclarationWithOuterScope.test
new file mode 100644
index 00000000000..88ba60d9af9
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameClassTypeParameterRedeclarationWithOuterScope/renameClassTypeParameterRedeclarationWithOuterScope.test
@@ -0,0 +1,6 @@
+{
+ "type": "MARKED_ELEMENT",
+ "mainFile": "test.kt",
+ "newName": "T",
+ "hint": "Type parameter 'T' is already declared in class 'A'"
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/before/test.kt b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/before/test.kt
new file mode 100644
index 00000000000..9c6b297b8b4
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/before/test.kt
@@ -0,0 +1,3 @@
+fun *rename*/U, V> foo() {
+
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/renameFunctionTypeParameterRedeclaration.test b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/renameFunctionTypeParameterRedeclaration.test
new file mode 100644
index 00000000000..729a01fa960
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclaration/renameFunctionTypeParameterRedeclaration.test
@@ -0,0 +1,6 @@
+{
+ "type": "MARKED_ELEMENT",
+ "mainFile": "test.kt",
+ "newName": "V",
+ "hint": "Type parameter 'V' is already declared in function 'foo'"
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/before/test.kt b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/before/test.kt
new file mode 100644
index 00000000000..144673b3d77
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/before/test.kt
@@ -0,0 +1,5 @@
+class A {
+ fun *rename*/U, V> foo() {
+
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/renameFunctionTypeParameterRedeclarationWithOuterScope.test b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/renameFunctionTypeParameterRedeclarationWithOuterScope.test
new file mode 100644
index 00000000000..88ba60d9af9
--- /dev/null
+++ b/idea/testData/refactoring/rename/renameFunctionTypeParameterRedeclarationWithOuterScope/renameFunctionTypeParameterRedeclarationWithOuterScope.test
@@ -0,0 +1,6 @@
+{
+ "type": "MARKED_ELEMENT",
+ "mainFile": "test.kt",
+ "newName": "T",
+ "hint": "Type parameter 'T' is already declared in class 'A'"
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java
index 3255341a48e..a201de344ac 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java
@@ -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");