From c2b38cfa41a67b929b00c4d110069e1315a96ab6 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 18 Aug 2016 16:10:17 +0300 Subject: [PATCH] Create from Usage: Place extension properties after the usage and generate stub getter #KT-11795 Fixed --- ChangeLog.md | 1 + .../callableBuilder/CallableBuilder.kt | 28 ++++++++++++++----- .../extensionPropertyGetter.kt | 1 - .../extensionPropertyGetter.kt.after | 10 ++++--- .../extensionPropertySetter.kt | 1 - .../extensionPropertySetter.kt.after | 12 +++++--- ...nPropertyOnTypeFromAnotherPackage.after.kt | 9 ++++-- .../extensionValOnGroovyType.after.kt | 9 ++++-- .../property/extensionValOnJavaType.after.kt | 9 ++++-- .../extensionWithTypeParameterAsReceiver.kt | 1 - ...ensionWithTypeParameterAsReceiver.kt.after | 10 ++++--- .../property/localValDelegateRuntime.kt.after | 4 +-- .../property/quotedName.kt.after | 6 ++-- .../property/recursiveBound.kt.after | 6 ++-- .../refInStringTemplateRuntime.kt.after | 6 ++-- .../property/topLevelValNoReceiver.kt.after | 4 +-- .../topLevelValWithPackageName.kt.after | 4 +-- .../createVariable/property/valOnLibObject.kt | 1 - .../property/valOnLibObject.kt.after | 8 ++++-- .../createVariable/property/valOnLibType.kt | 1 - .../property/valOnLibType.kt.after | 8 ++++-- .../createVariable/property/varOnLibType.kt | 1 - .../property/varOnLibType.kt.after | 10 +++++-- 23 files changed, 92 insertions(+), 58 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 76d83eab8a7..5f0194ff2bc 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -221,6 +221,7 @@ These artifacts include extensions for the types available in the latter JDKs, s - [`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 - [`KT-8903`](https://youtrack.jetbrains.com/issue/KT-8903) Remove Unused Receiver: update function/property usages - [`KT-11799`](https://youtrack.jetbrains.com/issue/KT-11799) Create from Usage: Make extension functions/properties 'private' by default +- [`KT-11795`](https://youtrack.jetbrains.com/issue/KT-11795) Create from Usage: Place extension properties after the usage and generate stub getter ##### 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 ae68007e69d..29eb994da67 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 @@ -498,8 +498,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { } } CallableKind.PROPERTY -> { - val valVar = if ((callableInfo as PropertyInfo).writable) "var" else "val" - psiFactory.createProperty("$modifiers$valVar<> $header") + val isVar = (callableInfo as PropertyInfo).writable + val valVar = if (isVar) "var" else "val" + val accessors = if (isExtension) { + buildString { + append("\nget() {}") + if (isVar) { + append("\nset() {}") + } + } + } + else "" + psiFactory.createProperty("$modifiers$valVar<> $header$accessors") } } @@ -559,7 +569,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { } } } - addNextToOriginalElementContainer(insertToBlock || declaration is KtProperty) + addNextToOriginalElementContainer(insertToBlock || (declaration is KtProperty && actualContainer !is KtFile)) } containingElement is KtFile -> containingElement.add(declaration) as KtNamedDeclaration @@ -683,18 +693,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { return typeRefsToShorten } - private fun setupFunctionBody(func: KtFunction) { + private fun setupDeclarationBody(func: KtDeclarationWithBody) { val oldBody = func.bodyExpression ?: return val templateKind = when (func) { is KtSecondaryConstructor -> TemplateKind.SECONDARY_CONSTRUCTOR - is KtNamedFunction -> TemplateKind.FUNCTION + is KtNamedFunction, is KtPropertyAccessor -> TemplateKind.FUNCTION else -> throw AssertionError("Unexpected declaration: " + func.getElementTextWithContext()) } val bodyText = getFunctionBodyTextFromTemplate( func.project, templateKind, if (callableInfo.name.isNotEmpty()) callableInfo.name else null, - if (skipReturnType) "Unit" else func.typeReference!!.text, + if (skipReturnType) "Unit" else (func as? KtFunction)?.typeReference?.text ?: "", receiverClassDescriptor?.importableFqName ?: receiverClassDescriptor?.name?.let { FqName.topLevel(it) } ) oldBody.replace(KtPsiFactory(func).createBlock(bodyText)) @@ -988,7 +998,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { runWriteAction { // file templates if (newDeclaration is KtNamedFunction || newDeclaration is KtSecondaryConstructor) { - setupFunctionBody(newDeclaration as KtFunction) + setupDeclarationBody(newDeclaration as KtFunction) + } + + if (newDeclaration is KtProperty) { + newDeclaration.getter?.let { setupDeclarationBody(it) } } val callElement = config.originalElement as? KtCallElement diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt index c9d035b74cf..c269476fb07 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt @@ -1,5 +1,4 @@ // "Create extension property 'A.foo'" "true" -// ERROR: Property must be initialized class A(val n: Int) class B { diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt.after index 7e65cdb046c..5336b32f9c6 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt.after +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertyGetter.kt.after @@ -1,9 +1,11 @@ // "Create extension property 'A.foo'" "true" -// ERROR: Property must be initialized class A(val n: Int) -private val A.foo: Boolean - class B { val A.test: Boolean get() = foo -} \ No newline at end of file +} + +private val A.foo: Boolean + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt index cd8f4570fae..25106ea5584 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt @@ -1,5 +1,4 @@ // "Create extension property 'A.foo'" "true" -// ERROR: Property must be initialized class A(val n: Int) class B { diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt.after index 29a8aae4f52..8adafd4b29b 100644 --- a/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt.after +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/extensionByExtensionReceiver/extensionPropertySetter.kt.after @@ -1,13 +1,17 @@ // "Create extension property 'A.foo'" "true" -// ERROR: Property must be initialized class A(val n: Int) -private var A.foo: Boolean - class B { var A.test: Boolean get() = foo set(v: Boolean) { foo = v } -} \ No newline at end of file +} + +private var A.foo: Boolean + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + set() { + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionPropertyOnTypeFromAnotherPackage.after.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionPropertyOnTypeFromAnotherPackage.after.kt index 81c4f7c8178..0718febb5ad 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionPropertyOnTypeFromAnotherPackage.after.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionPropertyOnTypeFromAnotherPackage.after.kt @@ -3,11 +3,14 @@ import package1.A -private val package2.A.foo: Any - class X { init { val y = package2.A() val foo = y.foo } -} \ No newline at end of file +} + +private val package2.A.foo: Any + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt index e85515fbe7d..2ffb6dc1943 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt @@ -1,8 +1,11 @@ // "Create extension property 'A.foo'" "true" // ERROR: Unresolved reference: foo -private val A.foo: String? - fun test(): String? { return A().foo -} \ No newline at end of file +} + +private val A.foo: String? + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt index e85515fbe7d..2ffb6dc1943 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt @@ -1,8 +1,11 @@ // "Create extension property 'A.foo'" "true" // ERROR: Unresolved reference: foo -private val A.foo: String? - fun test(): String? { return A().foo -} \ No newline at end of file +} + +private val A.foo: String? + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt index a300a34ee60..8baf0155d1f 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt @@ -1,5 +1,4 @@ // "Create extension property 'T.bar'" "true" -// ERROR: Property must be initialized fun consume(n: Int) {} fun foo(t: T) { diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after index 3ebe6069c25..d0acf69c8ca 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionWithTypeParameterAsReceiver.kt.after @@ -1,9 +1,11 @@ // "Create extension property 'T.bar'" "true" -// ERROR: Property must be initialized fun consume(n: Int) {} -private val T.bar: Int - fun foo(t: T) { consume(t.bar) -} \ No newline at end of file +} + +private val T.bar: Int + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/localValDelegateRuntime.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/localValDelegateRuntime.kt.after index 96b0cdae1e9..bd0e3519c64 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/localValDelegateRuntime.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/localValDelegateRuntime.kt.after @@ -3,8 +3,8 @@ import kotlin.properties.ReadOnlyProperty // "Create property 'foo'" "true" // ERROR: Property must be initialized -val foo: ReadOnlyProperty - fun test() { val x: Int by foo } + +val foo: ReadOnlyProperty diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/quotedName.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/quotedName.kt.after index 905369c5fe6..91aa8fdba0e 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/quotedName.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/quotedName.kt.after @@ -1,7 +1,7 @@ -val `!u00A0`: Int - // "Create property '!u00A0'" "true" // ERROR: Property must be initialized fun test() { val t: Int = `!u00A0` -} \ No newline at end of file +} + +val `!u00A0`: Int diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/recursiveBound.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/recursiveBound.kt.after index b129959307c..134e9c4f2ad 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/recursiveBound.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/recursiveBound.kt.after @@ -2,8 +2,8 @@ // ERROR: Property must be initialized class Cyclic> -val foo: Cyclic<*> - fun test() { val c : Cyclic<*> = foo -} \ No newline at end of file +} + +val foo: Cyclic<*> diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/refInStringTemplateRuntime.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/refInStringTemplateRuntime.kt.after index d339ab9ba6b..1158b7fcb98 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/refInStringTemplateRuntime.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/refInStringTemplateRuntime.kt.after @@ -1,8 +1,8 @@ // "Create property 'foo'" "true" // ERROR: Property must be initialized -val foo: String - fun test() { println("a = $foo") -} \ No newline at end of file +} + +val foo: String diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValNoReceiver.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValNoReceiver.kt.after index 3248ce2cf73..6c67f61adda 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValNoReceiver.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValNoReceiver.kt.after @@ -1,8 +1,8 @@ // "Create property 'foo'" "true" // ERROR: Property must be initialized -val foo: Int - fun test(): Int { return foo } + +val foo: Int diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValWithPackageName.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValWithPackageName.kt.after index 879ff8eaf38..544eab913e5 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValWithPackageName.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/topLevelValWithPackageName.kt.after @@ -3,8 +3,8 @@ package foo -val foo: Int - fun test(): Int { return foo } + +val foo: Int diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt index fc83f172231..29cf527cd1f 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt @@ -1,5 +1,4 @@ // "Create extension property 'Unit.foo'" "true" -// ERROR: Property must be initialized // WITH_RUNTIME fun test() { diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt.after index 4455d8b42c5..01f6d0bcbd8 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibObject.kt.after @@ -1,9 +1,11 @@ // "Create extension property 'Unit.foo'" "true" -// ERROR: Property must be initialized // WITH_RUNTIME -private val Unit.foo: Int - fun test() { val a: Int = Unit.foo } + +private val Unit.foo: Int + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt index 8670748af68..543f1bfb09d 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt @@ -1,5 +1,4 @@ // "Create extension property 'Int.foo'" "true" -// ERROR: Property must be initialized // WITH_RUNTIME class A(val n: T) diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt.after index 6fe0ccaa760..557d8860a54 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/valOnLibType.kt.after @@ -1,11 +1,13 @@ // "Create extension property 'Int.foo'" "true" -// ERROR: Property must be initialized // WITH_RUNTIME class A(val n: T) -private val Int.foo: A - fun test() { val a: A = 2.foo } + +private val Int.foo: A + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt index 0687308293f..cd0fe411f5e 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt @@ -1,5 +1,4 @@ // "Create extension property 'Int.foo'" "true" -// ERROR: Property must be initialized // WITH_RUNTIME class A(val n: T) diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt.after b/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt.after index 1337a64050c..eda768af149 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt.after +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/varOnLibType.kt.after @@ -1,11 +1,15 @@ // "Create extension property 'Int.foo'" "true" -// ERROR: Property must be initialized // WITH_RUNTIME class A(val n: T) -private var Int.foo: A - fun test() { 2.foo = A("2") } + +private var Int.foo: A + get() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + set() { + }