Rename: Check redeclaration for local variables

Also add tests for other local declarations

 #KT-13255 Fixed
This commit is contained in:
Alexey Sedunov
2018-02-26 19:02:13 +03:00
parent 4609b2ae37
commit 6c17bbe42c
6 changed files with 43 additions and 11 deletions
@@ -18,9 +18,6 @@ open class KotlinVariableInplaceRenameHandler : VariableInplaceRenameHandler() {
fun isInplaceRenameAvailable(element: PsiElement): Boolean { fun isInplaceRenameAvailable(element: PsiElement): Boolean {
when (element) { when (element) {
is KtTypeParameter -> return true is KtTypeParameter -> return true
is KtProperty -> {
if (element.isLocal) return true
}
is KtDestructuringDeclarationEntry -> return true is KtDestructuringDeclarationEntry -> return true
is KtParameter -> { is KtParameter -> {
val parent = element.parent val parent = element.parent
@@ -105,7 +105,7 @@ internal fun checkRedeclarations(
fun MemberScope.findSiblingsByName(): List<DeclarationDescriptor> { fun MemberScope.findSiblingsByName(): List<DeclarationDescriptor> {
val descriptorKindFilter = when (descriptor) { val descriptorKindFilter = when (descriptor) {
is ClassifierDescriptor -> DescriptorKindFilter.CLASSIFIERS is ClassifierDescriptor -> DescriptorKindFilter.CLASSIFIERS
is PropertyDescriptor -> DescriptorKindFilter.VARIABLES is VariableDescriptor -> DescriptorKindFilter.VARIABLES
is FunctionDescriptor -> DescriptorKindFilter.FUNCTIONS is FunctionDescriptor -> DescriptorKindFilter.FUNCTIONS
else -> return emptyList() else -> return emptyList()
} }
@@ -150,7 +150,7 @@ internal fun checkRedeclarations(
if (it.name != newName) return@mapNotNull null if (it.name != newName) return@mapNotNull null
val isAccepted = when (descriptor) { val isAccepted = when (descriptor) {
is ClassDescriptor -> it is KtClassOrObject is ClassDescriptor -> it is KtClassOrObject
is PropertyDescriptor -> it is KtProperty is VariableDescriptor -> it is KtProperty
is FunctionDescriptor -> it is KtNamedFunction is FunctionDescriptor -> it is KtNamedFunction
else -> false else -> false
} }
@@ -0,0 +1,5 @@
// SHOULD_FAIL_WITH: Class 'LocalClassB' is already declared in function 'containNames'
fun containNames() {
class <caret>LocalClassA {}
class LocalClassB {}
}
@@ -0,0 +1,5 @@
// SHOULD_FAIL_WITH: Function 'localFunB' is already declared in function 'containNames'
fun containNames() {
fun <caret>localFunA() = 11
fun localFunB() = 12
}
@@ -0,0 +1,5 @@
// SHOULD_FAIL_WITH: Variable 'localValB' is already declared in function 'containNames'
fun containNames() {
val <caret>localValA = 11
val localValB = 12
}
@@ -11,15 +11,18 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl
import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.impl.SimpleDataContext import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.command.WriteCommandAction
import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
import com.intellij.testFramework.LightPlatformCodeInsightTestCase import com.intellij.testFramework.LightPlatformCodeInsightTestCase
import com.intellij.testFramework.fixtures.CodeInsightTestUtil import com.intellij.testFramework.fixtures.CodeInsightTestUtil
import junit.framework.TestCase
import org.jetbrains.kotlin.idea.refactoring.rename.KotlinMemberInplaceRenameHandler import org.jetbrains.kotlin.idea.refactoring.rename.KotlinMemberInplaceRenameHandler
import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler import org.jetbrains.kotlin.idea.refactoring.rename.KotlinVariableInplaceRenameHandler
import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaParameter
import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
@@ -28,7 +31,7 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
override fun getTestDataPath(): String = PluginTestCaseBase.getTestDataPathBase() + "/refactoring/rename/inplace/" override fun getTestDataPath(): String = PluginTestCaseBase.getTestDataPathBase() + "/refactoring/rename/inplace/"
fun testLocalVal() { fun testLocalVal() {
doTestInplaceRename("y") doTestMemberInplaceRename("y")
} }
fun testForLoop() { fun testForLoop() {
@@ -80,7 +83,7 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
} }
fun testLocalVarShadowingMemberProperty() { fun testLocalVarShadowingMemberProperty() {
doTestInplaceRename("name1") doTestMemberInplaceRename("name1")
} }
fun testNoReformat() { fun testNoReformat() {
@@ -144,7 +147,7 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
} }
fun testQuotedLocalVar() { fun testQuotedLocalVar() {
doTestInplaceRename("x") doTestMemberInplaceRename("x")
} }
fun testQuotedParameter() { fun testQuotedParameter() {
@@ -155,6 +158,18 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
doTestMemberInplaceRename("") doTestMemberInplaceRename("")
} }
fun testLocalVarRedeclaration() {
doTestMemberInplaceRename("localValB")
}
fun testLocalFunRedeclaration() {
doTestMemberInplaceRename("localFunB")
}
fun testLocalClassRedeclaration() {
doTestMemberInplaceRename("LocalClassB")
}
private fun doTestImplicitLambdaParameter(newName: String) { private fun doTestImplicitLambdaParameter(newName: String) {
configureByFile(getTestName(false) + ".kt") configureByFile(getTestName(false) + ".kt")
@@ -225,9 +240,14 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
assertFalse(handler.isRenaming(dataContext), "In-place rename is allowed for " + element) assertFalse(handler.isRenaming(dataContext), "In-place rename is allowed for " + element)
} }
else { else {
assertTrue(handler.isRenaming(dataContext), "In-place rename not allowed for " + element) try {
CodeInsightTestUtil.doInlineRename(handler, newName, LightPlatformCodeInsightTestCase.getEditor(), element) assertTrue(handler.isRenaming(dataContext), "In-place rename not allowed for " + element)
checkResultByFile(getTestName(false) + ".kt.after") CodeInsightTestUtil.doInlineRename(handler, newName, LightPlatformCodeInsightTestCase.getEditor(), element)
checkResultByFile(getTestName(false) + ".kt.after")
} catch (e: BaseRefactoringProcessor.ConflictsInTestsException) {
val expectedMessage = InTextDirectivesUtils.findStringWithPrefixes(myFile.text, "// SHOULD_FAIL_WITH: ")
TestCase.assertEquals(expectedMessage, e.messages.joinToString())
}
} }
} }
} }