From c0f3ab59abe99005348b4e81545c71e7b11ff6be Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 6 Apr 2016 11:26:02 +0300 Subject: [PATCH] Supported "lastOrNull" and "any" without break in the loop --- .../result/FindAndAssignTransformation.kt | 21 +++++++++++++++---- .../result/FindAndReturnTransformation.kt | 2 +- .../idea/intentions/loopToCallChain/utils.kt | 4 ++-- .../loopToCallChain/any_ifAssign_noBreak.kt | 9 ++++++++ .../any_ifAssign_noBreak.kt.after | 4 ++++ .../loopToCallChain/lastOrNull_ifAssign.kt | 9 ++++++++ .../lastOrNull_ifAssign.kt.after | 4 ++++ 7 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt create mode 100644 idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt.after create mode 100644 idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt create mode 100644 idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndAssignTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndAssignTransformation.kt index 6c2f1395142..2e877427d17 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndAssignTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndAssignTransformation.kt @@ -70,16 +70,29 @@ class FindAndAssignTransformation( * variable = ... * break * } + * or + * val variable = ... + * for (...) { + * ... + * variable = ... + * } */ object Matcher : ResultTransformationMatcher { override fun match(state: MatchingState): ResultTransformationMatch? { //TODO: pass indexVariable as null if not used if (state.indexVariable != null) return null - if (state.statements.size != 2) return null + when (state.statements.size) { + 1 -> {} - val breakExpression = state.statements.last() as? KtBreakExpression ?: return null - if (!breakExpression.isBreakOrContinueOfLoop(state.outerLoop)) return null + 2 -> { + val breakExpression = state.statements.last() as? KtBreakExpression ?: return null + if (!breakExpression.isBreakOrContinueOfLoop(state.outerLoop)) return null + } + + else -> return null + } + val findFirst = state.statements.size == 2 val binaryExpression = state.statements.first() as? KtBinaryExpression ?: return null if (binaryExpression.operationToken != KtTokens.EQ) return null @@ -94,7 +107,7 @@ class FindAndAssignTransformation( val usageCountInLoop = ReferencesSearch.search(declarationBeforeLoop, LocalSearchScope(state.outerLoop)).count() if (usageCountInLoop != 1) return null // this should be the only usage of this variable inside the loop - val stdlibFunName = stdlibFunNameForFind(right, initializer, state.workingVariable) ?: return null + val stdlibFunName = stdlibFunNameForFind(right, initializer, state.workingVariable, findFirst) ?: return null val transformation = FindAndAssignTransformation(state.outerLoop, state.workingVariable, stdlibFunName, declarationBeforeLoop) return ResultTransformationMatch(transformation) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndReturnTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndReturnTransformation.kt index f0a739bee37..d88008d2e80 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndReturnTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindAndReturnTransformation.kt @@ -78,7 +78,7 @@ class FindAndReturnTransformation( val returnValueInLoop = returnInLoop.returnedExpression ?: return null val returnValueAfterLoop = returnAfterLoop.returnedExpression ?: return null - val stdlibFunName = stdlibFunNameForFind(returnValueInLoop, returnValueAfterLoop, state.workingVariable) ?: return null + val stdlibFunName = stdlibFunNameForFind(returnValueInLoop, returnValueAfterLoop, state.workingVariable, findFirst = true) ?: return null val transformation = FindAndReturnTransformation(state.outerLoop, state.workingVariable, stdlibFunName, returnAfterLoop) return ResultTransformationMatch(transformation) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt index 13d96da85f4..cc502fe90c4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt @@ -95,9 +95,9 @@ fun KtProperty.hasWriteUsages(): Boolean { } } -fun stdlibFunNameForFind(valueIfFound: KtExpression, valueIfNotFound: KtExpression, workingVariable: KtCallableDeclaration): String? { +fun stdlibFunNameForFind(valueIfFound: KtExpression, valueIfNotFound: KtExpression, workingVariable: KtCallableDeclaration, findFirst: Boolean): String? { return when { - valueIfNotFound.isNullExpression() && valueIfFound.isVariableReference(workingVariable) -> "firstOrNull" + valueIfNotFound.isNullExpression() && valueIfFound.isVariableReference(workingVariable) -> if (findFirst) "firstOrNull" else "lastOrNull" valueIfFound.isTrueConstant() && valueIfNotFound.isFalseConstant() -> "any" diff --git a/idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt b/idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt new file mode 100644 index 00000000000..b284ea5dcf1 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +fun foo(list: List) { + var found = false + for (s in list) { + if (s.length > 0) { + found = true + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt.after b/idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt.after new file mode 100644 index 00000000000..fd09759adb2 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/any_ifAssign_noBreak.kt.after @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun foo(list: List) { + val found = list.any { it.length > 0 } +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt b/idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt new file mode 100644 index 00000000000..9aade7bcfc2 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +fun foo(list: List) { + var result: String? = null + for (s in list) { + if (s.length > 0) { + result = s + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt.after b/idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt.after new file mode 100644 index 00000000000..0e830fecfa2 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/lastOrNull_ifAssign.kt.after @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun foo(list: List) { + val result: String? = list.lastOrNull { it.length > 0 } +} \ No newline at end of file