Rename: Warn about function name conflicts
#KT-13239 Fixed
This commit is contained in:
@@ -263,6 +263,7 @@ Using 'this' as function argument in constructor of non-final class
|
||||
- [`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
|
||||
- [`KT-13282`](https://youtrack.jetbrains.com/issue/KT-13282), [`KT-13283`](https://youtrack.jetbrains.com/issue/KT-13283) Rename: Fix name quoting for automatic renamers
|
||||
- [`KT-13239`](https://youtrack.jetbrains.com/issue/KT-13239) Rename: Warn about function name conflicts
|
||||
|
||||
##### New features
|
||||
|
||||
|
||||
@@ -80,7 +80,11 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
allRenames: Map<out PsiElement, String>,
|
||||
result: MutableList<UsageInfo>
|
||||
) {
|
||||
if (newName == null) return
|
||||
val declaration = element.unwrapped as? KtNamedFunction ?: return
|
||||
val descriptor = declaration.resolveToDescriptor()
|
||||
checkConflictsAndReplaceUsageInfos(element, allRenames, result)
|
||||
checkRedeclarations(descriptor, newName, result)
|
||||
}
|
||||
|
||||
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
|
||||
|
||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
|
||||
@@ -81,6 +82,16 @@ internal fun checkRedeclarations(
|
||||
newName: String,
|
||||
result: MutableList<UsageInfo>
|
||||
) {
|
||||
fun MemberScope.findSiblingByName(): DeclarationDescriptor? {
|
||||
val descriptorKindFilter = when (descriptor) {
|
||||
is ClassDescriptor -> DescriptorKindFilter.CLASSIFIERS
|
||||
is PropertyDescriptor -> DescriptorKindFilter.VARIABLES
|
||||
is FunctionDescriptor -> DescriptorKindFilter.FUNCTIONS
|
||||
else -> return null
|
||||
}
|
||||
return getDescriptorsFiltered(descriptorKindFilter) { it.asString() == newName }.firstOrNull { it != descriptor }
|
||||
}
|
||||
|
||||
fun getSiblingWithNewName(): DeclarationDescriptor? {
|
||||
val containingDescriptor = descriptor.containingDeclaration
|
||||
|
||||
@@ -104,17 +115,23 @@ internal fun checkRedeclarations(
|
||||
return context[BindingContext.VARIABLE, dummyVar]?.type?.constructor?.declarationDescriptor
|
||||
}
|
||||
|
||||
val containingScope = when (containingDescriptor) {
|
||||
is ClassDescriptor -> containingDescriptor.unsubstitutedMemberScope
|
||||
is PackageFragmentDescriptor -> containingDescriptor.getMemberScope()
|
||||
else -> return null
|
||||
return when (containingDescriptor) {
|
||||
is ClassDescriptor -> containingDescriptor.unsubstitutedMemberScope.findSiblingByName()
|
||||
is PackageFragmentDescriptor -> containingDescriptor.getMemberScope().findSiblingByName()
|
||||
else -> {
|
||||
val block = (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()?.parent as? KtBlockExpression
|
||||
?: return null
|
||||
(block.statements.firstOrNull {
|
||||
if (it.name != newName) return@firstOrNull false
|
||||
when (descriptor) {
|
||||
is ClassDescriptor -> it is KtClassOrObject
|
||||
is PropertyDescriptor -> it is KtProperty
|
||||
is FunctionDescriptor -> it is KtNamedFunction
|
||||
else -> false
|
||||
}
|
||||
} as? KtDeclaration)?.resolveToDescriptor()
|
||||
}
|
||||
}
|
||||
val descriptorKindFilter = when (descriptor) {
|
||||
is ClassDescriptor -> DescriptorKindFilter.CLASSIFIERS
|
||||
is PropertyDescriptor -> DescriptorKindFilter.VARIABLES
|
||||
else -> return null
|
||||
}
|
||||
return containingScope.getDescriptorsFiltered(descriptorKindFilter) { it.asString() == newName }.firstOrNull()
|
||||
}
|
||||
|
||||
val candidateDescriptor = getSiblingWithNewName() ?: return
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package test
|
||||
|
||||
class A {
|
||||
fun /*rename*/namedFunA() {}
|
||||
fun namedFunB() {}
|
||||
|
||||
fun useNames() {
|
||||
namedFunA()
|
||||
namedFunB()
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test/test.kt",
|
||||
"newName": "namedFunB",
|
||||
"withRuntime": "true",
|
||||
"hint": "Function 'namedFunB' is already declared in class 'A'"
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
fun /*rename*/namedFunA() {}
|
||||
fun namedFunB() {}
|
||||
|
||||
fun useNames() {
|
||||
namedFunA()
|
||||
namedFunB()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test/test.kt",
|
||||
"newName": "namedFunB",
|
||||
"withRuntime": "true",
|
||||
"hint": "Function 'namedFunB' is already declared in package 'test'"
|
||||
}
|
||||
@@ -185,6 +185,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberFunctionRedeclaration/memberFunctionRedeclaration.test")
|
||||
public void testMemberFunctionRedeclaration_MemberFunctionRedeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/memberFunctionRedeclaration/memberFunctionRedeclaration.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberPropertyRedeclaration/memberPropertyRedeclaration.test")
|
||||
public void testMemberPropertyRedeclaration_MemberPropertyRedeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/memberPropertyRedeclaration/memberPropertyRedeclaration.test");
|
||||
@@ -1007,6 +1013,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFunctionRedeclaration/topLevelFunctionRedeclaration.test")
|
||||
public void testTopLevelFunctionRedeclaration_TopLevelFunctionRedeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/topLevelFunctionRedeclaration/topLevelFunctionRedeclaration.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelPropertyRedeclaration/topLevelPropertyRedeclaration.test")
|
||||
public void testTopLevelPropertyRedeclaration_TopLevelPropertyRedeclaration() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/topLevelPropertyRedeclaration/topLevelPropertyRedeclaration.test");
|
||||
|
||||
Reference in New Issue
Block a user