Rename: Conflict detection for type parameters

#KT-13254 Fixed
This commit is contained in:
Alexey Sedunov
2016-08-08 16:48:38 +03:00
parent 562488b348
commit a5da9e81a0
13 changed files with 120 additions and 3 deletions
+1
View File
@@ -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
+2
View File
@@ -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"/>
@@ -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()
@@ -0,0 +1 @@
class A</*rename*/U, V>
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "V",
"hint": "Type parameter 'V' is already declared in class 'A'"
}
@@ -0,0 +1,3 @@
class A<T> {
inner class B</*rename*/U, V>
}
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "T",
"hint": "Type parameter 'T' is already declared in class 'A'"
}
@@ -0,0 +1,3 @@
fun </*rename*/U, V> foo() {
}
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "V",
"hint": "Type parameter 'V' is already declared in function 'foo'"
}
@@ -0,0 +1,5 @@
class A<T> {
fun </*rename*/U, V> foo() {
}
}
@@ -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");