diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt index 7e75514bb54..9c07a03bb28 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt @@ -17,9 +17,13 @@ import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isElseIf import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlockOrParenthesis import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.hasNoSideEffects import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.calls.callUtil.getType @@ -158,43 +162,29 @@ private fun KtExpression.enumEntry(): KtEnumEntry? { fun KtExpression.replaceWithBranch(branch: KtExpression, isUsedAsExpression: Boolean, keepBraces: Boolean = false) { val caretModel = findExistingEditor()?.caretModel - val subjectVariable = (this as? KtWhenExpression)?.subjectVariable?.let { it -> - if (it.annotationEntries.isNotEmpty()) return@let it - val initializer = it.initializer ?: return@let it - val references = ReferencesSearch.search(it, LocalSearchScope(this)).toList() - when (references.size) { - 0 -> when (initializer) { - is KtSimpleNameExpression, is KtStringTemplateExpression, is KtConstantExpression -> null - else -> it - } + val subjectVariable = (this as? KtWhenExpression)?.subjectVariable?.let(fun(property: KtProperty): KtProperty? { + if (property.annotationEntries.isNotEmpty()) return property + val initializer = property.initializer ?: return property + val references = ReferencesSearch.search(property, LocalSearchScope(this)).toList() + return when (references.size) { + 0 -> property.takeUnless { initializer.hasNoSideEffects() } 1 -> { - references.firstOrNull()?.element?.replace(initializer) - null + if (initializer.hasNoSideEffects()) { + references.first().element.replace(initializer) + null + } else + property } - else -> it + else -> property } - } - val wrapSubjectVariableByRun = if (subjectVariable != null) { - val subjectVariableName = subjectVariable.nameAsName - val parentBlock = getStrictParentOfType() - parentBlock?.anyDescendantOfType { it != subjectVariable && it.nameAsName == subjectVariableName } == true - } else { - false - } + }) val factory = KtPsiFactory(this) val parent = this.parent val replaced = when { branch !is KtBlockExpression -> { if (subjectVariable != null) { - if (isUsedAsExpression || wrapSubjectVariableByRun) { - replaced(KtPsiFactory(this).createExpressionByPattern("run { $0\n$1 }", subjectVariable, branch)) - } else { - parent.addBefore(subjectVariable, this).also { - parent.addAfter(factory.createNewLine(), it) - replaced(branch) - } - } + replaced(KtPsiFactory(this).createExpressionByPattern("run { $0\n$1 }", subjectVariable, branch)) } else { replaced(branch) } @@ -212,12 +202,11 @@ fun KtExpression.replaceWithBranch(branch: KtExpression, isUsedAsExpression: Boo if (keepBraces) { parent.addAfter(branch, this) } else { - if (subjectVariable != null && wrapSubjectVariableByRun) { + if (subjectVariable != null) { branch.addAfter(subjectVariable, branch.lBrace) parent.addAfter(KtPsiFactory(this).createExpression("run ${branch.text}"), this) } else { parent.addRangeAfter(firstChildSibling, lastChild.prevSibling, this) - subjectVariable?.let { parent.addBefore(subjectVariable, this) } } } } else { diff --git a/idea/src/org/jetbrains/kotlin/idea/util/expressionExt.kt b/idea/src/org/jetbrains/kotlin/idea/util/expressionExt.kt index 2aee6ecee4e..33824188bba 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/expressionExt.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/expressionExt.kt @@ -5,12 +5,12 @@ package org.jetbrains.kotlin.idea.util +import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtCallExpression -import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.psi.KtPrimaryConstructor -import org.jetbrains.kotlin.psi.KtTypeArgumentList +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode fun KtCallExpression.replaceOrCreateTypeArgumentList(newTypeArgumentList: KtTypeArgumentList) { @@ -25,4 +25,11 @@ fun KtModifierListOwner.hasInlineModifier() = hasModifier(KtTokens.INLINE_KEYWOR fun KtPrimaryConstructor.allowedValOrVar(): Boolean = containingClass()?.let { it.isAnnotation() || it.hasInlineModifier() -} ?: false \ No newline at end of file +} ?: false + +// TODO: add cases +fun KtExpression.hasNoSideEffects(): Boolean = when (this) { + is KtStringTemplateExpression -> !hasInterpolation() + is KtConstantExpression -> true + else -> ConstantExpressionEvaluator.getConstant(this, analyze(BodyResolveMode.PARTIAL)) != null +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/notExpression.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/notExpression.kt.after index 46086172e59..df0f4941af6 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/notExpression.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/notExpression.kt.after @@ -1,6 +1,6 @@ fun println(s: String) {} fun foo() { - println("") + println("") 1 } \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt index 3eb070f2c66..f51c6de5107 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = create()) { else -> { diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt.after index 993b29e7c2f..0034af0c416 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/multiReference.kt.after @@ -1,7 +1,10 @@ +// WITH_RUNTIME fun test() { - val a = create() - use(a, a) - foo() + run { + val a = create() + use(a, a) + foo() + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt index 20d920706f6..81ee291a819 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = create()) { else -> { diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt.after index 9ba37d2622d..bd786bbe0e5 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference.kt.after @@ -1,7 +1,10 @@ +// WITH_RUNTIME fun test() { - val a = create() - use("") - foo() + run { + val a = create() + use("") + foo() + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt index f9b90738f0a..1a26662195d 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = 42) { else -> { diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt.after index 46ca1cb2ec5..71b68626d4b 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/noReference2.kt.after @@ -1,5 +1,6 @@ +// WITH_RUNTIME fun test() { - use("") + use("") foo() } diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt index d93e2e0a076..7687809e9da 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = create()) { else -> { diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt.after index 36554c4a028..2edeafa5248 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElse/singleReference.kt.after @@ -1,6 +1,10 @@ +// WITH_RUNTIME fun test() { - use(create()) - foo() + run { + val a = create() + use(a) + foo() + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElseUsedAsExpression/singleReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElseUsedAsExpression/singleReference.kt.after index 160363e065d..f86bc09da83 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElseUsedAsExpression/singleReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/blockElseUsedAsExpression/singleReference.kt.after @@ -1,7 +1,8 @@ // WITH_RUNTIME fun test() { - val x = run { - use(create()) + val x = run { + val a = create() + use(a) } } diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt index 0de070b5861..53e8cb29e28 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun hasAnnotation() { when (@Bar val a = create()) { else -> use(a) diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt.after index 1f393ec15b9..e0e0d32943f 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/hasAnnotation.kt.after @@ -1,6 +1,9 @@ +// WITH_RUNTIME fun hasAnnotation() { - @Bar val a = create() - use(a) + run { + @Bar val a = create() + use(a) + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt index 592b2ec7c79..aefc0a85104 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = create()) { else -> use(a, a) diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt.after index d949293407a..6ef819e3a3f 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/multiReference.kt.after @@ -1,6 +1,9 @@ +// WITH_RUNTIME fun test() { - val a = create() - use(a, a) + run { + val a = create() + use(a, a) + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt index 383e9f243e2..6fd3427c090 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = create()) { else -> use("") diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt.after index cbb939a698b..c85fec5be6c 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference.kt.after @@ -1,6 +1,9 @@ +// WITH_RUNTIME fun test() { - val a = create() - use("") + run { + val a = create() + use("") + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference2.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference2.kt.after index 67b8d343162..0803d273d6e 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference2.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/noReference2.kt.after @@ -1,5 +1,5 @@ fun test() { - use("") + use("") } fun use(s: String) {} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt index def82072cb9..63ec5480126 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt @@ -1,3 +1,4 @@ +// WITH_RUNTIME fun test() { when (val a = create()) { else -> use(a) diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt.after index 9c2b8505bab..4e1750c8281 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReference.kt.after @@ -1,5 +1,9 @@ +// WITH_RUNTIME fun test() { - use(create()) + run { + val a = create() + use(a) + } } fun create(): String = "" diff --git a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReferenceUsedAsExpression.kt.after b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReferenceUsedAsExpression.kt.after index 08cde0eb0fb..f86bc09da83 100644 --- a/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReferenceUsedAsExpression.kt.after +++ b/idea/testData/inspectionsLocal/whenWithOnlyElse/subjectVariable/singleElse/singleReferenceUsedAsExpression.kt.after @@ -1,6 +1,9 @@ // WITH_RUNTIME fun test() { - val x = use(create()) + val x = run { + val a = create() + use(a) + } } fun create(): String = ""