Skip to content

Commit 1bad04d

Browse files
cypressiousasedunov
authored andcommitted
Fix Can't rename implicit lambda parameter 'it' when caret is placed right after the last character
#KT-14401 Fixed
1 parent e339117 commit 1bad04d

File tree

5 files changed

+63
-43
lines changed

5 files changed

+63
-43
lines changed

idea/src/org/jetbrains/kotlin/idea/refactoring/rename/RenameKotlinImplicitLambdaParameter.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2015 JetBrains s.r.o.
2+
* Copyright 2010-2017 JetBrains s.r.o.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,17 +21,15 @@ import com.intellij.openapi.editor.Editor
2121
import com.intellij.openapi.project.Project
2222
import com.intellij.psi.PsiElement
2323
import com.intellij.psi.PsiFile
24-
import com.intellij.psi.util.PsiTreeUtil
2524
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
2625
import org.jetbrains.kotlin.idea.intentions.ReplaceItWithExplicitFunctionLiteralParamIntention
2726
import org.jetbrains.kotlin.idea.intentions.isAutoCreatedItUsage
2827
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
2928
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
3029

31-
class RenameKotlinImplicitLambdaParameter: VariableInplaceRenameHandler() {
30+
class RenameKotlinImplicitLambdaParameter : VariableInplaceRenameHandler() {
3231
override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean {
33-
val nameExpression = PsiTreeUtil.findElementOfClassAtOffset(
34-
file, editor.caretModel.offset, KtNameReferenceExpression::class.java, false)
32+
val nameExpression = file.findElementForRename<KtNameReferenceExpression>(editor.caretModel.offset)
3533

3634
return nameExpression != null && isAutoCreatedItUsage(nameExpression)
3735
}

idea/src/org/jetbrains/kotlin/idea/refactoring/rename/renameUtil.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2015 JetBrains s.r.o.
2+
* Copyright 2010-2017 JetBrains s.r.o.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
1717
package org.jetbrains.kotlin.idea.refactoring.rename
1818

1919
import com.intellij.psi.PsiElement
20+
import com.intellij.psi.PsiFile
21+
import com.intellij.psi.util.PsiTreeUtil
2022
import com.intellij.refactoring.rename.ResolvableCollisionUsageInfo
2123
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
2224
import com.intellij.refactoring.util.MoveRenameUsageInfo
@@ -79,4 +81,9 @@ class LostDefaultValuesInOverridingFunctionUsageInfo(
7981
subParam.addRange(superParam.equalsToken, defaultValue)
8082
}
8183
}
84+
}
85+
86+
inline fun <reified T : PsiElement> PsiFile.findElementForRename(offset: Int): T? {
87+
return PsiTreeUtil.findElementOfClassAtOffset(this, offset, T::class.java, false)
88+
?: PsiTreeUtil.findElementOfClassAtOffset(this, (offset - 1).coerceAtLeast(0), T::class.java, false)
8289
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fun f() {
2+
val f: (Int) -> Int = { it<caret> + it }
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fun f() {
2+
val f: (Int) -> Int = { y -> y + y }
3+
}

idea/tests/org/jetbrains/kotlin/idea/refactoring/InplaceRenameTest.kt

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinImplicitLambdaPa
2828
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
2929
import com.intellij.codeInsight.template.TemplateManager
3030
import com.intellij.openapi.command.WriteCommandAction
31+
import org.jetbrains.kotlin.idea.refactoring.rename.findElementForRename
32+
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
3133

3234
class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
3335
override fun isRunInWriteAction(): Boolean = false
@@ -50,19 +52,58 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
5052
}
5153

5254
fun testFunctionLiteralIt() {
55+
doTestImplicitLambdaParameter("y")
56+
}
57+
58+
fun testFunctionLiteralItEndCaret() {
59+
doTestImplicitLambdaParameter("y")
60+
}
61+
62+
fun testFunctionLiteralParenthesis() {
63+
doTestInplaceRename("y")
64+
}
65+
66+
fun testLocalFunction() {
67+
doTestInplaceRename("bar")
68+
}
69+
70+
fun testFunctionParameterNotInplace() {
71+
doTestInplaceRename(null)
72+
}
73+
74+
fun testGlobalFunctionNotInplace() {
75+
doTestInplaceRename(null)
76+
}
77+
78+
fun testTopLevelValNotInplace() {
79+
doTestInplaceRename(null)
80+
}
81+
82+
fun testLabelFromFunction() {
83+
doTestInplaceRename("foo")
84+
}
85+
86+
fun testMultiDeclaration() {
87+
doTestInplaceRename("foo")
88+
}
89+
90+
fun testLocalVarShadowingMemberProperty() {
91+
doTestInplaceRename("name1")
92+
}
93+
94+
private fun doTestImplicitLambdaParameter(newName: String) {
5395
configureByFile(getTestName(false) + ".kt")
54-
val newName = "y"
5596

5697
// This code is copy-pasted from CodeInsightTestUtil.doInlineRename() and slightly modified.
5798
// Original method was not suitable because it expects renamed element to be reference to other or referrable
5899

59-
val file = LightPlatformCodeInsightTestCase.getFile()!!
60-
val editor = LightPlatformCodeInsightTestCase.getEditor()!!
61-
val element = file.findReferenceAt(editor.caretModel.offset)!!.element
100+
val file = getFile()!!
101+
val editor = getEditor()!!
102+
val element = file.findElementForRename<KtNameReferenceExpression>(editor.caretModel.offset)!!
62103
assertNotNull(element)
63104

64105
val dataContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PSI_ELEMENT.name, element!!,
65-
LightPlatformCodeInsightTestCase.getCurrentEditorDataContext())
106+
getCurrentEditorDataContext())
66107
val handler = RenameKotlinImplicitLambdaParameter()
67108

68109
assertTrue(handler.isRenaming(dataContext), "In-place rename not allowed for " + element)
@@ -100,38 +141,6 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
100141
checkResultByFile(getTestName(false) + ".kt.after")
101142
}
102143

103-
fun testFunctionLiteralParenthesis() {
104-
doTestInplaceRename("y")
105-
}
106-
107-
fun testLocalFunction() {
108-
doTestInplaceRename("bar")
109-
}
110-
111-
fun testFunctionParameterNotInplace() {
112-
doTestInplaceRename(null)
113-
}
114-
115-
fun testGlobalFunctionNotInplace() {
116-
doTestInplaceRename(null)
117-
}
118-
119-
fun testTopLevelValNotInplace() {
120-
doTestInplaceRename(null)
121-
}
122-
123-
fun testLabelFromFunction() {
124-
doTestInplaceRename("foo")
125-
}
126-
127-
fun testMultiDeclaration() {
128-
doTestInplaceRename("foo")
129-
}
130-
131-
fun testLocalVarShadowingMemberProperty() {
132-
doTestInplaceRename("name1")
133-
}
134-
135144
private fun doTestInplaceRename(newName: String?) {
136145
configureByFile(getTestName(false) + ".kt")
137146
val element = TargetElementUtilBase.findTargetElement(

0 commit comments

Comments
 (0)