Optimized code. More kotlin-style stuff. Made detecting of Boolean.TRUE/FALSE available to all constant evaluations.

This commit is contained in:
2019-04-08 11:56:13 +02:00
parent bdabcc7255
commit c1d8ade7b1
15 changed files with 154 additions and 127 deletions
@@ -6,6 +6,8 @@ import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
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.ReplaceSimpleMethodCallQuickFix
import org.jetbrains.annotations.NonNls
@@ -110,8 +112,8 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
}
protected fun checkAssertedType(expression: PsiMethodCallExpression, classname: String): Boolean {
var assertedType = expression.methodExpression.qualifierExpression?.type ?: return false
if (assertedType is PsiCapturedWildcardType) {
var assertedType = expression.qualifierExpression.type ?: return false
while (assertedType is PsiCapturedWildcardType) {
assertedType = assertedType.upperBound
}
val assertedClass = PsiTypesUtil.getPsiClass(assertedType) ?: return false
@@ -131,18 +133,26 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = SIMPLIFY_MESSAGE_TEMPLATE.format(originalMethod, replacementMethod)
holder.registerProblem(
expression,
message,
ReplaceSimpleMethodCallQuickFix(description, replacementMethod)
)
val quickFix = ReplaceSimpleMethodCallQuickFix(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.argumentList.expressions[argIndex] ?: return null
val valueExpression = expression.getArg(argIndex)
val constantEvaluationHelper = JavaPsiFacade.getInstance(expression.project).constantEvaluationHelper
return constantEvaluationHelper.computeConstantExpression(valueExpression)
val value = constantEvaluationHelper.computeConstantExpression(valueExpression)
if (value == null) {
val field = (valueExpression as? PsiReferenceExpression)?.resolve() as? PsiField
if (field?.containingClass?.qualifiedName == CommonClassNames.JAVA_LANG_BOOLEAN) {
return when (field.name) {
"TRUE" -> true
"FALSE" -> false
else -> null
}
}
}
return value
}
protected fun hasAssertJMethod(element: PsiElement, classAndMethod: String): Boolean {
@@ -5,6 +5,7 @@ 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
import de.platon42.intellij.plugins.cajon.quickfixes.SplitBinaryExpressionMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.SplitEqualsExpressionMethodCallQuickFix
@@ -26,19 +27,17 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
Mapping(JavaTokenType.LE, "isLessThanOrEqualTo()", "isGreaterThan()")
)
private val PRIMITIVE_MAPPINGS_SWAPPED = listOf(
Mapping(JavaTokenType.EQEQ, "isEqualTo()", "isNotEqualTo()"),
Mapping(JavaTokenType.NE, "isNotEqualTo()", "isEqualTo()"),
Mapping(JavaTokenType.GT, "isLessThan()", "isGreaterThanOrEqualTo()"),
Mapping(JavaTokenType.GE, "isLessThanOrEqualTo()", "isGreaterThan()"),
Mapping(JavaTokenType.LT, "isGreaterThan()", "isLessThanOrEqualTo()"),
Mapping(JavaTokenType.LE, "isGreaterThanOrEqualTo()", "isLessThan()")
)
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
@@ -55,14 +54,11 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val isInverted = getExpectedResult(expectedCallExpression) ?: return
val assertThatArgument = expression.argumentList.expressions[0] ?: return
val assertThatArgument = expression.firstArg
if (assertThatArgument is PsiMethodCallExpression && OBJECT_EQUALS.test(assertThatArgument)) {
val replacementMethod = if (isInverted) "isNotEqualTo()" else "isEqualTo()"
holder.registerProblem(
expression,
EQUALS_MORE_MEANINGFUL_MESSAGE,
SplitEqualsExpressionMethodCallQuickFix(SPLIT_EQUALS_EXPRESSION_DESCRIPTION, replacementMethod)
)
val quickFix = SplitEqualsExpressionMethodCallQuickFix(SPLIT_EQUALS_EXPRESSION_DESCRIPTION, replacementMethod)
holder.registerProblem(expression, EQUALS_MORE_MEANINGFUL_MESSAGE, quickFix)
return
}
@@ -71,8 +67,8 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
val leftType = binaryExpression.lOperand.type ?: return
val rightType = binaryExpression.rOperand?.type ?: return
val isLeftNull = TypeConversionUtil.isNullType(leftType)
val isRightNull = TypeConversionUtil.isNullType(rightType)
val bothTypes = listOf(leftType, rightType)
val (isLeftNull, isRightNull) = bothTypes.map(TypeConversionUtil::isNullType)
if (isLeftNull && isRightNull) {
return
} else if (isLeftNull || isRightNull) {
@@ -86,15 +82,17 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
return
}
val isPrimitive = TypeConversionUtil.isPrimitiveAndNotNull(leftType) && TypeConversionUtil.isPrimitiveAndNotNull(rightType)
val isNumericType = TypeConversionUtil.isNumericType(leftType) && TypeConversionUtil.isNumericType(rightType)
val isPrimitive = bothTypes.all(TypeConversionUtil::isPrimitiveAndNotNull)
val isNumericType = bothTypes.all(TypeConversionUtil::isNumericType)
val constantEvaluationHelper = JavaPsiFacade.getInstance(expression.project).constantEvaluationHelper
val swapExpectedAndActual = constantEvaluationHelper.computeConstantExpression(binaryExpression.lOperand) != null
val tokenType = binaryExpression.operationSign.tokenType
val tokenType = binaryExpression.operationSign.tokenType.let {
if (swapExpectedAndActual) SWAP_BINARY_OPERATOR.getOrDefault(it, it) else it
} ?: return
val mappingToUse =
if (isPrimitive || isNumericType) {
if (swapExpectedAndActual) PRIMITIVE_MAPPINGS_SWAPPED else PRIMITIVE_MAPPINGS
PRIMITIVE_MAPPINGS
} else {
OBJECT_MAPPINGS
}
@@ -127,11 +125,8 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
pickRightOperand: Boolean = false,
noExpectedExpression: Boolean = false
) {
holder.registerProblem(
expression,
BINARY_MORE_MEANINGFUL_MESSAGE,
SplitBinaryExpressionMethodCallQuickFix(SPLIT_BINARY_EXPRESSION_DESCRIPTION, replacementMethod, pickRightOperand, noExpectedExpression)
)
val quickFix = SplitBinaryExpressionMethodCallQuickFix(SPLIT_BINARY_EXPRESSION_DESCRIPTION, replacementMethod, pickRightOperand, noExpectedExpression)
holder.registerProblem(expression, BINARY_MORE_MEANINGFUL_MESSAGE, quickFix)
}
}
}
@@ -1,8 +1,11 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.util.TypeConversionUtil
import de.platon42.intellij.plugins.cajon.firstArg
class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() {
@@ -16,34 +19,23 @@ class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() {
return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
val isEqualToObject = IS_EQUAL_TO_OBJECT.test(expression)
val isEqualToBoolean = IS_EQUAL_TO_BOOLEAN.test(expression)
val isNotEqualToObject = IS_NOT_EQUAL_TO_OBJECT.test(expression)
val isNotEqualToBoolean = IS_NOT_EQUAL_TO_BOOLEAN.test(expression)
val normalBooleanTest = isEqualToObject || isEqualToBoolean
val flippedBooleanTest = isNotEqualToObject || isNotEqualToBoolean
if (!(normalBooleanTest || flippedBooleanTest)) {
val matchingCalls = listOf(
IS_EQUAL_TO_OBJECT, IS_EQUAL_TO_BOOLEAN,
IS_NOT_EQUAL_TO_OBJECT, IS_NOT_EQUAL_TO_BOOLEAN
).map { it.test(expression) }
if (matchingCalls.none { it }) {
return
}
if (!checkAssertedType(expression, ABSTRACT_BOOLEAN_ASSERT_CLASSNAME)) {
return
}
val equalToExpression = expression.argumentList.expressions[0] ?: return
val equalToExpression = expression.firstArg
if (!TypeConversionUtil.isBooleanType(equalToExpression.type)) {
return
}
var value = calculateConstantParameterValue(expression, 0)
if (value == null) {
val field = (equalToExpression as? PsiReferenceExpression)?.resolve() as? PsiField
if (field?.containingClass?.qualifiedName == CommonClassNames.JAVA_LANG_BOOLEAN) {
when {
field.name == "TRUE" -> value = true
field.name == "FALSE" -> value = false
}
}
}
val expectedResult = value 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()"
registerSimplifyMethod(holder, expression, replacementMethod)
@@ -17,8 +17,7 @@ class AssertThatEnumerableIsEmptyInspection : AbstractAssertJInspection() {
return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
val hasSize = HAS_SIZE.test(expression)
if (!hasSize) {
if (!HAS_SIZE.test(expression)) {
return
}
@@ -5,6 +5,7 @@ import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiType
import de.platon42.intellij.plugins.cajon.firstArg
class AssertThatObjectIsNullOrNotNullInspection : AbstractAssertJInspection() {
@@ -24,7 +25,7 @@ class AssertThatObjectIsNullOrNotNullInspection : AbstractAssertJInspection() {
return
}
if (expression.argumentList.expressions[0].type == PsiType.NULL) {
if (expression.firstArg.type == PsiType.NULL) {
registerSimplifyMethod(holder, expression, if (isEqualTo) "isNull()" else "isNotNull()")
}
}
@@ -3,6 +3,7 @@ package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSizeMethodCallQuickFix
class AssertThatSizeInspection : AbstractAssertJInspection() {
@@ -21,7 +22,7 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
if (!ASSERT_THAT_INT.test(expression)) {
return
}
val actualExpression = expression.argumentList.expressions[0] ?: return
val actualExpression = expression.firstArg
if (isArrayLength(actualExpression) || isCollectionSize(actualExpression)) {
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return
@@ -32,7 +33,7 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
registerSizeMethod(holder, expression, expectedCallExpression, "isEmpty()", noExpectedExpression = true)
return
}
val equalToExpression = expectedCallExpression.argumentList.expressions[0]
val equalToExpression = expectedCallExpression.firstArg
if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) {
registerSizeMethod(holder, expression, expectedCallExpression, "hasSameSizeAs()", expectedIsCollection = true)
return
@@ -56,10 +57,10 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
// new stuff in AssertJ 13.2.0
if (hasAssertJMethod(expression, "AbstractIterableAssert.hasSizeLessThan")) {
val matchedMethod = listOf(
Pair(IS_GREATER_THAN_INT, "hasSizeGreaterThan()"),
Pair(IS_GREATER_THAN_OR_EQUAL_TO_INT, "hasSizeGreaterThanOrEqualTo()"),
Pair(IS_LESS_THAN_OR_EQUAL_TO_INT, "hasSizeLessThanOrEqualTo()"),
Pair(IS_LESS_THAN_INT, "hasSizeLessThan()")
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)
@@ -89,11 +90,8 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod)
holder.registerProblem(
expression,
message,
ReplaceSizeMethodCallQuickFix(description, replacementMethod, noExpectedExpression, expectedIsCollection)
)
val quickfix = ReplaceSizeMethodCallQuickFix(description, replacementMethod, noExpectedExpression, expectedIsCollection)
holder.registerProblem(expression, message, quickfix)
}
}
}
@@ -142,11 +142,8 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
holder.registerProblem(
expression,
message,
ReplaceJUnitAssertMethodCallQuickFix(description, hasExpected, replacementMethod)
)
val quickFix = ReplaceJUnitAssertMethodCallQuickFix(description, hasExpected, replacementMethod)
holder.registerProblem(expression, message, quickFix)
}
private fun registerDeltaReplacementMethod(
@@ -157,11 +154,8 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
holder.registerProblem(
expression,
message,
ReplaceJUnitDeltaAssertMethodCallQuickFix(description, replacementMethod)
)
val quickFix = ReplaceJUnitDeltaAssertMethodCallQuickFix(description, replacementMethod)
holder.registerProblem(expression, message, quickFix)
}
private class Mapping(