Create from Usage: Place extension properties after the usage and generate stub getter

#KT-11795 Fixed
This commit is contained in:
Alexey Sedunov
2016-08-18 16:10:17 +03:00
parent 99ba340236
commit c2b38cfa41
23 changed files with 92 additions and 58 deletions
+1
View File
@@ -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-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-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-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 ##### New features
@@ -498,8 +498,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
} }
} }
CallableKind.PROPERTY -> { CallableKind.PROPERTY -> {
val valVar = if ((callableInfo as PropertyInfo).writable) "var" else "val" val isVar = (callableInfo as PropertyInfo).writable
psiFactory.createProperty("$modifiers$valVar<> $header") 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 containingElement is KtFile -> containingElement.add(declaration) as KtNamedDeclaration
@@ -683,18 +693,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
return typeRefsToShorten return typeRefsToShorten
} }
private fun setupFunctionBody(func: KtFunction) { private fun setupDeclarationBody(func: KtDeclarationWithBody) {
val oldBody = func.bodyExpression ?: return val oldBody = func.bodyExpression ?: return
val templateKind = when (func) { val templateKind = when (func) {
is KtSecondaryConstructor -> TemplateKind.SECONDARY_CONSTRUCTOR is KtSecondaryConstructor -> TemplateKind.SECONDARY_CONSTRUCTOR
is KtNamedFunction -> TemplateKind.FUNCTION is KtNamedFunction, is KtPropertyAccessor -> TemplateKind.FUNCTION
else -> throw AssertionError("Unexpected declaration: " + func.getElementTextWithContext()) else -> throw AssertionError("Unexpected declaration: " + func.getElementTextWithContext())
} }
val bodyText = getFunctionBodyTextFromTemplate( val bodyText = getFunctionBodyTextFromTemplate(
func.project, func.project,
templateKind, templateKind,
if (callableInfo.name.isNotEmpty()) callableInfo.name else null, 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) } receiverClassDescriptor?.importableFqName ?: receiverClassDescriptor?.name?.let { FqName.topLevel(it) }
) )
oldBody.replace(KtPsiFactory(func).createBlock(bodyText)) oldBody.replace(KtPsiFactory(func).createBlock(bodyText))
@@ -988,7 +998,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
runWriteAction { runWriteAction {
// file templates // file templates
if (newDeclaration is KtNamedFunction || newDeclaration is KtSecondaryConstructor) { 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 val callElement = config.originalElement as? KtCallElement
@@ -1,5 +1,4 @@
// "Create extension property 'A.foo'" "true" // "Create extension property 'A.foo'" "true"
// ERROR: Property must be initialized
class A(val n: Int) class A(val n: Int)
class B { class B {
@@ -1,9 +1,11 @@
// "Create extension property 'A.foo'" "true" // "Create extension property 'A.foo'" "true"
// ERROR: Property must be initialized
class A(val n: Int) class A(val n: Int)
private val A.foo: Boolean
class B { class B {
val A.test: Boolean get() = foo val A.test: Boolean get() = foo
} }
private val A.foo: Boolean
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,5 +1,4 @@
// "Create extension property 'A.foo'" "true" // "Create extension property 'A.foo'" "true"
// ERROR: Property must be initialized
class A(val n: Int) class A(val n: Int)
class B { class B {
@@ -1,9 +1,6 @@
// "Create extension property 'A.foo'" "true" // "Create extension property 'A.foo'" "true"
// ERROR: Property must be initialized
class A(val n: Int) class A(val n: Int)
private var A.foo: Boolean
class B { class B {
var A.test: Boolean var A.test: Boolean
get() = foo get() = foo
@@ -11,3 +8,10 @@ class B {
foo = v foo = v
} }
} }
private var A.foo: Boolean
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
set() {
}
@@ -3,11 +3,14 @@
import package1.A import package1.A
private val package2.A.foo: Any<caret>
class X { class X {
init { init {
val y = package2.A() val y = package2.A()
val foo = y.foo val foo = y.foo
} }
} }
private val package2.A.foo: Any
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,8 +1,11 @@
// "Create extension property 'A.foo'" "true" // "Create extension property 'A.foo'" "true"
// ERROR: Unresolved reference: foo // ERROR: Unresolved reference: foo
private val A.foo: String?<caret>
fun test(): String? { fun test(): String? {
return A().foo return A().foo
} }
private val A.foo: String?
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,8 +1,11 @@
// "Create extension property 'A.foo'" "true" // "Create extension property 'A.foo'" "true"
// ERROR: Unresolved reference: foo // ERROR: Unresolved reference: foo
private val A.foo: String?<caret>
fun test(): String? { fun test(): String? {
return A().foo return A().foo
} }
private val A.foo: String?
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,5 +1,4 @@
// "Create extension property 'T.bar'" "true" // "Create extension property 'T.bar'" "true"
// ERROR: Property must be initialized
fun consume(n: Int) {} fun consume(n: Int) {}
fun <T> foo(t: T) { fun <T> foo(t: T) {
@@ -1,9 +1,11 @@
// "Create extension property 'T.bar'" "true" // "Create extension property 'T.bar'" "true"
// ERROR: Property must be initialized
fun consume(n: Int) {} fun consume(n: Int) {}
private val <T> T.bar: Int
fun <T> foo(t: T) { fun <T> foo(t: T) {
consume(t.bar) consume(t.bar)
} }
private val <T> T.bar: Int
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -3,8 +3,8 @@ import kotlin.properties.ReadOnlyProperty
// "Create property 'foo'" "true" // "Create property 'foo'" "true"
// ERROR: Property must be initialized // ERROR: Property must be initialized
val foo: ReadOnlyProperty<Nothing?, Int>
fun test() { fun test() {
val x: Int by foo val x: Int by foo
} }
val foo: ReadOnlyProperty<Nothing?, Int>
@@ -1,7 +1,7 @@
val `!u00A0`: Int
// "Create property '!u00A0'" "true" // "Create property '!u00A0'" "true"
// ERROR: Property must be initialized // ERROR: Property must be initialized
fun test() { fun test() {
val t: Int = `!u00A0` val t: Int = `!u00A0`
} }
val `!u00A0`: Int
@@ -2,8 +2,8 @@
// ERROR: Property must be initialized // ERROR: Property must be initialized
class Cyclic<E : Cyclic<E>> class Cyclic<E : Cyclic<E>>
val foo: Cyclic<*>
fun test() { fun test() {
val c : Cyclic<*> = foo val c : Cyclic<*> = foo
} }
val foo: Cyclic<*>
@@ -1,8 +1,8 @@
// "Create property 'foo'" "true" // "Create property 'foo'" "true"
// ERROR: Property must be initialized // ERROR: Property must be initialized
val foo: String
fun test() { fun test() {
println("a = $foo") println("a = $foo")
} }
val foo: String
@@ -1,8 +1,8 @@
// "Create property 'foo'" "true" // "Create property 'foo'" "true"
// ERROR: Property must be initialized // ERROR: Property must be initialized
val foo: Int
fun test(): Int { fun test(): Int {
return foo return foo
} }
val foo: Int
@@ -3,8 +3,8 @@
package foo package foo
val foo: Int
fun test(): Int { fun test(): Int {
return foo return foo
} }
val foo: Int
@@ -1,5 +1,4 @@
// "Create extension property 'Unit.foo'" "true" // "Create extension property 'Unit.foo'" "true"
// ERROR: Property must be initialized
// WITH_RUNTIME // WITH_RUNTIME
fun test() { fun test() {
@@ -1,9 +1,11 @@
// "Create extension property 'Unit.foo'" "true" // "Create extension property 'Unit.foo'" "true"
// ERROR: Property must be initialized
// WITH_RUNTIME // WITH_RUNTIME
private val Unit.foo: Int
fun test() { fun test() {
val a: Int = Unit.foo 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.
}
@@ -1,5 +1,4 @@
// "Create extension property 'Int.foo'" "true" // "Create extension property 'Int.foo'" "true"
// ERROR: Property must be initialized
// WITH_RUNTIME // WITH_RUNTIME
class A<T>(val n: T) class A<T>(val n: T)
@@ -1,11 +1,13 @@
// "Create extension property 'Int.foo'" "true" // "Create extension property 'Int.foo'" "true"
// ERROR: Property must be initialized
// WITH_RUNTIME // WITH_RUNTIME
class A<T>(val n: T) class A<T>(val n: T)
private val Int.foo: A<Int>
fun test() { fun test() {
val a: A<Int> = 2.foo val a: A<Int> = 2.foo
} }
private val Int.foo: A<Int>
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,5 +1,4 @@
// "Create extension property 'Int.foo'" "true" // "Create extension property 'Int.foo'" "true"
// ERROR: Property must be initialized
// WITH_RUNTIME // WITH_RUNTIME
class A<T>(val n: T) class A<T>(val n: T)
@@ -1,11 +1,15 @@
// "Create extension property 'Int.foo'" "true" // "Create extension property 'Int.foo'" "true"
// ERROR: Property must be initialized
// WITH_RUNTIME // WITH_RUNTIME
class A<T>(val n: T) class A<T>(val n: T)
private var Int.foo: A<String>
fun test() { fun test() {
2.foo = A("2") 2.foo = A("2")
} }
private var Int.foo: A<String>
get() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
set() {
}