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