Extract Function: Generate function in property's enclosing declaration if original expression belongs to initializer of that property

#KT-6290 Fixed
This commit is contained in:
Alexey Sedunov
2014-12-26 11:53:44 +03:00
parent 22f4caa78d
commit 59d646bc16
10 changed files with 50 additions and 29 deletions
@@ -73,6 +73,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import com.intellij.psi.PsiPackage import com.intellij.psi.PsiPackage
import org.jetbrains.jet.plugin.util.ProjectRootsUtil import org.jetbrains.jet.plugin.util.ProjectRootsUtil
import org.jetbrains.kotlin.psi.psiUtil.parents
fun <T: Any> PsiElement.getAndRemoveCopyableUserData(key: Key<T>): T? { fun <T: Any> PsiElement.getAndRemoveCopyableUserData(key: Key<T>): T? {
val data = getCopyableUserData(key) val data = getCopyableUserData(key)
@@ -137,27 +138,27 @@ public fun PsiElement.getAllExtractionContainers(strict: Boolean = true): List<J
} }
public fun PsiElement.getExtractionContainers(strict: Boolean = true, includeAll: Boolean = false): List<JetElement> { public fun PsiElement.getExtractionContainers(strict: Boolean = true, includeAll: Boolean = false): List<JetElement> {
fun getEnclosingDeclaration(element: PsiElement, strict: Boolean): PsiElement? {
return element.parents(!strict)
.filter {
(it is JetDeclarationWithBody && it !is JetFunctionLiteral)
|| it is JetClassInitializer
|| it is JetClassBody
|| it is JetFile
}
.firstOrNull()
}
if (includeAll) return getAllExtractionContainers(strict) if (includeAll) return getAllExtractionContainers(strict)
val declaration = getParentOfType<JetDeclaration>(strict)?.let { declaration -> val enclosingDeclaration = getEnclosingDeclaration(this, strict)?.let {
stream(declaration) { it.getStrictParentOfType<JetDeclaration>() }.firstOrNull { it !is JetFunctionLiteral } if (it is JetDeclarationWithBody || it is JetClassInitializer) getEnclosingDeclaration(it, true) else it
} ?: return Collections.emptyList()
val parent = declaration.getParent()?.let {
when (it) {
is JetProperty, is JetMultiDeclaration -> it.getParent()
is JetParameterList -> it.getParent()?.getParent()
else -> it
}
} }
return when (parent) {
is JetFile -> Collections.singletonList(parent) return when (enclosingDeclaration) {
is JetClassBody -> { is JetFile -> Collections.singletonList(enclosingDeclaration)
getAllExtractionContainers(strict).filterIsInstance<JetClassBody>() is JetClassBody -> getAllExtractionContainers(strict).filterIsInstance<JetClassBody>()
}
else -> { else -> {
val enclosingDeclaration =
PsiTreeUtil.getNonStrictParentOfType(parent, javaClass<JetDeclarationWithBody>(), javaClass<JetClassInitializer>())
val targetContainer = when (enclosingDeclaration) { val targetContainer = when (enclosingDeclaration) {
is JetDeclarationWithBody -> enclosingDeclaration.getBodyExpression() is JetDeclarationWithBody -> enclosingDeclaration.getBodyExpression()
is JetClassInitializer -> enclosingDeclaration.getBody() is JetClassInitializer -> enclosingDeclaration.getBody()
@@ -3,6 +3,7 @@
// ACTION: Create class 'SomeTest' // ACTION: Create class 'SomeTest'
// ACTION: Create enum 'SomeTest' // ACTION: Create enum 'SomeTest'
// ACTION: Create object 'SomeTest' // ACTION: Create object 'SomeTest'
// ACTION: Create property 'SomeTest'
// ACTION: Create trait 'SomeTest' // ACTION: Create trait 'SomeTest'
// ERROR: Unresolved reference: SomeTest // ERROR: Unresolved reference: SomeTest
@@ -2,6 +2,7 @@
// ACTION: Create class 'A' // ACTION: Create class 'A'
// ACTION: Create trait 'A' // ACTION: Create trait 'A'
// ACTION: Create object 'A' // ACTION: Create object 'A'
// ACTION: Create property 'A'
// ACTION: Create enum 'A' // ACTION: Create enum 'A'
// ACTION: Create annotation 'A' // ACTION: Create annotation 'A'
// ERROR: Unresolved reference: A // ERROR: Unresolved reference: A
@@ -2,6 +2,7 @@
// ACTION: Create class 'A' // ACTION: Create class 'A'
// ACTION: Create trait 'A' // ACTION: Create trait 'A'
// ACTION: Create object 'A' // ACTION: Create object 'A'
// ACTION: Create property 'A'
// ACTION: Create enum 'A' // ACTION: Create enum 'A'
// ACTION: Create annotation 'A' // ACTION: Create annotation 'A'
// ERROR: Unresolved reference: A // ERROR: Unresolved reference: A
@@ -1,5 +1,6 @@
// "Create parameter 'foo'" "false" // "Create parameter 'foo'" "false"
// ACTION: Create local variable 'foo' // ACTION: Create local variable 'foo'
// ACTION: Create property 'foo'
// ACTION: Split property declaration // ACTION: Split property declaration
// ERROR: Unresolved reference: foo // ERROR: Unresolved reference: foo
@@ -1,8 +1,8 @@
fun foo() { fun foo() {
fun i(): Int {
return 1 + 1
}
val x = i() val x = i()
val y = i() val y = i()
}
private fun i(): Int {
return 1 + 1
} }
@@ -1,3 +1,7 @@
// PARAM_TYPES: kotlin.Int
// PARAM_TYPES: kotlin.Int
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in bar
// PARAM_DESCRIPTOR: value-parameter val b: kotlin.Int defined in bar
fun bar(a: Int, b: Int) { fun bar(a: Int, b: Int) {
val foo = <selection>a + b</selection> - 1 val foo = <selection>a + b</selection> - 1
} }
@@ -1,7 +1,11 @@
// PARAM_TYPES: kotlin.Int
// PARAM_TYPES: kotlin.Int
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in bar
// PARAM_DESCRIPTOR: value-parameter val b: kotlin.Int defined in bar
fun bar(a: Int, b: Int) { fun bar(a: Int, b: Int) {
fun i(): Int { val foo = i(a, b) - 1
return a + b }
}
val foo = i() - 1 private fun i(a: Int, b: Int): Int {
return a + b
} }
@@ -1,3 +1,7 @@
// PARAM_TYPES: kotlin.Int
// PARAM_TYPES: kotlin.Int
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in bar
// PARAM_DESCRIPTOR: value-parameter val b: kotlin.Int defined in bar
fun bar(a: Int, b: Int) { fun bar(a: Int, b: Int) {
val foo = { <selection>a + b</selection> - 1 }.invoke() val foo = { <selection>a + b</selection> - 1 }.invoke()
} }
@@ -1,7 +1,11 @@
// PARAM_TYPES: kotlin.Int
// PARAM_TYPES: kotlin.Int
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in bar
// PARAM_DESCRIPTOR: value-parameter val b: kotlin.Int defined in bar
fun bar(a: Int, b: Int) { fun bar(a: Int, b: Int) {
fun i(): Int { val foo = { i(a, b) - 1 }.invoke()
return a + b }
}
val foo = { i() - 1 }.invoke() private fun i(a: Int, b: Int): Int {
return a + b
} }