Convert ConvertTwoComparisonsToRangeCheck intention to inspection

Relates to #KT-17310
This commit is contained in:
Dmitry Gridin
2019-10-25 20:11:27 +07:00
parent 8e4c7ad65d
commit 81f3a98f49
65 changed files with 190 additions and 218 deletions
+2 -7
View File
@@ -1454,11 +1454,6 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertTwoComparisonsToRangeCheckIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertRangeCheckToTwoComparisonsIntention</className>
<category>Kotlin</category>
@@ -2370,8 +2365,8 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ConvertTwoComparisonsToRangeCheckInspection"
displayName="Convert two comparisons to 'in'"
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ConvertTwoComparisonsToRangeCheckInspection"
displayName="Two comparisons should be converted to a range check"
groupPath="Kotlin"
groupName="Style issues"
enabledByDefault="true"
@@ -1 +0,0 @@
fun foo(arg: Int) = arg in 1..4
@@ -1 +0,0 @@
fun foo(arg: Int) = 1 <= arg && arg <= 4
@@ -1,5 +0,0 @@
<html>
<body>
This intention converts two consecutive comparisons to a range check (<b>in</b>).
</body>
</html>
@@ -1,27 +1,15 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.intentions
package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.inspections.ReplaceRangeToWithUntilInspection
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.evaluatesTo
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -33,21 +21,15 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
@Suppress("DEPRECATION")
class ConvertTwoComparisonsToRangeCheckInspection : IntentionBasedInspection<KtBinaryExpression>(
ConvertTwoComparisonsToRangeCheckIntention::class
)
class ConvertTwoComparisonsToRangeCheckInspection :
AbstractApplicabilityBasedInspection<KtBinaryExpression>(KtBinaryExpression::class.java) {
override fun inspectionText(element: KtBinaryExpression) = "Two comparisons should be converted to a range check"
class ConvertTwoComparisonsToRangeCheckIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(
KtBinaryExpression::class.java,
"Convert to range check"
) {
override val defaultFixText = "Convert to a range check"
private data class RangeExpressionData(val value: KtExpression, val min: String, val max: String)
override fun isApplicable(element: KtBinaryExpression) = generateRangeExpressionData(element) != null
override fun isApplicableTo(element: KtBinaryExpression) = generateRangeExpressionData(element) != null
override fun applyTo(element: KtBinaryExpression, editor: Editor?) {
override fun applyTo(element: KtBinaryExpression, project: Project, editor: Editor?) {
val rangeData = generateRangeExpressionData(element) ?: return
val factory = KtPsiFactory(element)
val replaced = element.replace(
@@ -62,6 +44,8 @@ class ConvertTwoComparisonsToRangeCheckIntention : SelfTargetingOffsetIndependen
}
}
private data class RangeExpressionData(val value: KtExpression, val min: String, val max: String)
private fun generateRangeExpressionData(condition: KtBinaryExpression): RangeExpressionData? {
if (condition.operationToken != KtTokens.ANDAND) return null
val firstCondition = condition.left as? KtBinaryExpression ?: return null
@@ -200,4 +184,4 @@ class ConvertTwoComparisonsToRangeCheckIntention : SelfTargetingOffsetIndependen
this ?: return false
return this.isInteger() || KotlinBuiltIns.isChar(this)
}
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.ConvertTwoComparisonsToRangeCheckInspection
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// DISABLE-ERRORS
fun foo(bar: Char) {
bar > 1 && 2 > bar<caret>
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// WITH_RUNTIME
class A(val _value: Int) {
operator fun compareTo(other: Int) = _value.compareTo(other)
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// WITH_RUNTIME
class A(val _value: Int) {
operator fun compareTo(other: A) = _value.compareTo(other._value)
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// WITH_RUNTIME
fun foo(bar: Int) {
bar > 0.0 && 10.0 >= bar<caret>
@@ -1,4 +1,4 @@
// IS_APPLICABLE: false
// PROBLEM: none
// WITH_RUNTIME
fun foo(bar: Double) {
bar > 0 && 10 >= bar<caret>
@@ -1 +0,0 @@
org.jetbrains.kotlin.idea.intentions.ConvertTwoComparisonsToRangeCheckIntention
@@ -3406,6 +3406,174 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertTwoComparisonsToRangeCheck extends AbstractLocalInspectionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInConvertTwoComparisonsToRangeCheck() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), true);
}
@TestMetadata("char.kt")
public void testChar() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/char.kt");
}
@TestMetadata("charInclusive.kt")
public void testCharInclusive() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/charInclusive.kt");
}
@TestMetadata("charInt.kt")
public void testCharInt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/charInt.kt");
}
@TestMetadata("compareToComparableSameType.kt")
public void testCompareToComparableSameType() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/compareToComparableSameType.kt");
}
@TestMetadata("compareToDifferentTypes.kt")
public void testCompareToDifferentTypes() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/compareToDifferentTypes.kt");
}
@TestMetadata("compareToSameType.kt")
public void testCompareToSameType() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/compareToSameType.kt");
}
@TestMetadata("double.kt")
public void testDouble() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/double.kt");
}
@TestMetadata("doubleToInt1.kt")
public void testDoubleToInt1() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/doubleToInt1.kt");
}
@TestMetadata("doubleToInt2.kt")
public void testDoubleToInt2() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/doubleToInt2.kt");
}
@TestMetadata("flipped.kt")
public void testFlipped() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/flipped.kt");
}
@TestMetadata("flippedSideEffect.kt")
public void testFlippedSideEffect() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/flippedSideEffect.kt");
}
@TestMetadata("gtDouble.kt")
public void testGtDouble() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gtDouble.kt");
}
@TestMetadata("gtDouble2.kt")
public void testGtDouble2() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gtDouble2.kt");
}
@TestMetadata("gteqgt.kt")
public void testGteqgt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gteqgt.kt");
}
@TestMetadata("gteqgteq.kt")
public void testGteqgteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gteqgteq.kt");
}
@TestMetadata("gteqlt.kt")
public void testGteqlt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gteqlt.kt");
}
@TestMetadata("gteqlteq.kt")
public void testGteqlteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gteqlteq.kt");
}
@TestMetadata("gtgt.kt")
public void testGtgt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gtgt.kt");
}
@TestMetadata("gtgteq.kt")
public void testGtgteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gtgteq.kt");
}
@TestMetadata("gtlt.kt")
public void testGtlt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gtlt.kt");
}
@TestMetadata("gtlteq.kt")
public void testGtlteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/gtlteq.kt");
}
@TestMetadata("lteqgt.kt")
public void testLteqgt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/lteqgt.kt");
}
@TestMetadata("lteqgteq.kt")
public void testLteqgteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/lteqgteq.kt");
}
@TestMetadata("lteqlt.kt")
public void testLteqlt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/lteqlt.kt");
}
@TestMetadata("lteqlteq.kt")
public void testLteqlteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/lteqlteq.kt");
}
@TestMetadata("ltgt.kt")
public void testLtgt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/ltgt.kt");
}
@TestMetadata("ltgteq.kt")
public void testLtgteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/ltgteq.kt");
}
@TestMetadata("ltlt.kt")
public void testLtlt() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/ltlt.kt");
}
@TestMetadata("ltlteq.kt")
public void testLtlteq() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/ltlteq.kt");
}
@TestMetadata("nonConstants.kt")
public void testNonConstants() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/nonConstants.kt");
}
@TestMetadata("until.kt")
public void testUntil() throws Exception {
runTest("idea/testData/inspectionsLocal/convertTwoComparisonsToRangeCheck/until.kt");
}
}
@TestMetadata("idea/testData/inspectionsLocal/copyWithoutNamedArguments")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -7652,174 +7652,6 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertTwoComparisonsToRangeCheck")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertTwoComparisonsToRangeCheck extends AbstractIntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInConvertTwoComparisonsToRangeCheck() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertTwoComparisonsToRangeCheck"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), true);
}
@TestMetadata("char.kt")
public void testChar() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/char.kt");
}
@TestMetadata("charInclusive.kt")
public void testCharInclusive() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/charInclusive.kt");
}
@TestMetadata("charInt.kt")
public void testCharInt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/charInt.kt");
}
@TestMetadata("compareToComparableSameType.kt")
public void testCompareToComparableSameType() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/compareToComparableSameType.kt");
}
@TestMetadata("compareToDifferentTypes.kt")
public void testCompareToDifferentTypes() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/compareToDifferentTypes.kt");
}
@TestMetadata("compareToSameType.kt")
public void testCompareToSameType() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/compareToSameType.kt");
}
@TestMetadata("double.kt")
public void testDouble() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/double.kt");
}
@TestMetadata("doubleToInt1.kt")
public void testDoubleToInt1() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/doubleToInt1.kt");
}
@TestMetadata("doubleToInt2.kt")
public void testDoubleToInt2() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/doubleToInt2.kt");
}
@TestMetadata("flipped.kt")
public void testFlipped() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/flipped.kt");
}
@TestMetadata("flippedSideEffect.kt")
public void testFlippedSideEffect() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/flippedSideEffect.kt");
}
@TestMetadata("gtDouble.kt")
public void testGtDouble() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gtDouble.kt");
}
@TestMetadata("gtDouble2.kt")
public void testGtDouble2() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gtDouble2.kt");
}
@TestMetadata("gteqgt.kt")
public void testGteqgt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gteqgt.kt");
}
@TestMetadata("gteqgteq.kt")
public void testGteqgteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gteqgteq.kt");
}
@TestMetadata("gteqlt.kt")
public void testGteqlt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gteqlt.kt");
}
@TestMetadata("gteqlteq.kt")
public void testGteqlteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gteqlteq.kt");
}
@TestMetadata("gtgt.kt")
public void testGtgt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gtgt.kt");
}
@TestMetadata("gtgteq.kt")
public void testGtgteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gtgteq.kt");
}
@TestMetadata("gtlt.kt")
public void testGtlt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gtlt.kt");
}
@TestMetadata("gtlteq.kt")
public void testGtlteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/gtlteq.kt");
}
@TestMetadata("lteqgt.kt")
public void testLteqgt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/lteqgt.kt");
}
@TestMetadata("lteqgteq.kt")
public void testLteqgteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/lteqgteq.kt");
}
@TestMetadata("lteqlt.kt")
public void testLteqlt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/lteqlt.kt");
}
@TestMetadata("lteqlteq.kt")
public void testLteqlteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/lteqlteq.kt");
}
@TestMetadata("ltgt.kt")
public void testLtgt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/ltgt.kt");
}
@TestMetadata("ltgteq.kt")
public void testLtgteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/ltgteq.kt");
}
@TestMetadata("ltlt.kt")
public void testLtlt() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/ltlt.kt");
}
@TestMetadata("ltlteq.kt")
public void testLtlteq() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/ltlteq.kt");
}
@TestMetadata("nonConstants.kt")
public void testNonConstants() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/nonConstants.kt");
}
@TestMetadata("until.kt")
public void testUntil() throws Exception {
runTest("idea/testData/intentions/convertTwoComparisonsToRangeCheck/until.kt");
}
}
@TestMetadata("idea/testData/intentions/convertUnsafeCastCallToUnsafeCast")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)