[kotlin] Add conflict if nested Kotlin properties/methods are moved that are referred to by Java code

KTIJ-28862

GitOrigin-RevId: 6f7de83360a718c2ee5957e85716bb3ad3e8c181
This commit is contained in:
Frederik Haselmeier
2024-11-26 11:10:16 +00:00
committed by intellij-monorepo-bot
parent d77e86c64a
commit 26340dea20
18 changed files with 82 additions and 7 deletions
@@ -1850,6 +1850,8 @@ searching.for.0=Searching for {0}
move.out.of.companion.object=Move out of companion object
calls.with.explicit.extension.receiver.won.t.be.processed.0=Calls with explicit extension receiver won''t be processed: {0}
usages.of.outer.class.instance.inside.of.property.0.won.t.be.processed=Usages of outer class instance inside of property ''{0}'' won''t be processed
usages.of.outer.class.instance.inside.declaration.0.won.t.be.processed=Usages of outer class instance inside declaration ''{0}'' won''t be processed
usages.of.nested.declarations.from.non.kotlin.code.won.t.be.processed=Usages of nested declarations from non-Kotlin code won't be processed
companion.object.already.contains.0=Companion object already contains {0}
0.references.type.parameters.of.the.containing.class={0} references type parameters of the containing class
0.is.overridden.by.declaration.s.in.a.subclass={0} is overridden by declaration(s) in a subclass
@@ -1266,6 +1266,11 @@ public abstract class MoveTestGenerated extends AbstractMoveTest {
runTest("testData/refactoring/moveNested/kotlin/moveNestedClass/protectedClass/protectedClass.test");
}
@TestMetadata("kotlin/moveProperty/moveToTopLevel/externalPropertyUsageFromJava/externalPropertyUsageFromJava.test")
public void testKotlin_moveProperty_moveToTopLevel_externalPropertyUsageFromJava_ExternalPropertyUsageFromJava() throws Exception {
runTest("testData/refactoring/moveNested/kotlin/moveProperty/moveToTopLevel/externalPropertyUsageFromJava/externalPropertyUsageFromJava.test");
}
@TestMetadata("kotlin/moveProperty/moveToTopLevel/moveWithInstanceReference/moveWithInstanceReference.test")
public void testKotlin_moveProperty_moveToTopLevel_moveWithInstanceReference_MoveWithInstanceReference() throws Exception {
runTest("testData/refactoring/moveNested/kotlin/moveProperty/moveToTopLevel/moveWithInstanceReference/moveWithInstanceReference.test");
@@ -1,5 +1,5 @@
// IGNORE_K1
// "Propagate 'MyExperimentalAPI' opt-in requirement to containing class 'Derived'" "false"
// IGNORE_K1
// COMPILER_ARGUMENTS: -opt-in=kotlin.RequiresOptIn
// WITH_STDLIB
// ACTION: Enable a trailing comma by default in the formatter
@@ -0,0 +1 @@
Usages of nested declarations from non-Kotlin code won't be processed
@@ -4,5 +4,5 @@
"outerInstanceParameter": "test",
"withRuntime": "true",
"enabledInK1": "false",
"enabledInK2": "true"
"enabledInK2": "false"
}
@@ -0,0 +1 @@
Usages of outer class instance inside declaration 'foo' won't be processed
@@ -0,0 +1 @@
Usages of outer class instance inside declaration 'Inner' won't be processed
@@ -0,0 +1,7 @@
package bar;
class JavaClass {
public void test() {
System.out.println(new Test().getA());
}
}
@@ -0,0 +1,7 @@
package bar;
class JavaClass {
public void test() {
System.out.println(new Test().getA());
}
}
@@ -0,0 +1 @@
Usages of nested declarations from non-Kotlin code won't be processed
@@ -0,0 +1,8 @@
{
"mainFile": "bar/test.kt",
"type": "MOVE_KOTLIN_NESTED_DECLARATION",
"outerInstanceParameter": "test",
"withRuntime": "true",
"enabledInK1": "false",
"enabledInK2": "true"
}
@@ -1 +1 @@
Usages of outer class instance inside of property 'foo' won't be processed
Usages of outer class instance inside declaration 'foo' won't be processed
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.idea.k2.refactoring.move.descriptor.K2MoveOperationD
import org.jetbrains.kotlin.idea.k2.refactoring.move.descriptor.K2MoveSourceDescriptor
import org.jetbrains.kotlin.idea.k2.refactoring.move.descriptor.K2MoveTargetDescriptor
import org.jetbrains.kotlin.idea.k2.refactoring.move.processor.usages.ImplicitCompanionAsDispatchReceiverUsageInfo
import org.jetbrains.kotlin.idea.k2.refactoring.move.processor.usages.K2MoveRenameUsageInfo
import org.jetbrains.kotlin.idea.k2.refactoring.move.processor.usages.OuterInstanceReferenceUsageInfo
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -49,6 +50,10 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
else -> MoveType.UNKNOWN
}
}
init {
require(operationDescriptor.sourceElements.size == 1) { "We can only move a single nested declaration at a time" }
}
private val elementToMove = operationDescriptor.sourceElements.single()
private fun willLoseOuterInstanceReference(): Boolean {
@@ -68,6 +73,19 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
val element = usage.element ?: continue
val isConflict = when (usage) {
is K2MoveRenameUsageInfo.Light -> {
if (moveType != MoveType.CLASS && operationDescriptor.outerInstanceParameterName != null) {
// We only have the facility to correct outer class usages if the moved declaration is a nested class.
conflicts.putValue(
element,
KotlinBundle.message("usages.of.nested.declarations.from.non.kotlin.code.won.t.be.processed", element.text)
)
true
} else {
false
}
}
is ImplicitCompanionAsDispatchReceiverUsageInfo -> {
val isValidTarget = isValidTargetForImplicitCompanionAsDispatchReceiver(moveDescriptor.target, usage.companionObject)
if (!isValidTarget) {
@@ -80,11 +98,13 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
}
is OuterInstanceReferenceUsageInfo -> {
if (moveType == MoveType.PROPERTY) {
// For properties, any outer instance reference is a conflict because we do not process them.
if (willLoseOuterInstanceReference()) {
conflicts.putValue(
element,
KotlinBundle.message("usages.of.outer.class.instance.inside.of.property.0.won.t.be.processed", elementToMove.nameAsSafeName.asString())
KotlinBundle.message(
"usages.of.outer.class.instance.inside.declaration.0.won.t.be.processed",
elementToMove.nameAsSafeName.asString()
)
)
true
} else {
@@ -117,6 +137,8 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
val outerClass = referencedNestedDeclaration.containingClassOrObject
val lightOuterClass = outerClass?.toLightClass()
if (lightOuterClass != null) {
// While this is called the `MoveInnerClassUsagesHandler`, it will also correctly modify usages
// of inner methods from Kotlin code (but not from Java code!).
MoveInnerClassUsagesHandler.EP_NAME
.forLanguage(usage.element?.language ?: continue)
?.correctInnerClassUsage(usage, lightOuterClass, outerInstanceParameterName)
@@ -166,6 +188,7 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
}
}
}
is KtNamedFunction -> {
if (outerInstanceParameterName != null) {
val outerInstanceType = analyze(originalDeclaration) {
@@ -181,6 +204,7 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
)
}
}
is KtProperty -> {
}
@@ -200,6 +224,7 @@ class K2MoveNestedDeclarationsRefactoringProcessor(
val addedParameter = primaryConstructor.valueParameters.firstOrNull { it.name == outerInstanceParameterName } ?: return
shortenReferences(addedParameter)
}
is KtNamedFunction -> {
val addedParameter = newDeclaration.valueParameterList?.parameters?.firstOrNull() ?: return
shortenReferences(addedParameter)
@@ -270,7 +270,7 @@ sealed class K2MoveModel {
searchReferences = searchReferences.state,
dirStructureMatchesPkg = true,
newClassName = null,
outerInstanceParameterName = outerClassInstanceParameterName.takeIf { needsInstanceReference },
outerInstanceParameterName = outerClassInstanceParameterName.takeIf { passOuterClass },
moveCallBack = moveCallBack
)
}
@@ -390,6 +390,11 @@ public class K2MoveNestedTestGenerated extends AbstractK2MoveNestedTest {
runTest("../../idea/tests/testData/refactoring/moveNested/kotlin/moveNestedClass/protectedClass/protectedClass.test");
}
@TestMetadata("kotlin/moveProperty/moveToTopLevel/externalPropertyUsageFromJava/externalPropertyUsageFromJava.test")
public void testKotlin_moveProperty_moveToTopLevel_externalPropertyUsageFromJava_ExternalPropertyUsageFromJava() throws Exception {
runTest("../../idea/tests/testData/refactoring/moveNested/kotlin/moveProperty/moveToTopLevel/externalPropertyUsageFromJava/externalPropertyUsageFromJava.test");
}
@TestMetadata("kotlin/moveProperty/moveToTopLevel/moveWithInstanceReference/moveWithInstanceReference.test")
public void testKotlin_moveProperty_moveToTopLevel_moveWithInstanceReference_MoveWithInstanceReference() throws Exception {
runTest("../../idea/tests/testData/refactoring/moveNested/kotlin/moveProperty/moveToTopLevel/moveWithInstanceReference/moveWithInstanceReference.test");