Rename: Suspend function support

This commit is contained in:
Alexey Sedunov
2017-09-18 20:43:52 +03:00
parent c5b7d0f0df
commit 21bf4d3f24
31 changed files with 416 additions and 9 deletions
@@ -30,16 +30,21 @@ import com.intellij.util.Processor
import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.isOverridable
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
import org.jetbrains.kotlin.idea.core.isOverridable
import org.jetbrains.kotlin.idea.search.allScope
import org.jetbrains.kotlin.idea.search.excludeKotlinSources
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -163,4 +168,16 @@ fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement,
val members = ktClass.declarations.filterIsInstance<KtNamedDeclaration>() +
ktClass.primaryConstructorParameters.filter { it.hasValOrVar() }
forEachKotlinOverride(ktClass, members, scope, processor)
}
fun findDeepestSuperMethodsKotlinAware(method: PsiElement): List<PsiMethod> {
val element = method.unwrapped
return when (element) {
is PsiMethod -> element.findDeepestSuperMethods().toList()
is KtCallableDeclaration -> {
val descriptor = element.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return emptyList()
descriptor.getDeepestSuperDeclarations(false).mapNotNull { it.source.getPsi()?.getRepresentativeLightMethod() }
}
else -> emptyList()
}
}
@@ -149,9 +149,9 @@ fun <D : CallableMemberDescriptor> D.getDirectlyOverriddenDeclarations(): Collec
return OverridingUtil.filterOutOverridden(result)
}
fun <D : CallableMemberDescriptor> D.getDeepestSuperDeclarations(): Collection<D> {
fun <D : CallableMemberDescriptor> D.getDeepestSuperDeclarations(withThis: Boolean = true): Collection<D> {
val overriddenDeclarations = DescriptorUtils.getAllOverriddenDeclarations(this)
if (overriddenDeclarations.isEmpty()) {
if (overriddenDeclarations.isEmpty() && withThis) {
return setOf(this)
}
@@ -149,7 +149,7 @@ abstract class CallableRefactoring<out T: CallableDescriptor>(
assert(!closestModifiableDescriptors.isEmpty()) { "Should contain original declaration or some of its super declarations" }
val deepestSuperDeclarations =
(callableDescriptor as? CallableMemberDescriptor)?.let(CallableMemberDescriptor::getDeepestSuperDeclarations)
(callableDescriptor as? CallableMemberDescriptor)?.getDeepestSuperDeclarations()
?: listOf(callableDescriptor)
if (ApplicationManager.getApplication()!!.isUnitTestMode) {
performRefactoring(deepestSuperDeclarations)
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.idea.refactoring.rename
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiReference
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.listeners.RefactoringElementListener
@@ -30,6 +27,7 @@ import com.intellij.refactoring.rename.RenameDialog
import com.intellij.refactoring.rename.RenameJavaMethodProcessor
import com.intellij.refactoring.rename.RenameProcessor
import com.intellij.refactoring.rename.RenameUtil
import com.intellij.refactoring.util.RefactoringUtil
import com.intellij.usageView.UsageInfo
import com.intellij.util.SmartList
import org.jetbrains.kotlin.asJava.LightClassUtil
@@ -45,6 +43,8 @@ import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethodsWithPopup
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.search.declarationsSearch.findDeepestSuperMethodsKotlinAware
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingMethod
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -115,7 +115,7 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
val wrappedMethod = wrapPsiMethod(element) ?: return element
val deepestSuperMethods = wrappedMethod.findDeepestSuperMethods()
val deepestSuperMethods = findDeepestSuperMethodsKotlinAware(wrappedMethod)
val substitutedJavaElement = when {
deepestSuperMethods.isEmpty() -> return element
wrappedMethod.isConstructor || deepestSuperMethods.size == 1 || element !is KtNamedFunction -> {
@@ -149,7 +149,7 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
val wrappedMethod = wrapPsiMethod(element) ?: return
val deepestSuperMethods = wrappedMethod.findDeepestSuperMethods()
val deepestSuperMethods = findDeepestSuperMethodsKotlinAware(wrappedMethod)
when {
deepestSuperMethods.isEmpty() -> preprocessAndPass(element)
wrappedMethod.isConstructor || element !is KtNamedFunction -> {
@@ -186,6 +186,20 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
val psiMethod = wrapPsiMethod(declaration) ?: continue
allRenames[declaration] = newName
if (psiMethod.containingClass != null) {
psiMethod.forEachOverridingMethod { it ->
val overrider = (it as? PsiMirrorElement)?.prototype as? PsiMethod ?: it
if (overrider is SyntheticElement) return@forEachOverridingMethod true
val overriderName = overrider.name
val baseName = psiMethod.name
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName)
if (newOverriderName != null) {
RenameProcessor.assertNonCompileElement(overrider)
allRenames.put(overrider, newOverriderName)
}
return@forEachOverridingMethod true
}
javaMethodProcessorInstance.prepareRenaming(psiMethod, newName, allRenames, scope)
}
}
@@ -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,9 @@
package test
interface I {
suspend fun bar(s: String)
}
fun test(i: I) {
i.bar("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun bar(s: String) { }
}
fun test(c: C) {
c.bar("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun bar(s: String) { }
}
fun test(c: C) {
c.bar("test")
}
@@ -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,9 @@
package test
interface I {
suspend fun foo(s: String)
}
fun test(i: I) {
i.foo("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun /*rename*/foo(s: String) { }
}
fun test(c: C) {
c.foo("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun foo(s: String) { }
}
fun test(c: C) {
c.foo("test")
}
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"file": "JS/src/test/test.kt",
"newName": "bar",
"isMultiModule": "true"
}
@@ -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,9 @@
package test
interface I {
suspend fun bar(s: String)
}
fun test(i: I) {
i.bar("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun bar(s: String) { }
}
fun test(c: C) {
c.bar("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun bar(s: String) { }
}
fun test(c: C) {
c.bar("test")
}
@@ -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,9 @@
package test
interface I {
suspend fun /*rename*/foo(s: String)
}
fun test(i: I) {
i.foo("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun foo(s: String) { }
}
fun test(c: C) {
c.foo("test")
}
@@ -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,9 @@
package test
class C : I {
override suspend fun foo(s: String) { }
}
fun test(c: C) {
c.foo("test")
}
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"file": "Common/src/test/test.kt",
"newName": "bar",
"isMultiModule": "true"
}
@@ -149,4 +149,16 @@ public class MultiModuleRenameTestGenerated extends AbstractMultiModuleRenameTes
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/renameMultiModule/headersAndImplsByImplVal/headersAndImplsByImplVal.test");
doTest(fileName);
}
@TestMetadata("suspendFunImplInImplModule/suspendFunImplInImplModule.test")
public void testSuspendFunImplInImplModule_SuspendFunImplInImplModule() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/renameMultiModule/suspendFunImplInImplModule/suspendFunImplInImplModule.test");
doTest(fileName);
}
@TestMetadata("suspendFunInCommonModule/suspendFunInCommonModule.test")
public void testSuspendFunInCommonModule_SuspendFunInCommonModule() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/renameMultiModule/suspendFunInCommonModule/suspendFunInCommonModule.test");
doTest(fileName);
}
}