Refactoring

This commit is contained in:
Valentin Kipyatkov
2016-04-22 22:21:49 +03:00
parent 834fe9d535
commit 87c9af532e
@@ -85,7 +85,8 @@ object FindTransformationMatcher : TransformationMatcher {
// we do not try to convert anything if the initializer is not compile-time constant because of possible side-effects
if (!initialization.initializer.isConstant()) return null
val generator = buildFindOperationGenerator(right, initialization.initializer, state.inputVariable, state.indexVariable, filterTransformation, findFirst)
val generator = buildFindOperationGenerator(state.outerLoop, right, initialization.initializer, state.inputVariable,
state.indexVariable, filterTransformation, findFirst)
?: return null
val transformation = FindAndAssignTransformation(state.outerLoop, generator, initialization)
@@ -100,7 +101,7 @@ object FindTransformationMatcher : TransformationMatcher {
val returnValueInLoop = returnInLoop.returnedExpression ?: return null
val returnValueAfterLoop = returnAfterLoop.returnedExpression ?: return null
val generator = buildFindOperationGenerator(returnValueInLoop, returnValueAfterLoop,
val generator = buildFindOperationGenerator(state.outerLoop, returnValueInLoop, returnValueAfterLoop,
state.inputVariable, state.indexVariable, filterTransformation, findFirst = true)
?: return null
@@ -175,7 +176,37 @@ object FindTransformationMatcher : TransformationMatcher {
get() = 1
}
private class SimpleGenerator(
override val functionName: String,
private val inputVariable: KtCallableDeclaration,
private val filter: KtExpression?,
override val shouldUseInputVariable: Boolean
) : FindOperationGenerator {
override val hasFilter: Boolean
get() = filter != null
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
return generateChainedCall(functionName, chainedCallGenerator, inputVariable, filter)
}
}
private fun generateChainedCall(
stdlibFunName: String,
chainedCallGenerator: ChainedCallGenerator,
inputVariable: KtCallableDeclaration,
filter: KtExpression?
): KtExpression {
return if (filter == null) {
chainedCallGenerator.generate("$stdlibFunName()")
}
else {
val lambda = generateLambda(inputVariable, filter)
chainedCallGenerator.generate("$stdlibFunName $0:'{}'", lambda)
}
}
private fun buildFindOperationGenerator(
loop: KtForExpression,
valueIfFound: KtExpression,
valueIfNotFound: KtExpression,
inputVariable: KtCallableDeclaration,
@@ -186,29 +217,7 @@ object FindTransformationMatcher : TransformationMatcher {
assert(valueIfFound.isPhysical)
assert(valueIfNotFound.isPhysical)
val filterCondition = filterTransformation?.effectiveCondition()
fun generateChainedCall(stdlibFunName: String, chainedCallGenerator: ChainedCallGenerator, filter: KtExpression?): KtExpression {
return if (filter == null) {
chainedCallGenerator.generate("$stdlibFunName()")
}
else {
val lambda = generateLambda(inputVariable, filter)
chainedCallGenerator.generate("$stdlibFunName $0:'{}'", lambda)
}
}
class SimpleGenerator(
override val functionName: String,
override val shouldUseInputVariable: Boolean
) : FindOperationGenerator {
override val hasFilter: Boolean
get() = filterCondition != null
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
return generateChainedCall(functionName, chainedCallGenerator, filterCondition)
}
}
val filter = filterTransformation?.effectiveCondition()
if (indexVariable != null) {
if (filterTransformation == null) return null // makes no sense, indexVariable must be always 0
@@ -216,7 +225,8 @@ object FindTransformationMatcher : TransformationMatcher {
//TODO: what if value when not found is not "-1"?
if (valueIfFound.isVariableReference(indexVariable) && valueIfNotFound.text == "-1") {
return SimpleGenerator(if (findFirst) "indexOfFirst" else "indexOfLast", shouldUseInputVariable = false)
val functionName = if (findFirst) "indexOfFirst" else "indexOfLast"
return SimpleGenerator(functionName, inputVariable, filter, shouldUseInputVariable = false)
}
return null
@@ -239,45 +249,20 @@ object FindTransformationMatcher : TransformationMatcher {
}
}
fun buildGeneratorForAny(negated: Boolean): FindOperationGenerator {
if (filterCondition != null) {
val containsArgument = filterCondition.isFilterForContainsOperation(inputVariable, filterTransformation!!.loop)
if (containsArgument != null) {
return object: FindOperationGenerator {
override val functionName: String
get() = "contains"
override val hasFilter: Boolean
get() = false
override val shouldUseInputVariable: Boolean
get() = false
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
val expression = chainedCallGenerator.generate("contains($0)", containsArgument)
return if (negated) expression.negate() else expression
}
}
}
}
if (negated) {
return SimpleGenerator("none", shouldUseInputVariable = false)
}
else {
return SimpleGenerator("any", shouldUseInputVariable = false)
}
}
when {
valueIfFound.isVariableReference(inputVariable) -> {
val generator = SimpleGenerator(if (findFirst) "firstOrNull" else "lastOrNull", shouldUseInputVariable = true)
val functionName = if (findFirst) "firstOrNull" else "lastOrNull"
val generator = SimpleGenerator(functionName, inputVariable, filter, shouldUseInputVariable = true)
return generator.useElvisOperatorIfNeeded()
}
valueIfFound.isTrueConstant() && valueIfNotFound.isFalseConstant() -> return buildGeneratorForAny(negated = false)
valueIfFound.isTrueConstant() && valueIfNotFound.isFalseConstant() -> {
return buildFoundFlagGenerator(loop, inputVariable, filter, negated = false)
}
valueIfFound.isFalseConstant() && valueIfNotFound.isTrueConstant() -> return buildGeneratorForAny(negated = true)
valueIfFound.isFalseConstant() && valueIfNotFound.isTrueConstant() -> {
return buildFoundFlagGenerator(loop, inputVariable, filter, negated = true)
}
inputVariable.hasUsages(valueIfFound) -> {
if (!findFirst) return null // too dangerous because of side effects
@@ -293,7 +278,7 @@ object FindTransformationMatcher : TransformationMatcher {
get() = "firstOrNull"
override val hasFilter: Boolean
get() = filterCondition != null
get() = filter != null
override val shouldUseInputVariable: Boolean
get() = true
@@ -302,7 +287,7 @@ object FindTransformationMatcher : TransformationMatcher {
get() = 2
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, filterCondition)
val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, inputVariable, filter)
return chainedCallGenerator.generate("$0", selector, receiver = findFirstCall, safeCall = true)
}
}.useElvisOperatorIfNeeded()
@@ -317,7 +302,7 @@ object FindTransformationMatcher : TransformationMatcher {
get() = "firstOrNull"
override val hasFilter: Boolean
get() = filterCondition != null
get() = filter != null
override val shouldUseInputVariable: Boolean
get() = true
@@ -326,7 +311,7 @@ object FindTransformationMatcher : TransformationMatcher {
get() = 2 // also includes "let"
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, filterCondition)
val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, inputVariable, filter)
val letBody = generateLambda(inputVariable, valueIfFound)
return chainedCallGenerator.generate("let $0:'{}'", letBody, receiver = findFirstCall, safeCall = true)
}
@@ -334,10 +319,10 @@ object FindTransformationMatcher : TransformationMatcher {
}
else -> {
val generatorForAny = buildGeneratorForAny(negated = false)
return object: FindOperationGenerator by generatorForAny {
val generator = buildFoundFlagGenerator(loop, inputVariable, filter, negated = false)
return object: FindOperationGenerator by generator {
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
val chainedCall = generatorForAny.generate(chainedCallGenerator)
val chainedCall = generator.generate(chainedCallGenerator)
return KtPsiFactory(chainedCall).createExpressionByPattern("if ($0) $1 else $2", chainedCall, valueIfFound, valueIfNotFound)
}
}
@@ -346,6 +331,41 @@ object FindTransformationMatcher : TransformationMatcher {
}
}
private fun buildFoundFlagGenerator(
loop: KtForExpression,
inputVariable: KtCallableDeclaration,
filter: KtExpression?,
negated: Boolean
): FindOperationGenerator {
if (filter != null) {
val containsArgument = filter.isFilterForContainsOperation(inputVariable, loop)
if (containsArgument != null) {
return object: FindOperationGenerator {
override val functionName: String
get() = "contains"
override val hasFilter: Boolean
get() = false
override val shouldUseInputVariable: Boolean
get() = false
override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression {
val expression = chainedCallGenerator.generate("contains($0)", containsArgument)
return if (negated) expression.negate() else expression
}
}
}
}
if (negated) {
return SimpleGenerator("none", inputVariable, filter, shouldUseInputVariable = false)
}
else {
return SimpleGenerator("any", inputVariable, filter, shouldUseInputVariable = false)
}
}
private fun KtExpression.isFilterForContainsOperation(inputVariable: KtCallableDeclaration, loop: KtForExpression): KtExpression? {
if (this !is KtBinaryExpression) return null
if (operationToken != KtTokens.EQEQ) return null