diff --git a/idea/resources/inspectionDescriptions/ReplaceAssertBooleanWithAssertEquality.html b/idea/resources/inspectionDescriptions/ReplaceAssertBooleanWithAssertEquality.html new file mode 100644 index 00000000000..dfa5ccbbf46 --- /dev/null +++ b/idea/resources/inspectionDescriptions/ReplaceAssertBooleanWithAssertEquality.html @@ -0,0 +1,6 @@ + + +This inspection reports assert boolean function calls replaceable with assert equality function. +Example: assertTrue(a == b) can be replaced by assertEquals(a, b). + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 4adf664e6d6..94a9dab6b3b 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2997,6 +2997,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173 index ab6f00e4bf7..ccbe8172e47 100644 --- a/idea/src/META-INF/plugin.xml.173 +++ b/idea/src/META-INF/plugin.xml.173 @@ -2996,6 +2996,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.181 b/idea/src/META-INF/plugin.xml.181 index 734cbab93cb..f84120de957 100644 --- a/idea/src/META-INF/plugin.xml.181 +++ b/idea/src/META-INF/plugin.xml.181 @@ -2996,6 +2996,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.183 b/idea/src/META-INF/plugin.xml.183 index 07a7a44ac0b..735a9cd0a0b 100644 --- a/idea/src/META-INF/plugin.xml.183 +++ b/idea/src/META-INF/plugin.xml.183 @@ -2997,6 +2997,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31 index 93b4115f0a7..95698548183 100644 --- a/idea/src/META-INF/plugin.xml.as31 +++ b/idea/src/META-INF/plugin.xml.as31 @@ -2996,6 +2996,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32 index 92bd0cb3b71..5e97bc35f06 100644 --- a/idea/src/META-INF/plugin.xml.as32 +++ b/idea/src/META-INF/plugin.xml.as32 @@ -2996,6 +2996,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as33 b/idea/src/META-INF/plugin.xml.as33 index 3e6fc2aa78a..268ec4eee51 100644 --- a/idea/src/META-INF/plugin.xml.as33 +++ b/idea/src/META-INF/plugin.xml.as33 @@ -2998,6 +2998,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceAssertBooleanWithAssertEqualityInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceAssertBooleanWithAssertEqualityInspection.kt new file mode 100644 index 00000000000..9f830c62f0d --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceAssertBooleanWithAssertEqualityInspection.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.inspections + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe + +class ReplaceAssertBooleanWithAssertEqualityInspection : AbstractApplicabilityBasedInspection(KtCallExpression::class.java) { + + override fun inspectionText(element: KtCallExpression) = "Replace assert boolean with assert equality" + + override val defaultFixText = "Replace assert boolean with assert equality" + + override fun fixText(element: KtCallExpression): String { + val assertion = element.replaceableAssertion() ?: return defaultFixText + return "Replace with '$assertion'" + } + + override fun isApplicable(element: KtCallExpression): Boolean { + return (element.replaceableAssertion() != null) + } + + override fun applyTo(element: PsiElement, project: Project, editor: Editor?) { + val expression = element as? KtCallExpression ?: return + val condition = expression.valueArguments.first().getArgumentExpression() as? KtBinaryExpression ?: return + val left = condition.left ?: return + val right = condition.right ?: return + val assertion = expression.replaceableAssertion() ?: return + val factory = KtPsiFactory(project) + + if (expression.valueArguments.size == 1) { + expression.replace(factory.createExpressionByPattern("$assertion($0, $1)", left, right)) + } else if (expression.valueArguments.size == 2) { + val message = expression.valueArguments[1].getArgumentExpression() ?: return + expression.replace(factory.createExpressionByPattern("$assertion($0, $1, $2)", left, right, message)) + } + } + + private fun KtCallExpression.replaceableAssertion(): String? { + val referencedName = (calleeExpression as? KtNameReferenceExpression)?.getReferencedName() ?: return null + if (referencedName !in assertions) { + return null + } + + if (getCallableDescriptor()?.containingDeclaration?.fqNameSafe != FqName("kotlin.test")) { + return null + } + + if (valueArguments.size != 1 && valueArguments.size != 2) return null + val binaryExpression = valueArguments.first().getArgumentExpression() as? KtBinaryExpression ?: return null + val operationToken = binaryExpression.operationToken + + return assertionMap[Pair(referencedName, operationToken)] + } + + companion object { + private val assertions = setOf("assertTrue", "assertFalse") + + private val assertionMap = mapOf( + Pair("assertTrue", KtTokens.EQEQ) to "assertEquals", + Pair("assertTrue", KtTokens.EQEQEQ) to "assertSame", + Pair("assertFalse", KtTokens.EQEQ) to "assertNotEquals", + Pair("assertFalse", KtTokens.EQEQEQ) to "assertNotSame" + ) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/.inspection b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/.inspection new file mode 100644 index 00000000000..23cef0b237f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.ReplaceAssertBooleanWithAssertEqualityInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalse.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalse.kt new file mode 100644 index 00000000000..c34f4bae5bc --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalse.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST +// PROBLEM: none + +import kotlin.test.* + +fun foo() { + val isA = false + assertFalse(isA) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt new file mode 100644 index 00000000000..9daeb97d9d3 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "b" + assertFalse(a == b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt.after b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt.after new file mode 100644 index 00000000000..41fefb75779 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt.after @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "b" + assertNotEquals(a, b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt new file mode 100644 index 00000000000..836d6313869 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "b" + assertFalse(a === b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt.after b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt.after new file mode 100644 index 00000000000..c6f42a57c99 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt.after @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "b" + assertNotSame(a, b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt new file mode 100644 index 00000000000..2e2a1c3caa7 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "b" + assertFalse(a == b, "message") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt.after b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt.after new file mode 100644 index 00000000000..dc5380969bd --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt.after @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "b" + assertNotEquals(a, b, "message") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrue.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrue.kt new file mode 100644 index 00000000000..007eb2f1f4f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrue.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST +// PROBLEM: none + +import kotlin.test.* + +fun foo() { + val isA = true + assertTrue(isA) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt new file mode 100644 index 00000000000..a9384a0d47b --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "a" + assertTrue(a == b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt.after b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt.after new file mode 100644 index 00000000000..92086e37e9b --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt.after @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "a" + assertEquals(a, b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt new file mode 100644 index 00000000000..c1622231e5f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "a" + assertTrue(a === b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt.after b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt.after new file mode 100644 index 00000000000..0233b2c3c7a --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt.after @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "a" + assertSame(a, b) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt new file mode 100644 index 00000000000..30264bcaff4 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "a" + assertTrue(a == b, "message") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt.after b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt.after new file mode 100644 index 00000000000..de36b31fc72 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt.after @@ -0,0 +1,9 @@ +// RUNTIME_WITH_KOTLIN_TEST + +import kotlin.test.* + +fun foo() { + val a = "a" + val b = "a" + assertEquals(a, b, "message") +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index c8c575bf313..e6109eace40 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -4649,6 +4649,59 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceAssertBooleanWithAssertEquality extends AbstractLocalInspectionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInReplaceAssertBooleanWithAssertEquality() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("assertFalse.kt") + public void testAssertFalse() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalse.kt"); + } + + @TestMetadata("assertFalseEQEQ.kt") + public void testAssertFalseEQEQ() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQ.kt"); + } + + @TestMetadata("assertFalseEQEQEQ.kt") + public void testAssertFalseEQEQEQ() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseEQEQEQ.kt"); + } + + @TestMetadata("assertFalseWithMessage.kt") + public void testAssertFalseWithMessage() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertFalseWithMessage.kt"); + } + + @TestMetadata("assertTrue.kt") + public void testAssertTrue() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrue.kt"); + } + + @TestMetadata("assertTrueEQEQ.kt") + public void testAssertTrueEQEQ() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQ.kt"); + } + + @TestMetadata("assertTrueEQEQEQ.kt") + public void testAssertTrueEQEQEQ() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueEQEQEQ.kt"); + } + + @TestMetadata("assertTrueWithMessage.kt") + public void testAssertTrueWithMessage() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt"); + } + } + @TestMetadata("idea/testData/inspectionsLocal/replacePutWithAssignment") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)