From 562488b3482d6081125a2f9ad70131231a47fe8e Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 8 Aug 2016 15:32:54 +0300 Subject: [PATCH] Create from Usage: Disable "Create property" (non-abstract) in interfaces. Make "Create function" (non-abstract) generate function body in interfaces #KT-13365 Fixed --- ChangeLog.md | 1 + .../callableBuilder/CallableBuilder.kt | 2 +- .../CreateCallableFromCallActionFactory.kt | 19 ++++++++++++++++++- .../CreateCallableFromUsageFix.kt | 6 +++++- .../createFunction/call/funOnTrait.kt.after | 4 +++- .../parameter/inAccessorInTrait.kt | 1 - .../property/nonAbstractInInterface.kt | 11 +++++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 6 ++++++ 8 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createVariable/property/nonAbstractInInterface.kt diff --git a/ChangeLog.md b/ChangeLog.md index 2a1ceefa23c..f4bf25d4199 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -216,6 +216,7 @@ These artifacts include extensions for the types available in the latter JDKs, s - [`KT-13262`](https://youtrack.jetbrains.com/issue/KT-13262) "Wrap with safe let call" quickfix produces wrong result for qualified function - [`KT-13364`](https://youtrack.jetbrains.com/issue/KT-13364) Do not suggest creating annotations/enum classes for unresolved type parameter bounds - [`KT-12627`](https://youtrack.jetbrains.com/issue/KT-12627) Allow warnings suppression for secondary constructor +- [`KT-13365`](https://youtrack.jetbrains.com/issue/KT-13365) Disable "Create property" (non-abstract) in interfaces. Make "Create function" (non-abstract) generate function body in interfaces ##### New features 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 629745e58e9..41485291253 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 @@ -447,6 +447,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { if (containingElement is KtClass && containingElement.isInterface()) "" else "abstract " } else if (containingElement is KtClassOrObject + && !(containingElement is KtClass && containingElement.isInterface()) && containingElement.isAncestor(config.originalElement) && callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR) "private " else "" @@ -454,7 +455,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { val declaration: KtNamedDeclaration = when (callableInfo.kind) { CallableKind.FUNCTION, CallableKind.SECONDARY_CONSTRUCTOR -> { val body = when { - containingElement is KtClass && containingElement.isInterface() && !config.isExtension -> "" callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR -> "" callableInfo.isAbstract -> "" else -> "{}" 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 b6b0041d1dd..fcbc9fa4220 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 @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.* import org.jetbrains.kotlin.idea.refactoring.canRefactor import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers +import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.psi.* @@ -183,7 +184,23 @@ sealed class CreateCallableFromCallActionFactory( return PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers) } - object Default : Property() + object Default : Property() { + override fun doCreateCallableInfo( + expression: KtSimpleNameExpression, + context: BindingContext, + name: String, + receiverType: TypeInfo, + possibleContainers: List + ): CallableInfo? { + return super.doCreateCallableInfo( + expression, + context, + name, + receiverType, + possibleContainers.filterNot { it is KtClassBody && (it.parent as KtClassOrObject).isInterfaceClass() } + ) + } + } object Abstract : Property() { override fun doCreateCallableInfo( 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 c1c06e2de0f..e7bc42a4622 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 @@ -141,7 +141,10 @@ abstract class CreateCallableFromUsageFixBase( val receiverInfo = callableInfos.first().receiverTypeInfo - if (receiverInfo is TypeInfo.Empty) return !isExtension + if (receiverInfo is TypeInfo.Empty) { + if (callableInfos.any { it is PropertyInfo && it.possibleContainers.isEmpty() }) return false + return !isExtension + } // TODO: Remove after companion object extensions are supported if (isExtension && receiverInfo.staticContextRequired) return false @@ -158,6 +161,7 @@ abstract class CreateCallableFromUsageFixBase( isFunction && insertToJavaInterface && receiverInfo.staticContextRequired -> false !isExtension && declaration is KtTypeParameter -> false + propertyInfo != null && !propertyInfo.isAbstract && declaration is KtClass && declaration.isInterface() -> false else -> declaration != null } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/funOnTrait.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/funOnTrait.kt.after index fdc65eae7ba..289010a1406 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/funOnTrait.kt.after +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/funOnTrait.kt.after @@ -1,7 +1,9 @@ // "Create member function 'T.foo'" "true" interface T { - fun foo(s: String, i: Int): Boolean + fun foo(s: String, i: Int): Boolean { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } fun test(t: T) { diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt index bf57538add6..bc4a2a14908 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/inAccessorInTrait.kt @@ -1,7 +1,6 @@ // "Create parameter 'foo'" "false" // 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/nonAbstractInInterface.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/nonAbstractInInterface.kt new file mode 100644 index 00000000000..0aa4bcd247c --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/nonAbstractInInterface.kt @@ -0,0 +1,11 @@ +// "Create property 'foo'" "false" +// ACTION: Create abstract property 'foo' +// ACTION: Create local variable 'foo' +// ACTION: Create object 'foo' +// ACTION: Create parameter 'foo' +// ACTION: Rename reference +// ERROR: Unresolved reference: foo + +interface IF1 { + fun af2() = foo +} \ 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 3e85fae5652..7545722a5e9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3564,6 +3564,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("nonAbstractInInterface.kt") + public void testNonAbstractInInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/nonAbstractInInterface.kt"); + doTest(fileName); + } + @TestMetadata("objectMemberValNoReceiver.kt") public void testObjectMemberValNoReceiver() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/objectMemberValNoReceiver.kt");