Implement liftToExpected correctly for primary constructor properties

Before this commit, we always tried to find expect property in this case.
However, there is at least one case when we should find parameter of
expect primary constructor instead (safe delete).
So #KT-25321 Fixed
This commit is contained in:
Mikhail Glukhikh
2018-07-26 14:02:44 +03:00
parent 437b6f2c2d
commit ddd3a0a46e
19 changed files with 212 additions and 5 deletions
@@ -12,11 +12,12 @@ import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors
import org.jetbrains.kotlin.idea.caches.project.implementingDescriptors
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
@@ -60,13 +61,19 @@ fun KtDeclaration.liftToExpected(): KtDeclaration? {
return DescriptorToSourceUtils.descriptorToDeclaration(expectedDescriptor) as? KtDeclaration
}
fun KtParameter.liftToExpected(): KtParameter? {
val parameterDescriptor = resolveToParameterDescriptorIfAny()
val expectedDescriptor = parameterDescriptor?.liftToExpected() ?: return null
return DescriptorToSourceUtils.descriptorToDeclaration(expectedDescriptor) as? KtParameter
}
fun ModuleDescriptor.hasDeclarationOf(descriptor: MemberDescriptor) = declarationOf(descriptor) != null
private fun ModuleDescriptor.declarationOf(descriptor: MemberDescriptor): DeclarationDescriptor? =
with(ExpectedActualResolver) {
val expectedCompatibilityMap = findExpectedForActual(descriptor, this@declarationOf)
expectedCompatibilityMap?.get(ExpectedActualResolver.Compatibility.Compatible)?.firstOrNull()
?: expectedCompatibilityMap?.values?.flatten()?.firstOrNull()
?: expectedCompatibilityMap?.values?.flatten()?.firstOrNull()
}
fun ModuleDescriptor.hasActualsFor(descriptor: MemberDescriptor) =
@@ -457,7 +457,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
): Collection<PsiElement>? {
when (element) {
is KtParameter -> {
val expectParameter = element.liftToExpected() as? KtParameter
val expectParameter = element.liftToExpected()
if (expectParameter != null && expectParameter != element) {
return if (shouldAllowPropagationToExpected(element)) {
listOf(expectParameter)
@@ -449,7 +449,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
): Collection<PsiElement>? {
when (element) {
is KtParameter -> {
val expectParameter = element.liftToExpected() as? KtParameter
val expectParameter = element.liftToExpected()
if (expectParameter != null && expectParameter != element) {
if (shouldAllowPropagationToExpected(element)) {
return listOf(expectParameter)
@@ -459,7 +459,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
): Collection<PsiElement>? {
when (element) {
is KtParameter -> {
val expectParameter = element.liftToExpected() as? KtParameter
val expectParameter = element.liftToExpected()
if (expectParameter != null && expectParameter != element) {
if (shouldAllowPropagationToExpected(element)) {
return listOf(expectParameter)
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="Common (experimental) " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,8 @@
package test
expect class Foo()
fun test() {
Foo()
Foo()
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JavaScript " useProjectSettings="false">
<implements>Common</implements>
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,12 @@
package test
actual class Foo actual constructor() {
constructor(s: String): this(0)
}
fun test() {
Foo("1")
Foo(s = "1")
Foo()
Foo()
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.6" useProjectSettings="false">
<implements>Common</implements>
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,14 @@
package test
actual class Foo(s: String) {
actual constructor(): this("") {
val x = n + 1
}
}
fun test() {
Foo("1")
Foo(s = "1")
Foo()
Foo()
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="Common (experimental) " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,8 @@
package test
expect class Foo(n: Int)
fun test() {
Foo(1)
Foo(n = 1)
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JavaScript " useProjectSettings="false">
<implements>Common</implements>
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,12 @@
package test
actual class Foo actual constructor(val <caret>n: Int) {
constructor(s: String): this(0)
}
fun test() {
Foo("1")
Foo(s = "1")
Foo(1)
Foo(n = 1)
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.6" useProjectSettings="false">
<implements>Common</implements>
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,14 @@
package test
actual class Foo(s: String) {
actual constructor(n: Int): this("") {
val x = n + 1
}
}
fun test() {
Foo("1")
Foo(s = "1")
Foo(1)
Foo(n = 1)
}
@@ -0,0 +1 @@
parameter n has 2 usages that are not safe to delete.
@@ -0,0 +1,4 @@
{
"mainFile": "JS/src/test/test.kt",
"elementClass": "org.jetbrains.kotlin.psi.KtParameter"
}
@@ -54,6 +54,11 @@ public class MultiModuleSafeDeleteTestGenerated extends AbstractMultiModuleSafeD
runTest("idea/testData/refactoring/safeDeleteMultiModule/byActualClassPrimaryConstructorParameterLiftingToExpect/expectsAndActualsByActualClassPrimaryConstructorParameter.test");
}
@TestMetadata("byActualClassPrimaryConstructorPropertyLiftingToExpect/expectsAndActualsByActualClassPrimaryConstructorProperty.test")
public void testByActualClassPrimaryConstructorPropertyLiftingToExpect_ExpectsAndActualsByActualClassPrimaryConstructorProperty() throws Exception {
runTest("idea/testData/refactoring/safeDeleteMultiModule/byActualClassPrimaryConstructorPropertyLiftingToExpect/expectsAndActualsByActualClassPrimaryConstructorProperty.test");
}
@TestMetadata("byActualClassSecondaryConstructor/byActualClassSecondaryConstructor.test")
public void testByActualClassSecondaryConstructor_ByActualClassSecondaryConstructor() throws Exception {
runTest("idea/testData/refactoring/safeDeleteMultiModule/byActualClassSecondaryConstructor/byActualClassSecondaryConstructor.test");