diff --git a/ChangeLog.md b/ChangeLog.md index ec682b051d4..95b37f6481b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -119,6 +119,10 @@ These artifacts include extensions for the types available in the latter JDKs, s - [`KT-11115`](https://youtrack.jetbrains.com/issue/KT-11115) Implement Members: Fix base member detection when abstract and non-abstract members with matching signatures are inherited from an interface +###### New features + +- [`KT-7492`](https://youtrack.jetbrains.com/issue/KT-7492) Support "Create abstract function/property" inside an abstract class + #### Refactorings ###### Issues fixed diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 8fa08fa9c68..2bf5dfb1477 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -284,8 +284,7 @@ class QuickFixRegistrar : QuickFixContributor { TOO_MANY_ARGUMENTS.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES) EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES) NONE_APPLICABLE.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES) - TYPE_MISMATCH.registerFactory(CreateCallableFromCallActionFactory.Function) - TYPE_MISMATCH.registerFactory(CreateCallableFromCallActionFactory.Constructor) + TYPE_MISMATCH.registerFactory(*CreateCallableFromCallActionFactory.FUNCTIONS) NO_VALUE_FOR_PARAMETER.registerFactory(CreateConstructorFromDelegationCallActionFactory) TOO_MANY_ARGUMENTS.registerFactory(CreateConstructorFromDelegationCallActionFactory) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 00e8e46ec42..7359f3169cc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -443,10 +443,12 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { val psiFactory = KtPsiFactory(currentFile) val modifiers = - if (containingElement is KtClassOrObject - && containingElement.isAncestor(config.originalElement) - && callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR) - "private " + if (callableInfo.isAbstract) { + if (containingElement is KtClass && containingElement.isInterface()) "" else "abstract " + } + else if (containingElement is KtClassOrObject + && containingElement.isAncestor(config.originalElement) + && callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR) "private " else "" val declaration: KtNamedDeclaration = when (callableInfo.kind) { @@ -454,6 +456,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { val body = when { containingElement is KtClass && containingElement.isInterface() && !config.isExtension -> "" callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR -> "" + callableInfo.isAbstract -> "" else -> "{}" } @Suppress("USELESS_CAST") // KT-10755 diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt index e55ef153303..820444223dc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt @@ -133,10 +133,15 @@ abstract class CallableInfo ( val receiverTypeInfo: TypeInfo, val returnTypeInfo: TypeInfo, val possibleContainers: List, - val typeParameterInfos: List + val typeParameterInfos: List, + val isAbstract: Boolean = false ) { abstract val kind: CallableKind abstract val parameterInfos: List + + abstract fun copy(receiverTypeInfo: TypeInfo = this.receiverTypeInfo, + possibleContainers: List = this.possibleContainers, + isAbstract: Boolean = this.isAbstract): CallableInfo } class FunctionInfo(name: String, @@ -146,23 +151,40 @@ class FunctionInfo(name: String, override val parameterInfos: List = Collections.emptyList(), typeParameterInfos: List = Collections.emptyList(), val isOperator: Boolean = false, - val isInfix: Boolean = false -) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos) { + val isInfix: Boolean = false, + isAbstract: Boolean = false +) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isAbstract) { override val kind: CallableKind get() = CallableKind.FUNCTION + + override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List, isAbstract: Boolean) = FunctionInfo( + name, + receiverTypeInfo, + returnTypeInfo, + possibleContainers, + parameterInfos, + typeParameterInfos, + isOperator, + isInfix, + isAbstract + ) } class PrimaryConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInfo): CallableInfo( - classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments + classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments, false ) { override val kind: CallableKind get() = CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR override val parameterInfos: List get() = classInfo.parameterInfos + + override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List, isAbstract: Boolean) = throw UnsupportedOperationException() } class SecondaryConstructorInfo( override val parameterInfos: List, val targetClass: PsiElement -): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList()) { +): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList(), false) { override val kind: CallableKind get() = CallableKind.SECONDARY_CONSTRUCTOR + + override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List, isAbstract: Boolean) = throw UnsupportedOperationException() } class PropertyInfo(name: String, @@ -170,8 +192,19 @@ class PropertyInfo(name: String, returnTypeInfo: TypeInfo, val writable: Boolean, possibleContainers: List = Collections.emptyList(), - typeParameterInfos: List = Collections.emptyList() -) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos) { + typeParameterInfos: List = Collections.emptyList(), + isAbstract: Boolean = false +) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isAbstract) { override val kind: CallableKind get() = CallableKind.PROPERTY override val parameterInfos: List get() = Collections.emptyList() + + override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List, isAbstract: Boolean) = PropertyInfo( + name, + receiverTypeInfo, + returnTypeInfo, + writable, + possibleContainers, + typeParameterInfos, + isAbstract + ) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt index 2b024fadbb3..dbe0ce0d02a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.* import org.jetbrains.kotlin.idea.refactoring.canRefactor @@ -127,7 +128,21 @@ sealed class CreateCallableFromCallActionFactory( } } - object Property: CreateCallableFromCallActionFactory() { + protected fun getAbstractCallableInfo(mainCallable: CallableInfo, originalExpression: KtExpression): CallableInfo? { + val containingClass = originalExpression.getStrictParentOfType() as? KtClass ?: return null + if (!containingClass.isAbstract()) return null + + val receiverTypeInfo = mainCallable.receiverTypeInfo + if (receiverTypeInfo != TypeInfo.Empty) { + if (receiverTypeInfo !is TypeInfo.ByType) return null + val containingDescriptor = containingClass.resolveToDescriptor() as ClassDescriptor + if (receiverTypeInfo.theType.constructor.declarationDescriptor != containingDescriptor) return null + } + + return mainCallable.copy(receiverTypeInfo = TypeInfo.Empty, possibleContainers = listOf(containingClass), isAbstract = true) + } + + sealed class Property: CreateCallableFromCallActionFactory() { override fun getElementOfInterest(diagnostic: Diagnostic): KtSimpleNameExpression? { val refExpr = getExpressionOfInterest(diagnostic) as? KtNameReferenceExpression ?: return null if (refExpr.getParentOfTypeAndBranch { callableReference } != null) return null @@ -149,9 +164,23 @@ sealed class CreateCallableFromCallActionFactory( ) return PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers) } + + object Default : Property() + + object Abstract : Property() { + override fun doCreateCallableInfo( + expression: KtSimpleNameExpression, + context: BindingContext, + name: String, + receiverType: TypeInfo, + possibleContainers: List + ) = super.doCreateCallableInfo(expression, context, name, receiverType, possibleContainers)?.let { + getAbstractCallableInfo(it, expression) + } + } } - object Function: CreateCallableFromCallActionFactory() { + sealed class Function: CreateCallableFromCallActionFactory() { override fun getElementOfInterest(diagnostic: Diagnostic): KtCallExpression? { return getExpressionOfInterest(diagnostic) as? KtCallExpression } @@ -168,6 +197,20 @@ sealed class CreateCallableFromCallActionFactory( val returnType = TypeInfo(expression.getQualifiedExpressionForSelectorOrThis(), Variance.OUT_VARIANCE) return FunctionInfo(name, receiverType, returnType, possibleContainers, parameters, typeParameters) } + + object Default : Function() + + object Abstract : Function() { + override fun doCreateCallableInfo( + expression: KtCallExpression, + context: BindingContext, + name: String, + receiverType: TypeInfo, + possibleContainers: List + ) = super.doCreateCallableInfo(expression, context, name, receiverType, possibleContainers)?.let { + getAbstractCallableInfo(it, expression) + } + } } object Constructor: CreateCallableFromCallActionFactory() { @@ -204,6 +247,13 @@ sealed class CreateCallableFromCallActionFactory( } companion object { - val INSTANCES = arrayOf(Function, Constructor, Property) + val FUNCTIONS = arrayOf(Function.Default, + Function.Abstract, + Constructor) + val INSTANCES = arrayOf(Function.Default, + Function.Abstract, + Constructor, + Property.Default, + Property.Abstract) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt index 36fcf5ab68e..2fa298ba0a1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt @@ -79,13 +79,23 @@ abstract class CreateCallableFromUsageFixBase( override fun getText(): String { val renderedCallables = callableInfos.map { - val kind = when (it.kind) { - CallableKind.FUNCTION -> "function" - CallableKind.PROPERTY -> "property" - CallableKind.SECONDARY_CONSTRUCTOR -> "secondary constructor" - else -> throw AssertionError("Unexpected callable info: $it") + buildString { + if (it.isAbstract) { + append("abstract ") + } + + val kind = when (it.kind) { + CallableKind.FUNCTION -> "function" + CallableKind.PROPERTY -> "property" + CallableKind.SECONDARY_CONSTRUCTOR -> "secondary constructor" + else -> throw AssertionError("Unexpected callable info: $it") + } + append(kind) + + if (it.name.isNotEmpty()) { + append(" '${it.name}'") + } } - if (it.name.isNotEmpty()) "$kind '${it.name}'" else kind } return StringBuilder().apply { diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt new file mode 100644 index 00000000000..bdb59727ed1 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt @@ -0,0 +1,8 @@ +// "Create abstract function 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo(1, "2")) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt.after new file mode 100644 index 00000000000..2a30cdc48ae --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt.after @@ -0,0 +1,10 @@ +// "Create abstract function 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo(1, "2")) + } + + abstract fun foo(i: Int, s: String): Boolean +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt new file mode 100644 index 00000000000..2d1a864e9f1 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt @@ -0,0 +1,8 @@ +// "Create abstract function 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + fun test(a: A) { + bar(a.foo(1, "2")) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt.after new file mode 100644 index 00000000000..6d69552e7f0 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt.after @@ -0,0 +1,10 @@ +// "Create abstract function 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + fun test(a: A) { + bar(a.foo(1, "2")) + } + + abstract fun foo(i: Int, s: String): Boolean +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt new file mode 100644 index 00000000000..0c1983d2a0c --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt @@ -0,0 +1,8 @@ +// "Create abstract function 'foo'" "true" +interface A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo(1, "2")) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt.after new file mode 100644 index 00000000000..bc0df196658 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt.after @@ -0,0 +1,10 @@ +// "Create abstract function 'foo'" "true" +interface A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo(1, "2")) + } + + fun foo(i: Int, s: String): Boolean +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt new file mode 100644 index 00000000000..05bdc0d42dc --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt @@ -0,0 +1,12 @@ +// "Create abstract function 'foo'" "false" +// ACTION: Convert to expression body +// ACTION: Create function 'foo' +// ACTION: Rename reference +// ERROR: Unresolved reference: foo +class A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo(1, "2")) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt new file mode 100644 index 00000000000..f0703a047f4 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt @@ -0,0 +1,17 @@ +// "Create abstract function 'foo'" "false" +// ACTION: Convert to expression body +// ACTION: Create extension function 'foo' +// ACTION: Create member function 'foo' +// ACTION: Rename reference +// ERROR: Unresolved reference: foo +abstract class A { + fun bar(b: Boolean) {} + + fun test() { + bar(B().foo(1, "2")) + } +} + +class B { + +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt index cf2a9eb729a..bf57538add6 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt @@ -2,6 +2,7 @@ // ACTION: Convert to expression body // ACTION: Create local variable 'foo' // ACTION: Create property 'foo' +// ACTION: Create abstract property 'foo' // ACTION: Rename reference // ERROR: Unresolved reference: foo diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt new file mode 100644 index 00000000000..1133d3018f1 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt @@ -0,0 +1,8 @@ +// "Create abstract property 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt.after new file mode 100644 index 00000000000..021ce43d5b1 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt.after @@ -0,0 +1,10 @@ +// "Create abstract property 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + abstract val foo: Boolean + + fun test() { + bar(foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt new file mode 100644 index 00000000000..bbeb716015d --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt @@ -0,0 +1,8 @@ +// "Create abstract property 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + fun test(a: A) { + bar(a.foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt.after new file mode 100644 index 00000000000..119a0e94efc --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt.after @@ -0,0 +1,10 @@ +// "Create abstract property 'foo'" "true" +abstract class A { + fun bar(b: Boolean) {} + + abstract val foo: Boolean + + fun test(a: A) { + bar(a.foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt new file mode 100644 index 00000000000..7c44577a392 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt @@ -0,0 +1,8 @@ +// "Create abstract property 'foo'" "true" +interface A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt.after new file mode 100644 index 00000000000..668867e2a96 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt.after @@ -0,0 +1,10 @@ +// "Create abstract property 'foo'" "true" +interface A { + fun bar(b: Boolean) {} + + val foo: Boolean + + fun test() { + bar(foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt new file mode 100644 index 00000000000..d99f9bed0ca --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt @@ -0,0 +1,15 @@ +// "Create abstract property 'foo'" "false" +// ACTION: Convert to expression body +// ACTION: Create local variable 'foo' +// ACTION: Create parameter 'foo' +// ACTION: Create property 'foo' +// ACTION: Create property 'foo' as constructor parameter +// ACTION: Rename reference +// ERROR: Unresolved reference: foo +class A { + fun bar(b: Boolean) {} + + fun test() { + bar(foo) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt new file mode 100644 index 00000000000..e0ed57e1a5d --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt @@ -0,0 +1,18 @@ +// "Create abstract property 'foo'" "false" +// ACTION: Convert to expression body +// ACTION: Create extension property 'foo' +// ACTION: Create member property 'foo' +// ACTION: Create property 'foo' as constructor parameter +// ACTION: Rename reference +// ERROR: Unresolved reference: foo +abstract class A { + fun bar(b: Boolean) {} + + fun test() { + bar(B().foo) + } +} + +class B { + +} \ 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 7ee42ae0cdd..c574f5207c2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -2262,6 +2262,45 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/abstract") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Abstract extends AbstractQuickFixTest { + public void testAllFilesPresentInAbstract() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createFunction/call/abstract"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("classNoExplicitReceiver.kt") + public void testClassNoExplicitReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/abstract/classNoExplicitReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("explicitReceiverOfContainingClass.kt") + public void testExplicitReceiverOfContainingClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/abstract/explicitReceiverOfContainingClass.kt"); + doTest(fileName); + } + + @TestMetadata("interfaceNoExplicitReceiver.kt") + public void testInterfaceNoExplicitReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/abstract/interfaceNoExplicitReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("notAbstractClass.kt") + public void testNotAbstractClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/abstract/notAbstractClass.kt"); + doTest(fileName); + } + + @TestMetadata("otherExplicitReceiver.kt") + public void testOtherExplicitReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/abstract/otherExplicitReceiver.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/typeArguments") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -3560,6 +3599,45 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/varOnUserType.kt"); doTest(fileName); } + + @TestMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/abstract") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Abstract extends AbstractQuickFixTest { + public void testAllFilesPresentInAbstract() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createVariable/property/abstract"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("classNoExplicitReceiver.kt") + public void testClassNoExplicitReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/abstract/classNoExplicitReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("explicitReceiverOfContainingClass.kt") + public void testExplicitReceiverOfContainingClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/abstract/explicitReceiverOfContainingClass.kt"); + doTest(fileName); + } + + @TestMetadata("interfaceNoExplicitReceiver.kt") + public void testInterfaceNoExplicitReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/abstract/interfaceNoExplicitReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("notAbstractClass.kt") + public void testNotAbstractClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/abstract/notAbstractClass.kt"); + doTest(fileName); + } + + @TestMetadata("otherExplicitReceiver.kt") + public void testOtherExplicitReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/abstract/otherExplicitReceiver.kt"); + doTest(fileName); + } + } } } }