Replace assert boolean with assert equality: do not report when arguments type are not subtype

#KT-30761 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-04-09 14:55:23 +09:00
committed by Mikhail Glukhikh
parent 93d854362b
commit 849d18669b
8 changed files with 111 additions and 4 deletions
@@ -9,16 +9,23 @@ import com.intellij.codeInsight.actions.OptimizeImportsProcessor
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.replaced
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.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
class ReplaceAssertBooleanWithAssertEqualityInspection : AbstractApplicabilityBasedInspection<KtCallExpression>(KtCallExpression::class.java) {
class ReplaceAssertBooleanWithAssertEqualityInspection : AbstractApplicabilityBasedInspection<KtCallExpression>(
KtCallExpression::class.java
) {
override fun inspectionText(element: KtCallExpression) = "Replace assert boolean with assert equality"
override val defaultFixText = "Replace assert boolean with assert equality"
@@ -58,16 +65,28 @@ class ReplaceAssertBooleanWithAssertEqualityInspection : AbstractApplicabilityBa
return null
}
if (getCallableDescriptor()?.containingDeclaration?.fqNameSafe != FqName(kotlinTestPackage)) {
val context = analyze(BodyResolveMode.PARTIAL)
if (descriptor(context)?.containingDeclaration?.fqNameSafe != FqName(kotlinTestPackage)) {
return null
}
if (valueArguments.size != 1 && valueArguments.size != 2) return null
val binaryExpression = valueArguments.first().getArgumentExpression() as? KtBinaryExpression ?: return null
val leftType = binaryExpression.left?.type(context) ?: return null
val rightType = binaryExpression.right?.type(context) ?: return null
if (!leftType.isSubtypeOf(rightType) && !rightType.isSubtypeOf(leftType)) return null
val operationToken = binaryExpression.operationToken
return assertionMap[Pair(referencedName, operationToken)]
}
private fun KtExpression.descriptor(context: BindingContext): CallableDescriptor? {
return getResolvedCall(context)?.resultingDescriptor
}
private fun KtExpression.type(context: BindingContext): KotlinType? {
return descriptor(context)?.returnType
}
companion object {
private const val kotlinTestPackage = "kotlin.test"
@@ -0,0 +1,12 @@
// RUNTIME_WITH_KOTLIN_TEST
// PROBLEM: none
import kotlin.test.assertTrue
interface Parent
interface Child : Parent
fun test(p: Parent, c: Child?) {
assertTrue<caret>(p == c)
}
@@ -0,0 +1,12 @@
// RUNTIME_WITH_KOTLIN_TEST
// PROBLEM: none
import kotlin.test.assertTrue
interface Parent
interface Child : Parent
fun test(p: Parent, c: Child?) {
assertTrue<caret>(c === p)
}
@@ -0,0 +1,11 @@
// RUNTIME_WITH_KOTLIN_TEST
import kotlin.test.assertTrue
interface Parent
interface Child : Parent
fun test(p: Parent?, c: Child) {
<caret>assertTrue(p == c)
}
@@ -0,0 +1,11 @@
// RUNTIME_WITH_KOTLIN_TEST
import kotlin.test.assertEquals
interface Parent
interface Child : Parent
fun test(p: Parent?, c: Child) {
assertEquals(p, c)
}
@@ -0,0 +1,11 @@
// RUNTIME_WITH_KOTLIN_TEST
import kotlin.test.assertTrue
interface Parent
interface Child : Parent
fun test(p: Parent?, c: Child) {
<caret>assertTrue(c === p)
}
@@ -0,0 +1,11 @@
// RUNTIME_WITH_KOTLIN_TEST
import kotlin.test.assertSame
interface Parent
interface Child : Parent
fun test(p: Parent?, c: Child) {
assertSame(c, p)
}
@@ -6845,6 +6845,26 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
public void testAssertTrueWithMessage() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/assertTrueWithMessage.kt");
}
@TestMetadata("notSubtype.kt")
public void testNotSubtype() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/notSubtype.kt");
}
@TestMetadata("notSubtype2.kt")
public void testNotSubtype2() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/notSubtype2.kt");
}
@TestMetadata("subtype.kt")
public void testSubtype() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/subtype.kt");
}
@TestMetadata("subtype2.kt")
public void testSubtype2() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceAssertBooleanWithAssertEquality/subtype2.kt");
}
}
@TestMetadata("idea/testData/inspectionsLocal/replaceAssociateFunction")