Checking that input variable is really used
This commit is contained in:
@@ -51,9 +51,11 @@ interface Transformation {
|
||||
|
||||
fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression
|
||||
|
||||
|
||||
val chainCallCount: Int
|
||||
get() = 1
|
||||
|
||||
val shouldUseInputVariable: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,9 +71,17 @@ fun match(loop: KtForExpression): ResultTransformationMatch? {
|
||||
state = state.copy(statements = block.statements)
|
||||
}
|
||||
|
||||
val inputVariableUsed = state.inputVariable.hasUsages(state.statements)
|
||||
|
||||
for (matcher in MatcherRegistrar.resultMatchers) {
|
||||
val match = matcher.match(state)
|
||||
if (match != null) {
|
||||
if (!inputVariableUsed
|
||||
&& (match.sequenceTransformations.any { it.shouldUseInputVariable }
|
||||
|| match.resultTransformation.shouldUseInputVariable)) {
|
||||
return null
|
||||
}
|
||||
|
||||
sequenceTransformations.addAll(match.sequenceTransformations)
|
||||
return ResultTransformationMatch(match.resultTransformation, sequenceTransformations)
|
||||
.let { mergeTransformations(it) }
|
||||
@@ -84,6 +92,10 @@ fun match(loop: KtForExpression): ResultTransformationMatch? {
|
||||
for (matcher in MatcherRegistrar.sequenceMatchers) {
|
||||
val match = matcher.match(state)
|
||||
if (match != null) {
|
||||
if (!inputVariableUsed && match.transformations.any { it.shouldUseInputVariable }) {
|
||||
return null
|
||||
}
|
||||
|
||||
val newState = match.newState
|
||||
// check that old input variable is not needed anymore
|
||||
if (state.inputVariable != newState.inputVariable && state.inputVariable.hasUsages(newState.statements)) return null
|
||||
|
||||
+3
@@ -42,6 +42,9 @@ class CountTransformation(
|
||||
override val presentation: String
|
||||
get() = "count" + (if (filter != null) "{}" else "()")
|
||||
|
||||
override val shouldUseInputVariable: Boolean
|
||||
get() = false
|
||||
|
||||
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
|
||||
val call = if (filter != null) {
|
||||
val lambda = generateLambda(inputVariable, filter)
|
||||
|
||||
+3
@@ -46,6 +46,9 @@ class FindAndAssignTransformation(
|
||||
override val chainCallCount: Int
|
||||
get() = generator.chainCallCount
|
||||
|
||||
override val shouldUseInputVariable: Boolean
|
||||
get() = generator.shouldUseInputVariable
|
||||
|
||||
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
|
||||
return generator.generate(chainedCallGenerator, filter)
|
||||
}
|
||||
|
||||
+3
@@ -50,6 +50,9 @@ class FindAndReturnTransformation(
|
||||
override val chainCallCount: Int
|
||||
get() = generator.chainCallCount
|
||||
|
||||
override val shouldUseInputVariable: Boolean
|
||||
get() = generator.shouldUseInputVariable
|
||||
|
||||
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
|
||||
return generator.generate(chainedCallGenerator, filter)
|
||||
}
|
||||
|
||||
@@ -115,6 +115,8 @@ fun KtProperty.hasWriteUsages(): Boolean {
|
||||
interface FindOperatorGenerator {
|
||||
val functionName: String
|
||||
|
||||
val shouldUseInputVariable: Boolean
|
||||
|
||||
fun generate(chainedCallGenerator: ChainedCallGenerator, filter: KtExpression?): KtExpression
|
||||
|
||||
val chainCallCount: Int
|
||||
@@ -140,7 +142,7 @@ fun buildFindOperationGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleGenerator(override val functionName: String) : FindOperatorGenerator {
|
||||
class SimpleGenerator(override val functionName: String, override val shouldUseInputVariable: Boolean) : FindOperatorGenerator {
|
||||
override fun generate(chainedCallGenerator: ChainedCallGenerator, filter: KtExpression?): KtExpression {
|
||||
return generateChainedCall(functionName, chainedCallGenerator, filter)
|
||||
}
|
||||
@@ -164,13 +166,13 @@ fun buildFindOperationGenerator(
|
||||
|
||||
when {
|
||||
valueIfFound.isVariableReference(inputVariable) -> {
|
||||
val generator = SimpleGenerator(if (findFirst) "firstOrNull" else "lastOrNull")
|
||||
val generator = SimpleGenerator(if (findFirst) "firstOrNull" else "lastOrNull", shouldUseInputVariable = true)
|
||||
return generator.useElvisOperatorIfNeeded()
|
||||
}
|
||||
|
||||
valueIfFound.isTrueConstant() && valueIfNotFound.isFalseConstant() -> return SimpleGenerator("any")
|
||||
valueIfFound.isTrueConstant() && valueIfNotFound.isFalseConstant() -> return SimpleGenerator("any", shouldUseInputVariable = false)
|
||||
|
||||
valueIfFound.isFalseConstant() && valueIfNotFound.isTrueConstant() -> return SimpleGenerator("none")
|
||||
valueIfFound.isFalseConstant() && valueIfNotFound.isTrueConstant() -> return SimpleGenerator("none", shouldUseInputVariable = false)
|
||||
|
||||
inputVariable.hasUsages(valueIfFound) -> {
|
||||
if (!findFirst) return null // too dangerous because of side effects
|
||||
@@ -185,6 +187,9 @@ fun buildFindOperationGenerator(
|
||||
override val functionName: String
|
||||
get() = "firstOrNull"
|
||||
|
||||
override val shouldUseInputVariable: Boolean
|
||||
get() = true
|
||||
|
||||
override val chainCallCount: Int
|
||||
get() = 2
|
||||
|
||||
@@ -203,6 +208,9 @@ fun buildFindOperationGenerator(
|
||||
override val functionName: String
|
||||
get() = "firstOrNull"
|
||||
|
||||
override val shouldUseInputVariable: Boolean
|
||||
get() = true
|
||||
|
||||
override val chainCallCount: Int
|
||||
get() = 2 // also includes "let"
|
||||
|
||||
@@ -219,6 +227,9 @@ fun buildFindOperationGenerator(
|
||||
override val functionName: String
|
||||
get() = "any"
|
||||
|
||||
override val shouldUseInputVariable: Boolean
|
||||
get() = false
|
||||
|
||||
override fun generate(chainedCallGenerator: ChainedCallGenerator, filter: KtExpression?): KtExpression {
|
||||
val chainedCall = generateChainedCall(functionName, chainedCallGenerator, filter)
|
||||
return KtPsiFactory(chainedCall).createExpressionByPattern("if ($0) $1 else $2", chainedCall, valueIfFound, valueIfNotFound)
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
// IS_APPLICABLE: false
|
||||
import java.util.*
|
||||
|
||||
fun foo(list: List<String>): String? {
|
||||
val random = Random()
|
||||
for (s in list) {
|
||||
if (random.nextBoolean()) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
// IS_APPLICABLE: false
|
||||
fun foo(list: List<String>, target: MutableList<Int>) {
|
||||
<caret>for (s in list) {
|
||||
if (s.length > 0)
|
||||
target.add(0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user