Optimized even more code. Fixed BinaryExpression for Boolean.TRUE/FALSE. Added new AssertThatJava8Optional inspection. Added changelog to README.

This commit is contained in:
2019-04-11 16:26:11 +02:00
parent c1d8ade7b1
commit d49b7bf17b
18 changed files with 528 additions and 154 deletions
@@ -4,10 +4,13 @@ import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.PsiTypesUtil
import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.getArg
import de.platon42.intellij.plugins.cajon.qualifierExpression
import de.platon42.intellij.plugins.cajon.quickfixes.RemoveActualOutmostMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceExpectedOutmostMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix
import org.jetbrains.annotations.NonNls
@@ -15,6 +18,7 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
companion object {
const val SIMPLIFY_MESSAGE_TEMPLATE = "%s can be simplified to %s"
const val MORE_CONCISE_MESSAGE_TEMPLATE = "%s would be more concise than %s"
const val REPLACE_DESCRIPTION_TEMPLATE = "Replace %s with %s"
@@ -43,6 +47,10 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
@NonNls
const val IS_NOT_EQUAL_TO_METHOD = "isNotEqualTo"
@NonNls
const val IS_SAME_AS_METHOD = "isSameAs"
@NonNls
const val IS_NOT_SAME_AS_METHOD = "isNotSameAs"
@NonNls
const val IS_GREATER_THAN_METHOD = "isGreaterThan"
@NonNls
const val IS_GREATER_THAN_OR_EQUAL_TO_METHOD = "isGreaterThanOrEqualTo"
@@ -61,12 +69,50 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
@NonNls
const val HAS_SIZE_METHOD = "hasSize"
val TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP = mapOf<IElementType, String>(
JavaTokenType.EQEQ to IS_EQUAL_TO_METHOD,
JavaTokenType.NE to IS_NOT_EQUAL_TO_METHOD,
JavaTokenType.GT to IS_GREATER_THAN_METHOD,
JavaTokenType.GE to IS_GREATER_THAN_OR_EQUAL_TO_METHOD,
JavaTokenType.LT to IS_LESS_THAN_METHOD,
JavaTokenType.LE to IS_LESS_THAN_OR_EQUAL_TO_METHOD
)
val TOKEN_TO_ASSERTJ_FOR_OBJECT_MAPPINGS = mapOf<IElementType, String>(
JavaTokenType.EQEQ to IS_SAME_AS_METHOD,
JavaTokenType.NE to IS_NOT_SAME_AS_METHOD
)
val SWAP_SIDE_OF_BINARY_OPERATOR = mapOf<IElementType, IElementType>(
JavaTokenType.GT to JavaTokenType.LT,
JavaTokenType.GE to JavaTokenType.LE,
JavaTokenType.LT to JavaTokenType.GT,
JavaTokenType.LE to JavaTokenType.GE
)
val INVERT_BINARY_OPERATOR = mapOf<IElementType, IElementType>(
JavaTokenType.EQEQ to JavaTokenType.NE,
JavaTokenType.NE to JavaTokenType.EQEQ,
JavaTokenType.GT to JavaTokenType.LE,
JavaTokenType.GE to JavaTokenType.LT,
JavaTokenType.LT to JavaTokenType.GE,
JavaTokenType.LE to JavaTokenType.GT
)
val ASSERT_THAT_INT = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, ASSERT_THAT_METHOD)
.parameterTypes("int")!!
val ASSERT_THAT_BOOLEAN = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, ASSERT_THAT_METHOD)
.parameterTypes("boolean")!!
val ASSERT_THAT_ANY = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, ASSERT_THAT_METHOD)
.parameterCount(1)!!
val ASSERT_THAT_JAVA8_OPTIONAL = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, ASSERT_THAT_METHOD)
.parameterTypes(CommonClassNames.JAVA_UTIL_OPTIONAL)!!
val IS_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_EQUAL_TO_METHOD)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val IS_NOT_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_NOT_EQUAL_TO_METHOD)
@@ -76,6 +122,11 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
val IS_NOT_EQUAL_TO_BOOLEAN =
CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_NOT_EQUAL_TO_METHOD)
.parameterTypes("boolean")!!
val IS_SAME_AS_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_SAME_AS_METHOD)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val IS_NOT_SAME_AS_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_NOT_SAME_AS_METHOD)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val HAS_SIZE = CallMatcher.instanceCall(ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME, HAS_SIZE_METHOD)
.parameterTypes("int")!!
@@ -105,6 +156,18 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
.parameterCount(0)!!
val OBJECT_EQUALS = CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_OBJECT, "equals")
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val OPTIONAL_GET = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_OPTIONAL, "get")
.parameterCount(0)!!
val OPTIONAL_IS_PRESENT = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_OPTIONAL, "isPresent")
.parameterCount(0)!!
val OPTIONAL_OF = CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_OPTIONAL, "of")
.parameterCount(1)!!
val OPTIONAL_OF_NULLABLE = CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_OPTIONAL, "ofNullable")
.parameterCount(1)!!
val OPTIONAL_EMPTY = CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_OPTIONAL, "empty")
.parameterCount(0)!!
}
override fun getGroupDisplayName(): String {
@@ -137,6 +200,33 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
holder.registerProblem(expression, message, quickFix)
}
protected fun registerRemoveActualOutmostMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression,
replacementMethod: String,
noExpectedExpression: Boolean = false
) {
val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod)
val quickfix = RemoveActualOutmostMethodCallQuickFix(description, replacementMethod, noExpectedExpression)
holder.registerProblem(expression, message, quickfix)
}
protected fun registerRemoveExpectedOutmostMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression,
replacementMethod: String
) {
val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod)
val quickfix = ReplaceExpectedOutmostMethodCallQuickFix(description, replacementMethod)
holder.registerProblem(expression, message, quickfix)
}
protected fun calculateConstantParameterValue(expression: PsiMethodCallExpression, argIndex: Int): Any? {
if (argIndex >= expression.argumentList.expressionCount) return null
val valueExpression = expression.getArg(argIndex)
@@ -155,6 +245,22 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
return value
}
protected fun getExpectedBooleanResult(expectedCallExpression: PsiMethodCallExpression): Boolean? {
val isTrue = IS_TRUE.test(expectedCallExpression)
val isFalse = IS_FALSE.test(expectedCallExpression)
if (isTrue || isFalse) {
return isTrue
} else {
val isEqualTo = IS_EQUAL_TO_BOOLEAN.test(expectedCallExpression) || IS_EQUAL_TO_OBJECT.test(expectedCallExpression)
val isNotEqualTo = IS_NOT_EQUAL_TO_BOOLEAN.test(expectedCallExpression) || IS_NOT_EQUAL_TO_OBJECT.test(expectedCallExpression)
if (isEqualTo || isNotEqualTo) {
val constValue = calculateConstantParameterValue(expectedCallExpression, 0) as? Boolean ?: return null
return isNotEqualTo xor constValue
}
}
return null
}
protected fun hasAssertJMethod(element: PsiElement, classAndMethod: String): Boolean {
val classname = "org.assertj.core.api.${classAndMethod.substringBeforeLast(".")}"
val findClass =
@@ -2,7 +2,6 @@ package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.TypeConversionUtil
import de.platon42.intellij.plugins.cajon.firstArg
@@ -17,27 +16,6 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
private const val SPLIT_EQUALS_EXPRESSION_DESCRIPTION = "Split equals() expression out of assertThat()"
private const val BINARY_MORE_MEANINGFUL_MESSAGE = "Moving binary expression out of assertThat() would be more meaningful"
private const val EQUALS_MORE_MEANINGFUL_MESSAGE = "Moving equals() expression out of assertThat() would be more meaningful"
private val PRIMITIVE_MAPPINGS = listOf(
Mapping(JavaTokenType.EQEQ, "isEqualTo()", "isNotEqualTo()"),
Mapping(JavaTokenType.NE, "isNotEqualTo()", "isEqualTo()"),
Mapping(JavaTokenType.GT, "isGreaterThan()", "isLessThanOrEqualTo()"),
Mapping(JavaTokenType.GE, "isGreaterThanOrEqualTo()", "isLessThan()"),
Mapping(JavaTokenType.LT, "isLessThan()", "isGreaterThanOrEqualTo()"),
Mapping(JavaTokenType.LE, "isLessThanOrEqualTo()", "isGreaterThan()")
)
private val OBJECT_MAPPINGS = listOf(
Mapping(JavaTokenType.EQEQ, "isSameAs()", "isNotSameAs()"),
Mapping(JavaTokenType.NE, "isNotSameAs()", "isSameAs()")
)
private val SWAP_BINARY_OPERATOR = mapOf<IElementType, IElementType>(
JavaTokenType.GT to JavaTokenType.LT,
JavaTokenType.GE to JavaTokenType.LE,
JavaTokenType.LT to JavaTokenType.GT,
JavaTokenType.LE to JavaTokenType.GE
)
}
override fun getDisplayName() = DISPLAY_NAME
@@ -52,11 +30,11 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val isInverted = getExpectedResult(expectedCallExpression) ?: return
val expectedResult = getExpectedBooleanResult(expectedCallExpression) ?: return
val assertThatArgument = expression.firstArg
if (assertThatArgument is PsiMethodCallExpression && OBJECT_EQUALS.test(assertThatArgument)) {
val replacementMethod = if (isInverted) "isNotEqualTo()" else "isEqualTo()"
val replacementMethod = if (expectedResult) "isEqualTo()" else "isNotEqualTo()"
val quickFix = SplitEqualsExpressionMethodCallQuickFix(SPLIT_EQUALS_EXPRESSION_DESCRIPTION, replacementMethod)
holder.registerProblem(expression, EQUALS_MORE_MEANINGFUL_MESSAGE, quickFix)
return
@@ -72,13 +50,8 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
if (isLeftNull && isRightNull) {
return
} else if (isLeftNull || isRightNull) {
registerSplitBinaryExpressionMethod(
holder,
expression,
if (isInverted) "isNotNull()" else "isNull()",
pickRightOperand = isLeftNull,
noExpectedExpression = true
)
val replacementMethod = if (expectedResult) "isNull()" else "isNotNull()"
registerSplitBinaryExpressionMethod(holder, expression, replacementMethod, pickRightOperand = isLeftNull, noExpectedExpression = true)
return
}
@@ -87,35 +60,22 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
val constantEvaluationHelper = JavaPsiFacade.getInstance(expression.project).constantEvaluationHelper
val swapExpectedAndActual = constantEvaluationHelper.computeConstantExpression(binaryExpression.lOperand) != null
val tokenType = binaryExpression.operationSign.tokenType.let {
if (swapExpectedAndActual) SWAP_BINARY_OPERATOR.getOrDefault(it, it) else it
} ?: return
val tokenType = binaryExpression.operationSign.tokenType
.let {
if (swapExpectedAndActual) SWAP_SIDE_OF_BINARY_OPERATOR.getOrDefault(it, it) else it
}
.let {
if (expectedResult) it else INVERT_BINARY_OPERATOR.getOrDefault(it, it)
} ?: return
val mappingToUse =
if (isPrimitive || isNumericType) {
PRIMITIVE_MAPPINGS
TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP
} else {
OBJECT_MAPPINGS
TOKEN_TO_ASSERTJ_FOR_OBJECT_MAPPINGS
}
val mapping = mappingToUse.find { it.tokenType == tokenType } ?: return
val replacementMethod = if (isInverted) mapping.replacementInverted else mapping.replacement
val replacementMethod = mappingToUse[tokenType] ?: return
registerSplitBinaryExpressionMethod(holder, expression, replacementMethod, pickRightOperand = swapExpectedAndActual)
}
private fun getExpectedResult(expectedCallExpression: PsiMethodCallExpression): Boolean? {
val isTrue = IS_TRUE.test(expectedCallExpression)
val isFalse = IS_FALSE.test(expectedCallExpression)
if (isTrue || isFalse) {
return isFalse
} else {
val isEqualTo = IS_EQUAL_TO_BOOLEAN.test(expectedCallExpression)
val isNotEqualTo = IS_NOT_EQUAL_TO_BOOLEAN.test(expectedCallExpression)
if (isEqualTo || isNotEqualTo) {
val constValue = calculateConstantParameterValue(expectedCallExpression, 0) as? Boolean ?: return null
return isEqualTo xor constValue
}
}
return null
registerSplitBinaryExpressionMethod(holder, expression, "$replacementMethod()", pickRightOperand = swapExpectedAndActual)
}
private fun registerSplitBinaryExpressionMethod(
@@ -130,10 +90,4 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
}
}
}
private class Mapping(
val tokenType: IElementType,
val replacement: String,
val replacementInverted: String
)
}
@@ -30,11 +30,11 @@ class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() {
return
}
val equalToExpression = expression.firstArg
if (!TypeConversionUtil.isBooleanType(equalToExpression.type)) {
val expectedExpression = expression.firstArg
if (!TypeConversionUtil.isBooleanType(expectedExpression.type)) {
return
}
val expectedResult = calculateConstantParameterValue(expression, 0)as? Boolean ?: return
val expectedResult = calculateConstantParameterValue(expression, 0) as? Boolean ?: return
val flippedBooleanTest = matchingCalls.drop(2).any { it }
val replacementMethod = if (expectedResult xor flippedBooleanTest) "isTrue()" else "isFalse()"
@@ -0,0 +1,65 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.firstArg
class AssertThatJava8OptionalInspection : AbstractAssertJInspection() {
companion object {
private const val DISPLAY_NAME = "Asserting an Optional (Java 8)"
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
if (!ASSERT_THAT_ANY.test(expression)) {
return
}
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
if (ASSERT_THAT_JAVA8_OPTIONAL.test(expression)) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (OPTIONAL_OF.test(innerExpectedCall) || OPTIONAL_OF_NULLABLE.test(innerExpectedCall)) {
registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, "contains()")
} else if (OPTIONAL_EMPTY.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, "isNotPresent()")
}
} else if (IS_NOT_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (OPTIONAL_EMPTY.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, "isPresent()")
}
}
} else {
val actualExpression = expression.firstArg as? PsiMethodCallExpression ?: return
val isGet = OPTIONAL_GET.test(actualExpression)
val isIsPresent = OPTIONAL_IS_PRESENT.test(actualExpression)
if (isGet || isIsPresent) {
if (isGet) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, "contains()")
} else if (IS_SAME_AS_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, "containsSame()")
}
} else {
val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return
val replacementMethod = if (expectedPresence) "isPresent()" else "isNotPresent()"
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true)
}
}
}
}
}
}
}
@@ -10,7 +10,12 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
companion object {
private const val DISPLAY_NAME = "Asserting the size of an collection or array"
private const val MORE_CONCISE_MESSAGE_TEMPLATE = "%s would be more concise than %s"
private val BONUS_EXPRESSIONS_CALL_MATCHER_MAP = listOf(
IS_GREATER_THAN_INT to "hasSizeGreaterThan()",
IS_GREATER_THAN_OR_EQUAL_TO_INT to "hasSizeGreaterThanOrEqualTo()",
IS_LESS_THAN_OR_EQUAL_TO_INT to "hasSizeLessThanOrEqualTo()",
IS_LESS_THAN_INT to "hasSizeLessThan()"
)
}
override fun getDisplayName() = DISPLAY_NAME
@@ -30,41 +35,29 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
val constValue = calculateConstantParameterValue(expectedCallExpression, 0)
if (IS_EQUAL_TO_INT.test(expectedCallExpression)) {
if (constValue == 0) {
registerSizeMethod(holder, expression, expectedCallExpression, "isEmpty()", noExpectedExpression = true)
return
registerReplaceSizeMethod(holder, expression, expectedCallExpression, "isEmpty()", noExpectedExpression = true)
} else {
val equalToExpression = expectedCallExpression.firstArg
if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, "hasSameSizeAs()", expectedIsCollection = true)
} else {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, "hasSize()")
}
}
val equalToExpression = expectedCallExpression.firstArg
if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) {
registerSizeMethod(holder, expression, expectedCallExpression, "hasSameSizeAs()", expectedIsCollection = true)
return
}
registerSizeMethod(holder, expression, expectedCallExpression, "hasSize()")
} else {
if ((IS_LESS_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 0))
|| (IS_LESS_THAN_INT.test(expectedCallExpression) && (constValue == 1))
|| IS_ZERO.test(expectedCallExpression)
) {
registerSizeMethod(holder, expression, expectedCallExpression, "isEmpty()", noExpectedExpression = true)
return
}
if ((IS_GREATER_THAN_INT.test(expectedCallExpression) && (constValue == 0))
|| (IS_GREATER_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 1))
|| IS_NOT_ZERO.test(expectedCallExpression)
) {
registerSizeMethod(holder, expression, expectedCallExpression, "isNotEmpty()", noExpectedExpression = true)
return
}
// new stuff in AssertJ 13.2.0
if (hasAssertJMethod(expression, "AbstractIterableAssert.hasSizeLessThan")) {
val matchedMethod = listOf(
IS_GREATER_THAN_INT to "hasSizeGreaterThan()",
IS_GREATER_THAN_OR_EQUAL_TO_INT to "hasSizeGreaterThanOrEqualTo()",
IS_LESS_THAN_OR_EQUAL_TO_INT to "hasSizeLessThanOrEqualTo()",
IS_LESS_THAN_INT to "hasSizeLessThan()"
).find { it.first.test(expectedCallExpression) }?.second
if (matchedMethod != null) {
registerSizeMethod(holder, expression, expectedCallExpression, matchedMethod)
return
val isTestForEmpty = ((IS_LESS_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 0))
|| (IS_LESS_THAN_INT.test(expectedCallExpression) && (constValue == 1))
|| IS_ZERO.test(expectedCallExpression))
val isTestForNotEmpty = ((IS_GREATER_THAN_INT.test(expectedCallExpression) && (constValue == 0))
|| (IS_GREATER_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 1))
|| IS_NOT_ZERO.test(expectedCallExpression))
when {
isTestForEmpty -> registerReplaceSizeMethod(holder, expression, expectedCallExpression, "isEmpty()", noExpectedExpression = true)
isTestForNotEmpty -> registerReplaceSizeMethod(holder, expression, expectedCallExpression, "isNotEmpty()", noExpectedExpression = true)
// new stuff in AssertJ 13.2.0
hasAssertJMethod(expression, "AbstractIterableAssert.hasSizeLessThan") -> {
val matchedMethod = BONUS_EXPRESSIONS_CALL_MATCHER_MAP.find { it.first.test(expectedCallExpression) }?.second ?: return
registerReplaceSizeMethod(holder, expression, expectedCallExpression, matchedMethod)
}
}
}
@@ -79,7 +72,7 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
&& ((psiReferenceExpression.resolve() as? PsiField)?.name == "length"))
}
private fun registerSizeMethod(
private fun registerReplaceSizeMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression,
@@ -0,0 +1,36 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.qualifierExpression
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class RemoveActualOutmostMethodCallQuickFix(
description: String,
private val replacementMethod: String,
private val noExpectedExpression: Boolean
) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement
val methodCallExpression = element as? PsiMethodCallExpression ?: return
val assertExpression = methodCallExpression.firstArg as? PsiMethodCallExpression ?: return
assertExpression.replace(assertExpression.qualifierExpression)
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression =
factory.createExpressionFromText("a.${if (noExpectedExpression) replacementMethod else replacementMethod.replace("()", "(e)")}", element) as PsiMethodCallExpression
if (!noExpectedExpression) {
expectedExpression.firstArg.replace(oldExpectedExpression.firstArg)
}
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression)
}
}
@@ -0,0 +1,27 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class ReplaceExpectedOutmostMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression =
factory.createExpressionFromText("a.${replacementMethod.replace("()", "(e)")}", element) as PsiMethodCallExpression
val expectedMethodCallExpression = oldExpectedExpression.firstArg as? PsiMethodCallExpression ?: return
expectedExpression.firstArg.replace(expectedMethodCallExpression.firstArg)
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression)
}
}