From fd41e266fbfef794742c5d22f51721f55d52bb8d Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 18 Apr 2017 20:39:53 +0300 Subject: [PATCH] Quick Fixes: Add/remove 'suspend' in hierarchy #KT-15903 Fixed --- .../jetbrains/kotlin/util/descriptorUtils.kt | 11 +- .../quickfix/ChangeSuspendInHierarchyFix.kt | 193 ++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 + .../quickfix/addSuspend/fakeOverride.kt | 46 +++++ .../quickfix/addSuspend/fakeOverride.kt.after | 46 +++++ .../quickfix/addSuspend/fakeOverride2.kt | 46 +++++ .../addSuspend/fakeOverride2.kt.after | 46 +++++ .../quickfix/addSuspend/middleClass.kt | 50 +++++ .../quickfix/addSuspend/middleClass.kt.after | 50 +++++ .../quickfix/addSuspend/middleClass2.kt | 50 +++++ .../quickfix/addSuspend/middleClass2.kt.after | 50 +++++ .../quickfix/addSuspend/nonOverridden.kt | 50 +++++ .../addSuspend/nonOverridden.kt.after | 50 +++++ .../quickfix/addSuspend/nonOverridden2.kt | 50 +++++ .../addSuspend/nonOverridden2.kt.after | 50 +++++ .../quickfix/removeSuspend/fakeOverride.kt | 46 +++++ .../removeSuspend/fakeOverride.kt.after | 46 +++++ .../quickfix/removeSuspend/fakeOverride2.kt | 46 +++++ .../removeSuspend/fakeOverride2.kt.after | 46 +++++ .../quickfix/removeSuspend/middleClass.kt | 50 +++++ .../removeSuspend/middleClass.kt.after | 50 +++++ .../quickfix/removeSuspend/middleClass2.kt | 50 +++++ .../removeSuspend/middleClass2.kt.after | 50 +++++ .../quickfix/removeSuspend/nonOverridden.kt | 50 +++++ .../removeSuspend/nonOverridden.kt.after | 50 +++++ .../quickfix/removeSuspend/nonOverridden2.kt | 50 +++++ .../removeSuspend/nonOverridden2.kt.after | 50 +++++ .../idea/quickfix/QuickFixTestGenerated.java | 90 ++++++++ 28 files changed, 1461 insertions(+), 3 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeSuspendInHierarchyFix.kt create mode 100644 idea/testData/quickfix/addSuspend/fakeOverride.kt create mode 100644 idea/testData/quickfix/addSuspend/fakeOverride.kt.after create mode 100644 idea/testData/quickfix/addSuspend/fakeOverride2.kt create mode 100644 idea/testData/quickfix/addSuspend/fakeOverride2.kt.after create mode 100644 idea/testData/quickfix/addSuspend/middleClass.kt create mode 100644 idea/testData/quickfix/addSuspend/middleClass.kt.after create mode 100644 idea/testData/quickfix/addSuspend/middleClass2.kt create mode 100644 idea/testData/quickfix/addSuspend/middleClass2.kt.after create mode 100644 idea/testData/quickfix/addSuspend/nonOverridden.kt create mode 100644 idea/testData/quickfix/addSuspend/nonOverridden.kt.after create mode 100644 idea/testData/quickfix/addSuspend/nonOverridden2.kt create mode 100644 idea/testData/quickfix/addSuspend/nonOverridden2.kt.after create mode 100644 idea/testData/quickfix/removeSuspend/fakeOverride.kt create mode 100644 idea/testData/quickfix/removeSuspend/fakeOverride.kt.after create mode 100644 idea/testData/quickfix/removeSuspend/fakeOverride2.kt create mode 100644 idea/testData/quickfix/removeSuspend/fakeOverride2.kt.after create mode 100644 idea/testData/quickfix/removeSuspend/middleClass.kt create mode 100644 idea/testData/quickfix/removeSuspend/middleClass.kt.after create mode 100644 idea/testData/quickfix/removeSuspend/middleClass2.kt create mode 100644 idea/testData/quickfix/removeSuspend/middleClass2.kt.after create mode 100644 idea/testData/quickfix/removeSuspend/nonOverridden.kt create mode 100644 idea/testData/quickfix/removeSuspend/nonOverridden.kt.after create mode 100644 idea/testData/quickfix/removeSuspend/nonOverridden2.kt create mode 100644 idea/testData/quickfix/removeSuspend/nonOverridden2.kt.after diff --git a/idea/ide-common/src/org/jetbrains/kotlin/util/descriptorUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/util/descriptorUtils.kt index 9ef223a872c..3f22f514a16 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/util/descriptorUtils.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/util/descriptorUtils.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.util import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.CONFLICT import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -60,14 +61,18 @@ fun descriptorsEqualWithSubstitution(descriptor1: DeclarationDescriptor?, descri return true } -fun ClassDescriptor.findCallableMemberBySignature(signature: CallableMemberDescriptor): CallableMemberDescriptor? { +fun ClassDescriptor.findCallableMemberBySignature( + signature: CallableMemberDescriptor, + allowOverridabilityConflicts: Boolean = false +): CallableMemberDescriptor? { val descriptorKind = if (signature is FunctionDescriptor) DescriptorKindFilter.FUNCTIONS else DescriptorKindFilter.VARIABLES return defaultType.memberScope .getContributedDescriptors(descriptorKind) .filterIsInstance() .firstOrNull { - it.containingDeclaration == this - && OverridingUtil.DEFAULT.isOverridableBy(it as CallableDescriptor, signature, null).result == OVERRIDABLE + if (it.containingDeclaration != this) return@firstOrNull false + val overridability = OverridingUtil.DEFAULT.isOverridableBy(it as CallableDescriptor, signature, null).result + overridability == OVERRIDABLE || (allowOverridabilityConflicts && overridability == CONFLICT) } as? CallableMemberDescriptor } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeSuspendInHierarchyFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeSuspendInHierarchyFix.kt new file mode 100644 index 00000000000..6eb6bf777a5 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeSuspendInHierarchyFix.kt @@ -0,0 +1,193 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiNamedElement +import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor +import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde +import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress +import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest +import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf +import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor +import org.jetbrains.kotlin.util.findCallableMemberBySignature +import org.jetbrains.kotlin.utils.DFS +import org.jetbrains.kotlin.utils.ifEmpty +import java.util.ArrayList +import kotlin.collections.Collection +import kotlin.collections.HashMap +import kotlin.collections.LinkedHashSet +import kotlin.collections.List +import kotlin.collections.Set +import kotlin.collections.emptyList +import kotlin.collections.emptySet +import kotlin.collections.filter +import kotlin.collections.flatMap +import kotlin.collections.forEach +import kotlin.collections.getOrPut +import kotlin.collections.listOf +import kotlin.collections.mapNotNullTo +import kotlin.collections.plus + +class ChangeSuspendInHierarchyFix( + element: KtNamedFunction, + private val addModifier: Boolean +) : KotlinQuickFixAction(element) { + override fun getFamilyName(): String { + return if (addModifier) { + "Add 'suspend' modifier to all functions in hierarchy" + } else { + "Remove 'suspend' modifier from all functions in hierarchy" + } + } + + override fun getText() = familyName + + override fun startInWriteAction() = false + + private fun findAllFunctionToProcess(project: Project): Set { + val result = LinkedHashSet() + + val progressIndicator = ProgressManager.getInstance().progressIndicator + + val function = element ?: return emptySet() + val functionDescriptor = function.resolveToDescriptor() as FunctionDescriptor + + val baseFunctionDescriptors = functionDescriptor.findTopMostOverriddables() + baseFunctionDescriptors.forEach { baseFunctionDescriptor -> + val baseClassDescriptor = baseFunctionDescriptor.containingDeclaration as? ClassDescriptor ?: return@forEach + val baseClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, baseClassDescriptor) ?: return@forEach + + val name = (baseClass as? PsiNamedElement)?.name ?: return@forEach + progressIndicator.text = "Looking for class $name inheritors..." + val classes = listOf(baseClass) + HierarchySearchRequest(baseClass, baseClass.useScope).searchInheritors() + classes.mapNotNullTo(result) { + val subClass = it.unwrapped as? KtClassOrObject ?: return@mapNotNullTo null + val classDescriptor = subClass.resolveToDescriptor() as ClassDescriptor + val substitutor = getTypeSubstitutor(baseClassDescriptor.defaultType, classDescriptor.defaultType) + ?: return@mapNotNullTo null + val signatureInSubClass = baseFunctionDescriptor.substitute(substitutor) as FunctionDescriptor + val subFunctionDescriptor = classDescriptor.findCallableMemberBySignature(signatureInSubClass, true) + ?: return@mapNotNullTo null + subFunctionDescriptor.source.getPsi() as? KtNamedFunction + } + } + + return result + } + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val functions = project.runSynchronouslyWithProgress("Analyzing class hierarchy...", true) { + runReadAction { findAllFunctionToProcess(project) } + } ?: return + + runWriteAction { + functions.forEach { + if (addModifier) { + it.addModifier(KtTokens.SUSPEND_KEYWORD) + } + else { + it.removeModifier(KtTokens.SUSPEND_KEYWORD) + } + } + } + } + + companion object : KotlinIntentionActionsFactory() { + fun FunctionDescriptor.findTopMostOverriddables(): List { + val overridablesCache = HashMap>() + + fun FunctionDescriptor.getOverridables(): List { + return overridablesCache.getOrPut(this) { + val classDescriptor = containingDeclaration as? ClassDescriptorWithResolutionScopes ?: return emptyList() + DescriptorUtils.getSuperclassDescriptors(classDescriptor).flatMap { superClassDescriptor -> + if (superClassDescriptor !is ClassDescriptorWithResolutionScopes) return@flatMap emptyList() + val candidates = superClassDescriptor.unsubstitutedMemberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE) + val substitutor = getTypeSubstitutor(superClassDescriptor.defaultType, classDescriptor.defaultType) + ?: return@flatMap emptyList() + candidates.filter { + val signature = it.substitute(substitutor) as FunctionDescriptor + classDescriptor.findCallableMemberBySignature(signature, true) == this + } + } + } + } + + return DFS.dfs( + listOf(this), + { (it as? FunctionDescriptor)?.getOverridables() ?: emptyList() }, + object : DFS.CollectingNodeHandler>(ArrayList()) { + override fun afterChildren(current: FunctionDescriptor) { + if (current.getOverridables().isEmpty()) { + result.add(current) + } + } + }) + } + + private fun Collection.getOverridables( + currentDescriptor: FunctionDescriptor + ): List { + val currentClassDescriptor = currentDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList() + return filter { + if (it !is FunctionDescriptor || it == currentDescriptor) return@filter false + if (it.isSuspend == currentDescriptor.isSuspend) return@filter false + val containingClassDescriptor = it.containingDeclaration as? ClassDescriptor ?: return@filter false + if (!currentClassDescriptor.isSubclassOf(containingClassDescriptor)) return@filter false + val substitutor = getTypeSubstitutor( + containingClassDescriptor.defaultType, + currentClassDescriptor.defaultType + ) ?: return@filter false + val signatureInCurrentClass = it.substitute(substitutor) as? FunctionDescriptor ?: return@filter false + OverridingUtil.DEFAULT.isOverridableBy(signatureInCurrentClass, currentDescriptor, null).result == + OverridingUtil.OverrideCompatibilityInfo.Result.CONFLICT + } + } + + override fun doCreateActions(diagnostic: Diagnostic): List { + val currentFunction = diagnostic.psiElement as? KtNamedFunction ?: return emptyList() + val currentDescriptor = currentFunction.resolveToDescriptor() as FunctionDescriptor + Errors.CONFLICTING_OVERLOADS.cast(diagnostic).a.getOverridables(currentDescriptor).ifEmpty { return emptyList() } + + return listOf( + ChangeSuspendInHierarchyFix(currentFunction, true), + ChangeSuspendInHierarchyFix(currentFunction, false) + ) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 8fa538bd5a5..b2f2bc13efa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -485,5 +485,7 @@ class QuickFixRegistrar : QuickFixContributor { ILLEGAL_INLINE_PARAMETER_MODIFIER.registerFactory(AddInlineToFunctionFix) INAPPLICABLE_JVM_FIELD.registerFactory(ReplaceJvmFieldWithConstFix) + + CONFLICTING_OVERLOADS.registerFactory(ChangeSuspendInHierarchyFix) } } diff --git a/idea/testData/quickfix/addSuspend/fakeOverride.kt b/idea/testData/quickfix/addSuspend/fakeOverride.kt new file mode 100644 index 00000000000..1bbc698197f --- /dev/null +++ b/idea/testData/quickfix/addSuspend/fakeOverride.kt @@ -0,0 +1,46 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/fakeOverride.kt.after b/idea/testData/quickfix/addSuspend/fakeOverride.kt.after new file mode 100644 index 00000000000..f39be6e02cd --- /dev/null +++ b/idea/testData/quickfix/addSuspend/fakeOverride.kt.after @@ -0,0 +1,46 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/fakeOverride2.kt b/idea/testData/quickfix/addSuspend/fakeOverride2.kt new file mode 100644 index 00000000000..51b0e81f05c --- /dev/null +++ b/idea/testData/quickfix/addSuspend/fakeOverride2.kt @@ -0,0 +1,46 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/fakeOverride2.kt.after b/idea/testData/quickfix/addSuspend/fakeOverride2.kt.after new file mode 100644 index 00000000000..f39be6e02cd --- /dev/null +++ b/idea/testData/quickfix/addSuspend/fakeOverride2.kt.after @@ -0,0 +1,46 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/middleClass.kt b/idea/testData/quickfix/addSuspend/middleClass.kt new file mode 100644 index 00000000000..9c0df527767 --- /dev/null +++ b/idea/testData/quickfix/addSuspend/middleClass.kt @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/middleClass.kt.after b/idea/testData/quickfix/addSuspend/middleClass.kt.after new file mode 100644 index 00000000000..56c3c6ae58b --- /dev/null +++ b/idea/testData/quickfix/addSuspend/middleClass.kt.after @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/middleClass2.kt b/idea/testData/quickfix/addSuspend/middleClass2.kt new file mode 100644 index 00000000000..f6aa15ec494 --- /dev/null +++ b/idea/testData/quickfix/addSuspend/middleClass2.kt @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/middleClass2.kt.after b/idea/testData/quickfix/addSuspend/middleClass2.kt.after new file mode 100644 index 00000000000..56c3c6ae58b --- /dev/null +++ b/idea/testData/quickfix/addSuspend/middleClass2.kt.after @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/nonOverridden.kt b/idea/testData/quickfix/addSuspend/nonOverridden.kt new file mode 100644 index 00000000000..553278c9b02 --- /dev/null +++ b/idea/testData/quickfix/addSuspend/nonOverridden.kt @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/nonOverridden.kt.after b/idea/testData/quickfix/addSuspend/nonOverridden.kt.after new file mode 100644 index 00000000000..56c3c6ae58b --- /dev/null +++ b/idea/testData/quickfix/addSuspend/nonOverridden.kt.after @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/nonOverridden2.kt b/idea/testData/quickfix/addSuspend/nonOverridden2.kt new file mode 100644 index 00000000000..37ef2d4840a --- /dev/null +++ b/idea/testData/quickfix/addSuspend/nonOverridden2.kt @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSuspend/nonOverridden2.kt.after b/idea/testData/quickfix/addSuspend/nonOverridden2.kt.after new file mode 100644 index 00000000000..56c3c6ae58b --- /dev/null +++ b/idea/testData/quickfix/addSuspend/nonOverridden2.kt.after @@ -0,0 +1,50 @@ +// "Add 'suspend' modifier to all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/fakeOverride.kt b/idea/testData/quickfix/removeSuspend/fakeOverride.kt new file mode 100644 index 00000000000..8064b7fdcb1 --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/fakeOverride.kt @@ -0,0 +1,46 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/fakeOverride.kt.after b/idea/testData/quickfix/removeSuspend/fakeOverride.kt.after new file mode 100644 index 00000000000..7d399cc77c4 --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/fakeOverride.kt.after @@ -0,0 +1,46 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/fakeOverride2.kt b/idea/testData/quickfix/removeSuspend/fakeOverride2.kt new file mode 100644 index 00000000000..d77961091b5 --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/fakeOverride2.kt @@ -0,0 +1,46 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/fakeOverride2.kt.after b/idea/testData/quickfix/removeSuspend/fakeOverride2.kt.after new file mode 100644 index 00000000000..7d399cc77c4 --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/fakeOverride2.kt.after @@ -0,0 +1,46 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/middleClass.kt b/idea/testData/quickfix/removeSuspend/middleClass.kt new file mode 100644 index 00000000000..0635f4310de --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/middleClass.kt @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/middleClass.kt.after b/idea/testData/quickfix/removeSuspend/middleClass.kt.after new file mode 100644 index 00000000000..47d0e0cee4a --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/middleClass.kt.after @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/middleClass2.kt b/idea/testData/quickfix/removeSuspend/middleClass2.kt new file mode 100644 index 00000000000..801b9f5dd4d --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/middleClass2.kt @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/middleClass2.kt.after b/idea/testData/quickfix/removeSuspend/middleClass2.kt.after new file mode 100644 index 00000000000..47d0e0cee4a --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/middleClass2.kt.after @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/nonOverridden.kt b/idea/testData/quickfix/removeSuspend/nonOverridden.kt new file mode 100644 index 00000000000..e87173cddc3 --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/nonOverridden.kt @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/nonOverridden.kt.after b/idea/testData/quickfix/removeSuspend/nonOverridden.kt.after new file mode 100644 index 00000000000..47d0e0cee4a --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/nonOverridden.kt.after @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/nonOverridden2.kt b/idea/testData/quickfix/removeSuspend/nonOverridden2.kt new file mode 100644 index 00000000000..4c285785e1c --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/nonOverridden2.kt @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open suspend fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override suspend fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeSuspend/nonOverridden2.kt.after b/idea/testData/quickfix/removeSuspend/nonOverridden2.kt.after new file mode 100644 index 00000000000..47d0e0cee4a --- /dev/null +++ b/idea/testData/quickfix/removeSuspend/nonOverridden2.kt.after @@ -0,0 +1,50 @@ +// "Remove 'suspend' modifier from all functions in hierarchy" "true" +open class A { + open fun foo() { + + } + + open fun foo(n: Int) { + + } +} + +open class B : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class B1 : A() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} + +open class C1 : B() { + override fun foo() { + + } + + override fun foo(n: Int) { + + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 9bfcd6d6428..234c9856e47 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -666,6 +666,51 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/addSuspend") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddSuspend extends AbstractQuickFixTest { + public void testAllFilesPresentInAddSuspend() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/addSuspend"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("fakeOverride.kt") + public void testFakeOverride() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addSuspend/fakeOverride.kt"); + doTest(fileName); + } + + @TestMetadata("fakeOverride2.kt") + public void testFakeOverride2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addSuspend/fakeOverride2.kt"); + doTest(fileName); + } + + @TestMetadata("middleClass.kt") + public void testMiddleClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addSuspend/middleClass.kt"); + doTest(fileName); + } + + @TestMetadata("middleClass2.kt") + public void testMiddleClass2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addSuspend/middleClass2.kt"); + doTest(fileName); + } + + @TestMetadata("nonOverridden.kt") + public void testNonOverridden() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addSuspend/nonOverridden.kt"); + doTest(fileName); + } + + @TestMetadata("nonOverridden2.kt") + public void testNonOverridden2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addSuspend/nonOverridden2.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/addTypeAnnotationToValueParameter") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -7887,6 +7932,51 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/removeSuspend") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RemoveSuspend extends AbstractQuickFixTest { + public void testAllFilesPresentInRemoveSuspend() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/removeSuspend"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("fakeOverride.kt") + public void testFakeOverride() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeSuspend/fakeOverride.kt"); + doTest(fileName); + } + + @TestMetadata("fakeOverride2.kt") + public void testFakeOverride2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeSuspend/fakeOverride2.kt"); + doTest(fileName); + } + + @TestMetadata("middleClass.kt") + public void testMiddleClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeSuspend/middleClass.kt"); + doTest(fileName); + } + + @TestMetadata("middleClass2.kt") + public void testMiddleClass2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeSuspend/middleClass2.kt"); + doTest(fileName); + } + + @TestMetadata("nonOverridden.kt") + public void testNonOverridden() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeSuspend/nonOverridden.kt"); + doTest(fileName); + } + + @TestMetadata("nonOverridden2.kt") + public void testNonOverridden2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeSuspend/nonOverridden2.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/removeToStringInStringTemplate") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)