SmartPointers in Introduce Variable refactoring

It's often case, when psi can die after reparse, especially after
reformatting cases, SmartPointers are opposite to it, can survive

#KT-32601 Fixed
This commit is contained in:
Alexander Podkhalyuzin
2019-07-14 13:44:44 +03:00
parent aa604d0854
commit ddd25c703a
4 changed files with 30 additions and 15 deletions
@@ -26,10 +26,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.HelpID
import com.intellij.refactoring.RefactoringActionHandler
@@ -115,8 +112,8 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
private val psiFactory = KtPsiFactory(expression)
var propertyRef: KtDeclaration? = null
var reference: KtExpression? = null
val references = ArrayList<KtExpression>()
var reference: SmartPsiElementPointer<KtExpression>? = null
val references = ArrayList<SmartPsiElementPointer<KtExpression>>()
private fun findElementByOffsetAndText(offset: Int, text: String, newContainer: PsiElement): PsiElement? {
return newContainer.findElementAt(offset)?.parentsWithSelf?.firstOrNull { (it as? KtExpression)?.text == text }
@@ -139,9 +136,13 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
result = result.removeTemplateEntryBracesIfPossible()
if (addToReferences) references.addIfNotNull(result)
if (addToReferences) {
references.addIfNotNull(SmartPointerManager.createPointer(result))
}
if (isActualExpression) reference = result
if (isActualExpression) {
reference = SmartPointerManager.createPointer(result)
}
return result
}
@@ -214,24 +215,24 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
}
}
//ugly logic to make sure we are working with right actual expression
var actualExpression = reference ?: return
var actualExpression = reference?.element ?: return
var diff = actualExpression.textRange.startOffset - oldElement.textRange.startOffset
var actualExpressionText = actualExpression.text
val newElement = emptyBody.addAfter(oldElement, firstChild)
var elem: PsiElement? = findElementByOffsetAndText(diff, actualExpressionText, newElement)
if (elem != null) {
reference = elem as KtExpression
reference = SmartPointerManager.createPointer(elem as KtExpression)
}
emptyBody.addAfter(psiFactory.createNewLine(), firstChild)
property = emptyBody.addAfter(property, firstChild) as KtProperty
emptyBody.addAfter(psiFactory.createNewLine(), firstChild)
actualExpression = reference ?: return
actualExpression = reference?.element ?: return
diff = actualExpression.textRange.startOffset - emptyBody.textRange.startOffset
actualExpressionText = actualExpression.text
emptyBody = anchor.replace(emptyBody) as KtBlockExpression
elem = findElementByOffsetAndText(diff, actualExpressionText, emptyBody)
if (elem != null) {
reference = elem as KtExpression
reference = SmartPointerManager.createPointer(elem as KtExpression)
}
emptyBody.accept(
@@ -240,7 +241,7 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
if (!expression.isOccurrence) return
expression.isOccurrence = false
references.add(expression)
references.add(SmartPointerManager.createPointer(expression))
}
})
}
@@ -615,8 +616,8 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
is KtProperty -> {
KotlinVariableInplaceIntroducer(
property,
introduceVariableContext.reference,
introduceVariableContext.references.toTypedArray(),
introduceVariableContext.reference?.element,
introduceVariableContext.references.mapNotNull { it.element }.toTypedArray(),
suggestedNames.single(),
isVar,
/*todo*/ false,
@@ -0,0 +1,4 @@
fun foo() {
val z = <selection>123</selection>
val x: (Int) -> Int = { 123}
}
@@ -0,0 +1,5 @@
fun foo() {
val i = 123
val z = i
val x: (Int) -> Int = { i }
}
@@ -110,6 +110,11 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
runTest("idea/testData/refactoring/introduceVariable/FewOccurrences.kt");
}
@TestMetadata("FromLambda.kt")
public void testFromLambda() throws Exception {
runTest("idea/testData/refactoring/introduceVariable/FromLambda.kt");
}
@TestMetadata("FunctionAddBlock.kt")
public void testFunctionAddBlock() throws Exception {
runTest("idea/testData/refactoring/introduceVariable/FunctionAddBlock.kt");