Supported "lastOrNull" and "any" without break in the loop

This commit is contained in:
Valentin Kipyatkov
2016-04-06 11:26:02 +03:00
parent 0243efd8b5
commit c0f3ab59ab
7 changed files with 46 additions and 7 deletions
@@ -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)
@@ -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)
@@ -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"
@@ -0,0 +1,9 @@
// WITH_RUNTIME
fun foo(list: List<String>) {
var found = false
<caret>for (s in list) {
if (s.length > 0) {
found = true
}
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo(list: List<String>) {
<caret>val found = list.any { it.length > 0 }
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
fun foo(list: List<String>) {
var result: String? = null
<caret>for (s in list) {
if (s.length > 0) {
result = s
}
}
}
@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo(list: List<String>) {
<caret>val result: String? = list.lastOrNull { it.length > 0 }
}