Generating more simple construct instead of "let" in some cases

This commit is contained in:
Valentin Kipyatkov
2016-04-06 12:25:39 +03:00
parent a760ef3665
commit ff0bb4fbb8
7 changed files with 52 additions and 3 deletions

View File

@@ -61,7 +61,7 @@ class FlatMapTransformation(
if (iterableType.checkIsSuperTypeOf(nestedSequenceType) == null) return null
val nestedLoopBody = nestedLoop.body ?: return null
if (state.workingVariable.hasUsages(listOf(nestedLoopBody))) return null // workingVariable is still needed - cannot transform
if (state.workingVariable.hasUsages(nestedLoopBody)) return null // workingVariable is still needed - cannot transform
val newWorkingVariable = nestedLoop.loopParameter ?: return null
val transformation = FlatMapTransformation(state.workingVariable, transform)

View File

@@ -87,6 +87,10 @@ fun KtExpression?.isSimpleName(name: Name): Boolean {
return this is KtNameReferenceExpression && this.getQualifiedExpressionForSelector() == null && this.getReferencedNameAsName() == name
}
fun KtCallableDeclaration.hasUsages(inElement: KtElement): Boolean {
return hasUsages(listOf(inElement))
}
fun KtCallableDeclaration.hasUsages(inElements: Collection<KtElement>): Boolean {
// TODO: it's a temporary workaround about strange dead-lock when running inspections
return inElements.any { ReferencesSearch.search(this, LocalSearchScope(it)).any() }
@@ -127,10 +131,23 @@ fun buildFindOperationGenerator(
valueIfFound.isFalseConstant() && valueIfNotFound.isTrueConstant() -> "none"
workingVariable.hasUsages(listOf(valueIfFound)) -> {
workingVariable.hasUsages(valueIfFound) -> {
if (!valueIfNotFound.isNullExpression()) return null //TODO
if (!findFirst) return null // too dangerous because of side effects
// specially handle the case when the result expression is "<working variable>.<some call>" or "<working variable>?.<some call>"
val qualifiedExpression = valueIfFound as? KtQualifiedExpression
if (qualifiedExpression != null) {
val receiver = qualifiedExpression.receiverExpression
val selector = qualifiedExpression.selectorExpression
if (receiver.isVariableReference(workingVariable) && selector != null && !workingVariable.hasUsages(selector)) {
return { chainedCallGenerator, filter ->
val findFirstCall = generateChainedCall("firstOrNull", chainedCallGenerator, filter)
KtPsiFactory(findFirstCall).createExpressionByPattern("$0?.$1", findFirstCall, selector)
}
}
}
// in case of nullable working variable we cannot distinguish by the result of "firstOrNull" whether nothing was found or 'null' was found
if ((workingVariable.resolveToDescriptor() as VariableDescriptor).type.nullability() != TypeNullability.NOT_NULL) return null

View File

@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun foo(list: List<String>) {
var result: String? = null
<caret>for (s in list) {
if (s.length > 0) {
result = s.substring(0, s.length - 1)
break
}
}
}
fun bar(s: String): String = s

View File

@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun foo(list: List<String>) {
<caret>val result: String? = list.firstOrNull { it.length > 0 }?.let { it.substring(0, it.length - 1) }
}
fun bar(s: String): String = s

View File

@@ -1,4 +1,4 @@
// WITH_RUNTIME
fun foo(list: List<String>): Int? {
<caret>return list.firstOrNull { it.isNotEmpty() }?.let { it.length }
<caret>return list.firstOrNull { it.isNotEmpty() }?.length
}

View File

@@ -0,0 +1,10 @@
// WITH_RUNTIME
fun foo(list: List<String?>) {
var result: String? = null
<caret>for (s in list) {
if (s != "") {
result = s?.substring(1)
break
}
}
}

View File

@@ -0,0 +1,4 @@
// WITH_RUNTIME
fun foo(list: List<String?>) {
<caret>val result: String? = list.firstOrNull { it != "" }?.substring(1)
}