diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java index 804d7234e3c..a6c14859d77 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java @@ -600,21 +600,6 @@ public class JetPsiUtil { ((JetBinaryExpression) element).getOperationToken().equals(JetTokens.EQ); } - @Nullable - public static JetElement getOutermostLastBlockElement(@Nullable JetElement element, @NotNull Predicate checkElement) { - if (element == null) return null; - - if (!(element instanceof JetBlockExpression)) return checkElement.apply(element) ? element : null; - - JetBlockExpression block = (JetBlockExpression)element; - int n = block.getStatements().size(); - - if (n == 0) return null; - - JetElement lastElement = block.getStatements().get(n - 1); - return checkElement.apply(lastElement) ? lastElement : null; - } - public static boolean checkVariableDeclarationInBlock(@NotNull JetBlockExpression block, @NotNull String varName) { for (JetElement element : block.getStatements()) { if (element instanceof JetVariableDeclaration) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt index 58d4ab3bd23..66069e20a19 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt @@ -44,6 +44,7 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.stubs.StubElement import org.jetbrains.kotlin.JetNodeTypes import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? { val calleeExpression = getCalleeExpression() ?: return null @@ -135,8 +136,11 @@ public fun T.copied(): T = copy() as T public fun JetElement.blockExpressionsOrSingle(): Sequence = if (this is JetBlockExpression) getStatements().asSequence() else sequenceOf(this) -public fun JetElement.outermostLastBlockElement(predicate: (JetElement) -> Boolean = { true }): JetElement? { - return JetPsiUtil.getOutermostLastBlockElement(this) { e -> e != null && predicate(e) } +public fun JetExpression.lastBlockStatementOrThis(): JetExpression { + return if (this is JetBlockExpression) + this.getStatements().lastIsInstanceOrNull() ?: this + else + this } public fun JetBlockExpression.appendElement(element: JetElement): JetElement { diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/addToStdlib.kt b/compiler/util/src/org/jetbrains/kotlin/utils/addToStdlib.kt index 58023efae68..3fbf2414204 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/addToStdlib.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/addToStdlib.kt @@ -53,6 +53,24 @@ public inline fun Array<*>.firstIsInstance(): T { throw NoSuchElementException("No element of given type found") } +public inline fun Iterable<*>.lastIsInstanceOrNull(): T? { + when (this) { + is List<*> -> { + for (i in this.indices.reversed()) { + val element = this[i] + if (element is T) return element + } + return null + } + + else -> { + return reverse().firstIsInstanceOrNull() + } + } +} + public fun streamOfLazyValues(vararg elements: () -> T): Stream = elements.stream().map { it() } -public fun Pair.swap(): Pair = Pair(second, first) \ No newline at end of file +public fun Pair.swap(): Pair = Pair(second, first) + +public fun T.check(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt index 1d56d5a08ab..2cdfc1d9f4c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedFoldingUtils.kt @@ -16,36 +16,31 @@ package org.jetbrains.kotlin.idea.intentions.branchedTransformations -import com.google.common.base.Predicate import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis +import org.jetbrains.kotlin.utils.addToStdlib.check object BranchedFoldingUtils { - private val CHECK_ASSIGNMENT = object : Predicate { - override fun apply(input: JetElement): Boolean { - if (input !is JetBinaryExpression) return false - if (input.getOperationToken() !in JetTokens.ALL_ASSIGNMENTS) return false + public fun getFoldableBranchedAssignment(branch: JetExpression?): JetBinaryExpression? { + fun checkAssignment(expression: JetBinaryExpression): Boolean { + if (expression.getOperationToken() !in JetTokens.ALL_ASSIGNMENTS) return false - val left = input.getLeft() as? JetSimpleNameExpression ?: return false - if (input.getRight() == null) return false + val left = expression.getLeft() as? JetSimpleNameExpression ?: return false + if (expression.getRight() == null) return false - val parent = input.getParent() + val parent = expression.getParent() if (parent is JetBlockExpression) { return !JetPsiUtil.checkVariableDeclarationInBlock(parent, left.getText()) } return true } - } - - public fun getFoldableBranchedAssignment(branch: JetExpression?): JetBinaryExpression? { - return JetPsiUtil.getOutermostLastBlockElement(branch, CHECK_ASSIGNMENT) as JetBinaryExpression? + return (branch?.lastBlockStatementOrThis() as? JetBinaryExpression)?.check(::checkAssignment) } public fun getFoldableBranchedReturn(branch: JetExpression?): JetReturnExpression? { - return JetPsiUtil.getOutermostLastBlockElement(branch) { - (it as? JetReturnExpression)?.getReturnedExpression() != null - } as JetReturnExpression? + return (branch?.lastBlockStatementOrThis() as? JetReturnExpression)?.check { it.getReturnedExpression() != null } } public fun checkAssignmentsMatch(a1: JetBinaryExpression, a2: JetBinaryExpression): Boolean { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedUnfoldingUtils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedUnfoldingUtils.kt index 153c25bde8b..4cf2335d551 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedUnfoldingUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/BranchedUnfoldingUtils.kt @@ -19,12 +19,9 @@ package org.jetbrains.kotlin.idea.intentions.branchedTransformations import com.intellij.openapi.editor.Editor import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.copied +import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis public object BranchedUnfoldingUtils { - public fun getOutermostLastBlockElement(expression: JetExpression?): JetExpression { - return JetPsiUtil.getOutermostLastBlockElement(expression, JetPsiUtil.ANY_JET_ELEMENT) as JetExpression - } - public fun unfoldAssignmentToIf(assignment: JetBinaryExpression, editor: Editor) { val op = assignment.getOperationReference().getText() val left = assignment.getLeft()!! @@ -32,8 +29,8 @@ public object BranchedUnfoldingUtils { val newIfExpression = ifExpression.copied() - val thenExpr = getOutermostLastBlockElement(newIfExpression.getThen()) - val elseExpr = getOutermostLastBlockElement(newIfExpression.getElse()) + val thenExpr = newIfExpression.getThen()!!.lastBlockStatementOrThis() + val elseExpr = newIfExpression.getElse()!!.lastBlockStatementOrThis() val psiFactory = JetPsiFactory(assignment) thenExpr.replace(psiFactory.createExpressionByPattern("$0 $1 $2", left, op, thenExpr)) @@ -52,7 +49,7 @@ public object BranchedUnfoldingUtils { val newWhenExpression = whenExpression.copied() for (entry in newWhenExpression.getEntries()) { - val expr = getOutermostLastBlockElement(entry.getExpression()) + val expr = entry.getExpression()!!.lastBlockStatementOrThis() expr.replace(JetPsiFactory(assignment).createExpressionByPattern("$0 $1 $2", left, op, expr)) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/MergeWhenIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/MergeWhenIntention.kt index fc9a809dc86..4ad25067611 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/MergeWhenIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/MergeWhenIntention.kt @@ -54,7 +54,7 @@ public class MergeWhenIntention : JetSelfTargetingRangeIntention false else -> true } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/UnfoldAssignmentToWhenIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/UnfoldAssignmentToWhenIntention.kt index 5f34e604afa..fa5caadd2e1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/UnfoldAssignmentToWhenIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/branchedTransformations/intentions/UnfoldAssignmentToWhenIntention.kt @@ -33,6 +33,7 @@ public class UnfoldAssignmentToWhenIntention : JetSelfTargetingRangeIntention(javaClass(), "Replace return with 'if' expression") { @@ -37,8 +34,8 @@ public class UnfoldReturnToIfIntention : JetSelfTargetingRangeIntention(javaClass(), "Replace return with 'when' expression") { override fun applicabilityRange(element: JetReturnExpression): TextRange? { val whenExpr = element.getReturnedExpression() as? JetWhenExpression ?: return null if (!JetPsiUtil.checkWhenExpressionHasSingleElse(whenExpr)) return null + if (whenExpr.getEntries().any { it.getExpression() == null }) return null return TextRange(element.startOffset, whenExpr.getWhenKeyword().endOffset) } @@ -37,8 +39,8 @@ public class UnfoldReturnToWhenIntention : JetSelfTargetingRangeIntention