Convert 'simplify when' from intention to inspection

Related to KT-20492
This commit is contained in:
Mikhail Glukhikh
2017-11-09 16:30:34 +03:00
parent df86ff7115
commit 7b2a66c006
36 changed files with 150 additions and 133 deletions
@@ -0,0 +1,5 @@
<html>
<body>
This inspection detects 'when' with 'true' or 'false' branches that can be simplified.
</body>
</html>
@@ -1,5 +0,0 @@
val foo = when {
true -> "foo"
false -> "bar"
else -> "baz"
}
@@ -1,5 +0,0 @@
<html>
<body>
This intention simplifies a when expression that has branch conditions which are true or false
</body>
</html>
+10 -5
View File
@@ -1650,11 +1650,6 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.inspections.SimplifyWhenWithBooleanConstantConditionIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
@@ -2678,6 +2673,16 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.SimplifyWhenWithBooleanConstantConditionInspection"
displayName="Simplifiable 'when'"
groupPath="Kotlin"
groupName="Redundant constructs"
enabledByDefault="true"
level="WEAK WARNING"
language="kotlin"
/>
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
@@ -14,47 +14,64 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.intentions
package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.inspections.replaceWithBranch
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.isFalseConstant
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.isTrueConstant
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtWhenConditionWithExpression
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
class SimplifyWhenWithBooleanConstantConditionIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Simplify when expression") {
class SimplifyWhenWithBooleanConstantConditionInspection : AbstractKotlinInspection() {
override fun applicabilityRange(element: KtWhenExpression): TextRange? {
if (element.closeBrace == null) return null
if (element.subjectExpression != null) return null
if (element.entries.none { it.isTrueConstantCondition() || it.isFalseConstantCondition() }) return null
return element.whenKeyword.textRange
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : KtVisitorVoid() {
override fun visitWhenExpression(expression: KtWhenExpression) {
super.visitWhenExpression(expression)
if (expression.closeBrace == null) return
if (expression.subjectExpression != null) return
if (expression.entries.none { it.isTrueConstantCondition() || it.isFalseConstantCondition() }) return
holder.registerProblem(expression.whenKeyword,
"This 'when' is simplifiable",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
SimplifyWhenFix())
}
}
}
}
override fun applyTo(element: KtWhenExpression, editor: Editor?) {
private class SimplifyWhenFix : LocalQuickFix {
override fun getName() = "Simplify 'when'"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.psiElement.getStrictParentOfType<KtWhenExpression>() ?: return
val closeBrace = element.closeBrace ?: return
val project = editor?.project ?: return
val factory = KtPsiFactory(project)
val usedAsExpression = element.isUsedAsExpression(element.analyze())
element.deleteFalseEntry(usedAsExpression)
element.deleteFalseEntries(usedAsExpression)
element.replaceTrueEntry(usedAsExpression, closeBrace, factory)
}
}
private fun KtWhenExpression.deleteFalseEntry(usedAsExpression: Boolean) {
private fun KtWhenExpression.deleteFalseEntries(usedAsExpression: Boolean) {
for (entry in entries) {
if (entry.isFalseConstantCondition()) {
entry.delete()
}
}
val entries = entries
if (entries.isEmpty() && !usedAsExpression) {
delete()
}
@@ -64,6 +81,7 @@ private fun KtWhenExpression.deleteFalseEntry(usedAsExpression: Boolean) {
}
private fun KtWhenExpression.replaceTrueEntry(usedAsExpression: Boolean, closeBrace: PsiElement, factory: KtPsiFactory) {
val entries = entries
val trueIndex = entries.indexOfFirst { it.isTrueConstantCondition() }
if (trueIndex == -1) return
@@ -74,8 +92,8 @@ private fun KtWhenExpression.replaceTrueEntry(usedAsExpression: Boolean, closeBr
}
else {
val elseEntry = factory.createWhenEntry("else -> ${expression.text}")
for (index in trueIndex until entries.size) {
entries[index].delete()
for (entry in entries.subList(trueIndex, entries.size)) {
entry.delete()
}
addBefore(elseEntry, closeBrace)
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.SimplifyWhenWithBooleanConstantConditionInspection
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// WITH_RUNTIME
fun test(b: Boolean) {
<caret>when(b) {
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// WITH_RUNTIME
fun test(i: Int) {
<caret>when {
@@ -1,6 +1,6 @@
// WITH_RUNTIME
fun test() {
when<caret> {
wh<caret>en {
true -> {
println(1)
}
@@ -1 +0,0 @@
org.jetbrains.kotlin.idea.intentions.SimplifyWhenWithBooleanConstantConditionIntention
@@ -2250,6 +2250,99 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SimplifyWhenWithBooleanConstantCondition extends AbstractLocalInspectionTest {
public void testAllFilesPresentInSimplifyWhenWithBooleanConstantCondition() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("falseAndElse1.kt")
public void testFalseAndElse1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/falseAndElse1.kt");
doTest(fileName);
}
@TestMetadata("falseAndElse2.kt")
public void testFalseAndElse2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/falseAndElse2.kt");
doTest(fileName);
}
@TestMetadata("falseAndElse3.kt")
public void testFalseAndElse3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/falseAndElse3.kt");
doTest(fileName);
}
@TestMetadata("falseOnly1.kt")
public void testFalseOnly1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/falseOnly1.kt");
doTest(fileName);
}
@TestMetadata("falseOnly2.kt")
public void testFalseOnly2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/falseOnly2.kt");
doTest(fileName);
}
@TestMetadata("falseOnly3.kt")
public void testFalseOnly3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/falseOnly3.kt");
doTest(fileName);
}
@TestMetadata("hasSubject.kt")
public void testHasSubject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/hasSubject.kt");
doTest(fileName);
}
@TestMetadata("noBoolean.kt")
public void testNoBoolean() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/noBoolean.kt");
doTest(fileName);
}
@TestMetadata("trueIsNotTop1.kt")
public void testTrueIsNotTop1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/trueIsNotTop1.kt");
doTest(fileName);
}
@TestMetadata("trueIsNotTop2.kt")
public void testTrueIsNotTop2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/trueIsNotTop2.kt");
doTest(fileName);
}
@TestMetadata("trueIsNotTop3.kt")
public void testTrueIsNotTop3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/trueIsNotTop3.kt");
doTest(fileName);
}
@TestMetadata("trueIsTop1.kt")
public void testTrueIsTop1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/trueIsTop1.kt");
doTest(fileName);
}
@TestMetadata("trueIsTop2.kt")
public void testTrueIsTop2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/trueIsTop2.kt");
doTest(fileName);
}
@TestMetadata("trueIsTop3.kt")
public void testTrueIsTop3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/simplifyWhenWithBooleanConstantCondition/trueIsTop3.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/inspectionsLocal/unnecessaryVariable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -15216,99 +15216,6 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SimplifyWhenWithBooleanConstantCondition extends AbstractIntentionTest {
public void testAllFilesPresentInSimplifyWhenWithBooleanConstantCondition() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("falseAndElse1.kt")
public void testFalseAndElse1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/falseAndElse1.kt");
doTest(fileName);
}
@TestMetadata("falseAndElse2.kt")
public void testFalseAndElse2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/falseAndElse2.kt");
doTest(fileName);
}
@TestMetadata("falseAndElse3.kt")
public void testFalseAndElse3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/falseAndElse3.kt");
doTest(fileName);
}
@TestMetadata("falseOnly1.kt")
public void testFalseOnly1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/falseOnly1.kt");
doTest(fileName);
}
@TestMetadata("falseOnly2.kt")
public void testFalseOnly2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/falseOnly2.kt");
doTest(fileName);
}
@TestMetadata("falseOnly3.kt")
public void testFalseOnly3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/falseOnly3.kt");
doTest(fileName);
}
@TestMetadata("hasSubject.kt")
public void testHasSubject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/hasSubject.kt");
doTest(fileName);
}
@TestMetadata("noBooolean.kt")
public void testNoBooolean() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/noBooolean.kt");
doTest(fileName);
}
@TestMetadata("trueIsNotTop1.kt")
public void testTrueIsNotTop1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/trueIsNotTop1.kt");
doTest(fileName);
}
@TestMetadata("trueIsNotTop2.kt")
public void testTrueIsNotTop2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/trueIsNotTop2.kt");
doTest(fileName);
}
@TestMetadata("trueIsNotTop3.kt")
public void testTrueIsNotTop3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/trueIsNotTop3.kt");
doTest(fileName);
}
@TestMetadata("trueIsTop1.kt")
public void testTrueIsTop1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/trueIsTop1.kt");
doTest(fileName);
}
@TestMetadata("trueIsTop2.kt")
public void testTrueIsTop2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/trueIsTop2.kt");
doTest(fileName);
}
@TestMetadata("trueIsTop3.kt")
public void testTrueIsTop3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyWhenWithBooleanConstantCondition/trueIsTop3.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/intentions/specifyExplicitLambdaSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)