Move: Fix processing of callable references to nested Kotlin classes
#KT-17827 In Progress
This commit is contained in:
@@ -209,6 +209,7 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
||||
parent is KtCallableReferenceExpression && parent.callableReference == this -> {
|
||||
parentDelimiter = ""
|
||||
val callableRefCopy = parent.copied()
|
||||
callableRefCopy.receiverExpression?.delete()
|
||||
callableRefCopy.callableReference.replace(psiFactory.createSimpleName(shortName)).parent!!.text
|
||||
}
|
||||
else -> shortName
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
@@ -259,6 +260,35 @@ class QualifiableMoveRenameUsageInfo(
|
||||
}
|
||||
}
|
||||
|
||||
interface DeferredKotlinMoveUsage : KotlinMoveUsage {
|
||||
fun resolve(newElement: PsiElement): UsageInfo?
|
||||
}
|
||||
|
||||
class CallableReferenceMoveRenameUsageInfo(
|
||||
element: PsiElement,
|
||||
reference: PsiReference,
|
||||
referencedElement: PsiElement,
|
||||
val originalFile: PsiFile,
|
||||
val addImportToOriginalFile: Boolean,
|
||||
override val isInternal: Boolean
|
||||
) : MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false), DeferredKotlinMoveUsage {
|
||||
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||
return CallableReferenceMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, originalFile, addImportToOriginalFile, isInternal)
|
||||
}
|
||||
|
||||
override fun resolve(newElement: PsiElement): UsageInfo? {
|
||||
val target = newElement.unwrapped
|
||||
val element = element ?: return null
|
||||
val reference = reference ?: return null
|
||||
val referencedElement = referencedElement ?: return null
|
||||
if (target is KtDeclaration && target.parent is KtFile) {
|
||||
element.getStrictParentOfType<KtCallableReferenceExpression>()?.receiverExpression?.delete()
|
||||
return UnqualifiableMoveRenameUsageInfo(element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal)
|
||||
}
|
||||
return QualifiableMoveRenameUsageInfo(element, reference, referencedElement, isInternal)
|
||||
}
|
||||
}
|
||||
|
||||
fun createMoveUsageInfoIfPossible(
|
||||
reference: PsiReference,
|
||||
referencedElement: PsiElement,
|
||||
@@ -273,6 +303,9 @@ fun createMoveUsageInfoIfPossible(
|
||||
ReferenceKind.UNQUALIFIABLE -> UnqualifiableMoveRenameUsageInfo(
|
||||
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal
|
||||
)
|
||||
ReferenceKind.CALLABLE_REFERENCE -> CallableReferenceMoveRenameUsageInfo(
|
||||
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -280,6 +313,7 @@ fun createMoveUsageInfoIfPossible(
|
||||
private enum class ReferenceKind {
|
||||
QUALIFIABLE,
|
||||
UNQUALIFIABLE,
|
||||
CALLABLE_REFERENCE,
|
||||
IRRELEVANT
|
||||
}
|
||||
|
||||
@@ -300,7 +334,11 @@ private fun getReferenceKind(reference: PsiReference, referencedElement: PsiElem
|
||||
if (element.isExtensionRef() && reference.element.getNonStrictParentOfType<KtImportDirective>() == null) return ReferenceKind.UNQUALIFIABLE
|
||||
|
||||
element.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference }?.let {
|
||||
if (it.receiverExpression != null) return ReferenceKind.IRRELEVANT
|
||||
val receiverExpression = it.receiverExpression
|
||||
if (receiverExpression != null) {
|
||||
val lhs = it.analyze(BodyResolveMode.PARTIAL)[BindingContext.DOUBLE_COLON_LHS, receiverExpression]
|
||||
return if (lhs is DoubleColonLHS.Type) ReferenceKind.CALLABLE_REFERENCE else ReferenceKind.IRRELEVANT
|
||||
}
|
||||
if (target is KtDeclaration && target.parent is KtFile) return ReferenceKind.UNQUALIFIABLE
|
||||
if (target is PsiMember && target.containingClass == null) return ReferenceKind.UNQUALIFIABLE
|
||||
}
|
||||
@@ -364,20 +402,28 @@ private fun postProcessMoveUsage(
|
||||
nonCodeUsages: ArrayList<NonCodeUsageInfo>,
|
||||
shorteningMode: ShorteningMode
|
||||
) {
|
||||
if (usage is NonCodeUsageInfo) {
|
||||
nonCodeUsages.add(usage)
|
||||
return
|
||||
}
|
||||
|
||||
if (usage !is MoveRenameUsageInfo) return
|
||||
|
||||
val oldElement = usage.referencedElement!!
|
||||
val newElement = mapToNewOrThis(oldElement, oldToNewElementsMapping)
|
||||
|
||||
when (usage) {
|
||||
is NonCodeUsageInfo -> {
|
||||
nonCodeUsages.add(usage)
|
||||
is DeferredKotlinMoveUsage -> {
|
||||
val newUsage = usage.resolve(newElement) ?: return
|
||||
postProcessMoveUsage(newUsage, oldToNewElementsMapping, nonCodeUsages, shorteningMode)
|
||||
}
|
||||
|
||||
is UnqualifiableMoveRenameUsageInfo -> {
|
||||
val file = with(usage) { if (addImportToOriginalFile) originalFile else mapToNewOrThis(originalFile, oldToNewElementsMapping) } as KtFile
|
||||
val declaration = mapToNewOrThis(usage.referencedElement!!, oldToNewElementsMapping)
|
||||
addDelayedImportRequest(declaration, file)
|
||||
addDelayedImportRequest(newElement, file)
|
||||
}
|
||||
|
||||
is MoveRenameUsageInfo -> {
|
||||
val oldElement = usage.referencedElement!!
|
||||
val newElement = mapToNewOrThis(oldElement, oldToNewElementsMapping)
|
||||
else -> {
|
||||
val reference = (usage.element as? KtSimpleNameExpression)?.mainReference ?: usage.reference
|
||||
processReference(reference, newElement, shorteningMode, oldElement)
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package bar
|
||||
|
||||
class MemberNewEnd {
|
||||
class Nested
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package foo
|
||||
|
||||
import bar.MemberNewEnd
|
||||
|
||||
val v = MemberNewEnd::Nested
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package foo
|
||||
|
||||
class MemberEnd {
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package bar
|
||||
|
||||
class MemberNewEnd
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo
|
||||
|
||||
val v = MemberEnd::Nested
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package foo
|
||||
|
||||
class MemberEnd {
|
||||
class <caret>Nested
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainFile": "foo/MemberEnd.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"targetClass": "bar.MemberNewEnd",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo
|
||||
|
||||
val v = ::Nested
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package foo
|
||||
|
||||
class MemberEnd {
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo
|
||||
|
||||
class Nested
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package foo
|
||||
|
||||
val v = MemberEnd::Nested
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package foo
|
||||
|
||||
class MemberEnd {
|
||||
class <caret>Nested
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "foo/MemberEnd.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+12
@@ -319,6 +319,18 @@ public class MoveTestGenerated extends AbstractMoveTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlin/moveNestedClass/callableReferences/nestedToAnotherClass/nestedToAnotherClass.test")
|
||||
public void testKotlin_moveNestedClass_callableReferences_nestedToAnotherClass_NestedToAnotherClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveNestedClass/callableReferences/nestedToAnotherClass/nestedToAnotherClass.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlin/moveNestedClass/callableReferences/nestedToTopLevel/nestedToTopLevel.test")
|
||||
public void testKotlin_moveNestedClass_callableReferences_nestedToTopLevel_NestedToTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveNestedClass/callableReferences/nestedToTopLevel/nestedToTopLevel.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlin/moveNestedClass/deepInnerToTopLevelWithOuterOuterThis/deepInnerToTopLevelWithOuterOuterThis.test")
|
||||
public void testKotlin_moveNestedClass_deepInnerToTopLevelWithOuterOuterThis_DeepInnerToTopLevelWithOuterOuterThis() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveNestedClass/deepInnerToTopLevelWithOuterOuterThis/deepInnerToTopLevelWithOuterOuterThis.test");
|
||||
|
||||
Reference in New Issue
Block a user