Implemented AssertThatBooleanIsTrueOrFalseInspection.
This commit is contained in:
		
							parent
							
								
									80104004d0
								
							
						
					
					
						commit
						8051511524
					
				| @ -19,12 +19,12 @@ This makes finding bugs and fixing failed tests easier. | ||||
| - AssertThatObjectIsNotNull | ||||
|   > from: assertThat(object).isNotEqualTo(null); | ||||
|   >   to: assertThat(object).isNotNull(); | ||||
| 
 | ||||
| ## TODO | ||||
| - AssertThatBooleanIsTrueOrFalse | ||||
|   > from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE); | ||||
|   >   to: assertThat(booleanValue).isTrue()/isFalse(); | ||||
| - AssertThatStringEmpty | ||||
| 
 | ||||
| ## TODO | ||||
| - AssertThatStringIsEmpty | ||||
|   > from: assertThat(string).isEqualTo("") | ||||
|   >   to: assertThat(string).isEmpty(); | ||||
| - AssertThatArrayHasLiteralSize | ||||
|  | ||||
| @ -7,14 +7,19 @@ import com.siyeh.ig.callMatcher.CallMatcher | ||||
| open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() { | ||||
| 
 | ||||
|     companion object { | ||||
|         private const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert" | ||||
|         private const val IS_EQUAL_TO = "isEqualTo" | ||||
|         private const val IS_NOT_EQUAL_TO = "isNotEqualTo" | ||||
|         const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert" | ||||
|         const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert" | ||||
|         const val IS_EQUAL_TO = "isEqualTo" | ||||
|         const val IS_NOT_EQUAL_TO = "isNotEqualTo" | ||||
| 
 | ||||
|         val IS_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_EQUAL_TO) | ||||
|             .parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! | ||||
|         val IS_NOT_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_NOT_EQUAL_TO) | ||||
|             .parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! | ||||
|         val IS_EQUAL_TO_BOOLEAN = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_EQUAL_TO) | ||||
|             .parameterTypes("boolean")!! | ||||
|         val IS_NOT_EQUAL_TO_BOOLEAN = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_NOT_EQUAL_TO) | ||||
|             .parameterTypes("boolean")!! | ||||
|     } | ||||
| 
 | ||||
|     override fun getGroupDisplayName(): String { | ||||
|  | ||||
| @ -0,0 +1,96 @@ | ||||
| package de.platon42.intellij.plugins.cajon.inspections | ||||
| 
 | ||||
| import com.intellij.codeInspection.LocalQuickFix | ||||
| import com.intellij.codeInspection.ProblemDescriptor | ||||
| import com.intellij.codeInspection.ProblemHighlightType | ||||
| import com.intellij.codeInspection.ProblemsHolder | ||||
| import com.intellij.openapi.project.Project | ||||
| import com.intellij.openapi.util.TextRange | ||||
| import com.intellij.psi.* | ||||
| import com.intellij.psi.util.TypeConversionUtil | ||||
| import org.jetbrains.annotations.NonNls | ||||
| 
 | ||||
| class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() { | ||||
| 
 | ||||
|     companion object { | ||||
|         @NonNls | ||||
|         private val DISPLAY_NAME = "Asserting true or false" | ||||
| 
 | ||||
|         @NonNls | ||||
|         private val INSPECTION_MESSAGE = "isEqualTo(true/false) can be simplified to isTrue()/isFalse()" | ||||
| 
 | ||||
|         @NonNls | ||||
|         private val QUICKFIX_DESCRIPTION_IS_TRUE = "Replace isEqualTo(true/false) with isTrue()/isFalse()" | ||||
| 
 | ||||
|         @NonNls | ||||
|         private val QUICKFIX_DESCRIPTION_NOT_IS_TRUE = "Replace isNotEqualTo(true/false) with isFalse()/isTrue()" | ||||
|     } | ||||
| 
 | ||||
|     override fun getDisplayName() = DISPLAY_NAME | ||||
| 
 | ||||
|     override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { | ||||
|         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)) { | ||||
|                     return | ||||
|                 } | ||||
|                 var assertedType = expression.methodExpression.qualifierExpression?.type | ||||
|                 if (assertedType is PsiCapturedWildcardType) { | ||||
|                     assertedType = assertedType.upperBound | ||||
|                 } | ||||
|                 val assertedTypeIsBoolean = | ||||
|                     assertedType?.canonicalText?.startsWith(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME) ?: false | ||||
|                 val equalToExpression = expression.argumentList.expressions[0]!! | ||||
|                 if (!TypeConversionUtil.isBooleanType(equalToExpression.type) || !assertedTypeIsBoolean) { | ||||
|                     return | ||||
|                 } | ||||
|                 val constantEvaluationHelper = JavaPsiFacade.getInstance(holder.project).constantEvaluationHelper | ||||
|                 var result = constantEvaluationHelper.computeConstantExpression(equalToExpression) | ||||
|                 if (result == null) { | ||||
|                     val field = (equalToExpression as? PsiReferenceExpression)?.resolve() as? PsiField | ||||
|                     if (field?.containingClass?.qualifiedName == CommonClassNames.JAVA_LANG_BOOLEAN) { | ||||
|                         when { | ||||
|                             field.name == "TRUE" -> result = true | ||||
|                             field.name == "FALSE" -> result = false | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 val expectedResult = result as? Boolean ?: return | ||||
|                 holder.registerProblem( | ||||
|                     expression, | ||||
|                     INSPECTION_MESSAGE, | ||||
|                     ProblemHighlightType.INFORMATION, | ||||
|                     null as TextRange?, | ||||
|                     ReplaceWithIsNullQuickFix( | ||||
|                         expectedResult xor flippedBooleanTest, | ||||
|                         if (flippedBooleanTest) QUICKFIX_DESCRIPTION_NOT_IS_TRUE else QUICKFIX_DESCRIPTION_IS_TRUE | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private class ReplaceWithIsNullQuickFix(val expectedResult: Boolean, val quickfixName: String) : LocalQuickFix { | ||||
|         override fun getFamilyName() = quickfixName | ||||
| 
 | ||||
|         override fun applyFix(project: Project, descriptor: ProblemDescriptor) { | ||||
|             val element = descriptor.startElement | ||||
|             val factory = JavaPsiFacade.getElementFactory(element.project) | ||||
|             val methodCallExpression = element as? PsiMethodCallExpression ?: return | ||||
|             val oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return | ||||
|             val methodName = if (expectedResult) "isTrue()" else "isFalse()" | ||||
|             val isNullExpression = | ||||
|                 factory.createExpressionFromText("a.$methodName", null) as PsiMethodCallExpression | ||||
|             isNullExpression.methodExpression.qualifierExpression!!.replace(oldQualifier) | ||||
|             element.replace(isNullExpression) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -13,7 +13,7 @@ class AssertThatObjectIsNotNullInspection : AbstractAssertJInspection() { | ||||
| 
 | ||||
|     companion object { | ||||
|         @NonNls | ||||
|         private val DISPLAY_NAME = "Comparing to non-null" | ||||
|         private val DISPLAY_NAME = "Asserting non-null" | ||||
| 
 | ||||
|         @NonNls | ||||
|         private val INSPECTION_MESSAGE = "isNotEqualTo(null) can be simplified to isNotNull()" | ||||
|  | ||||
| @ -13,7 +13,7 @@ class AssertThatObjectIsNullInspection : AbstractAssertJInspection() { | ||||
| 
 | ||||
|     companion object { | ||||
|         @NonNls | ||||
|         private val DISPLAY_NAME = "Comparing to null" | ||||
|         private val DISPLAY_NAME = "Asserting null" | ||||
| 
 | ||||
|         @NonNls | ||||
|         private val INSPECTION_MESSAGE = "isEqualTo(null) can be simplified to isNull()" | ||||
|  | ||||
| @ -22,6 +22,9 @@ | ||||
|                          implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatObjectIsNullInspection"/> | ||||
|         <localInspection groupPath="Java" shortName="AssertThatObjectIsNotNull" enabledByDefault="true" level="WARNING" | ||||
|                          implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatObjectIsNotNullInspection"/> | ||||
|         <localInspection groupPath="Java" shortName="AssertThatBooleanIsTrueOrFalse" enabledByDefault="true" | ||||
|                          level="WARNING" | ||||
|                          implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatBooleanIsTrueOrFalseInspection"/> | ||||
|     </extensions> | ||||
| 
 | ||||
|     <actions> | ||||
|  | ||||
| @ -0,0 +1,7 @@ | ||||
| <html> | ||||
| <body> | ||||
| Turns assertThat(booleanExpression).isEqualTo(true/false) or assertThat(booleanExpression).isNotEqualTo(true/false) | ||||
| into assertThat(booleanExpression).isTrue() or assertThat(booleanExpression).isFalse(). | ||||
| <!-- tooltip end --> | ||||
| </body> | ||||
| </html> | ||||
| @ -14,5 +14,38 @@ public class Playground { | ||||
|         assertThat(new String[1].length).isLessThanOrEqualTo(1); | ||||
|         assertThat(new String[1]).hasSameSizeAs(new Object()); | ||||
|         assertThat("").isEqualTo(null); | ||||
|         assertThat(true).isTrue(); | ||||
|         assertThat(true).isEqualTo(true); | ||||
|         assertThat(Boolean.TRUE).isEqualTo(Boolean.FALSE); | ||||
|         assertThat(Boolean.TRUE).isEqualTo(true); | ||||
|     } | ||||
| 
 | ||||
|     private void booleanIsTrueOrFalse() { | ||||
|         boolean primitive = false; | ||||
|         Boolean object = java.lang.Boolean.TRUE; | ||||
| 
 | ||||
|         assertThat(primitive).isEqualTo(Boolean.TRUE); | ||||
|         assertThat(primitive).isEqualTo(Boolean.FALSE); | ||||
|         assertThat(object).isEqualTo(Boolean.TRUE); | ||||
|         assertThat(object).isEqualTo(Boolean.FALSE); | ||||
|         assertThat(primitive).isEqualTo(true); | ||||
|         assertThat(primitive).isEqualTo(false); | ||||
|         assertThat(object).isEqualTo(true); | ||||
|         assertThat(object).isEqualTo(false); | ||||
| 
 | ||||
|         assertThat(primitive).isNotEqualTo(Boolean.TRUE); | ||||
|         assertThat(primitive).isNotEqualTo(Boolean.FALSE); | ||||
|         assertThat(object).isNotEqualTo(Boolean.TRUE); | ||||
|         assertThat(object).isNotEqualTo(Boolean.FALSE); | ||||
|         assertThat(primitive).isNotEqualTo(true); | ||||
|         assertThat(primitive).isNotEqualTo(false); | ||||
|         assertThat(object).isNotEqualTo(true); | ||||
|         assertThat(object).isNotEqualTo(false); | ||||
| 
 | ||||
|         assertThat(primitive).as("nah").isEqualTo(true && !true); | ||||
|         assertThat(object).isEqualTo(Boolean.TRUE && !Boolean.TRUE); | ||||
| 
 | ||||
|         assertThat("").isEqualTo(Boolean.TRUE); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -59,8 +59,8 @@ abstract class AbstractCajonTest { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected fun executeQuickFixes(myFixture: JavaCodeInsightTestFixture, expectedFixes: Int) { | ||||
|         val quickfixes = myFixture.getAllQuickFixes() | ||||
|     protected fun executeQuickFixes(myFixture: JavaCodeInsightTestFixture, regex: Regex, expectedFixes: Int) { | ||||
|         val quickfixes = myFixture.getAllQuickFixes().filter { it.familyName.matches(regex) } | ||||
|         assertThat(quickfixes).hasSize(expectedFixes) | ||||
|         quickfixes.forEach(myFixture::launchAction) | ||||
|     } | ||||
|  | ||||
| @ -0,0 +1,21 @@ | ||||
| package de.platon42.intellij.plugins.cajon.inspections | ||||
| 
 | ||||
| import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture | ||||
| import de.platon42.intellij.jupiter.MyFixture | ||||
| import de.platon42.intellij.jupiter.TestDataSubPath | ||||
| import de.platon42.intellij.plugins.cajon.AbstractCajonTest | ||||
| import org.junit.jupiter.api.Test | ||||
| 
 | ||||
| internal class AssertThatBooleanIsTrueOrFalseInspectionTest : AbstractCajonTest() { | ||||
| 
 | ||||
|     @Test | ||||
|     @TestDataSubPath("inspections/BooleanIsTrueOrFalse") | ||||
|     internal fun assertThat_with_isEqualTo_true_or_false_can_use_isTrue_or_isFalse(@MyFixture myFixture: JavaCodeInsightTestFixture) { | ||||
|         runTest { | ||||
|             myFixture.enableInspections(AssertThatBooleanIsTrueOrFalseInspection::class.java) | ||||
|             myFixture.configureByFile("BooleanIsTrueOrFalseBefore.java") | ||||
|             executeQuickFixes(myFixture, Regex("Replace is.*"), 17) | ||||
|             myFixture.checkResultByFile("BooleanIsTrueOrFalseAfter.java") | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -14,7 +14,7 @@ internal class AssertThatObjectIsNotNullInspectionTest : AbstractCajonTest() { | ||||
|         runTest { | ||||
|             myFixture.enableInspections(AssertThatObjectIsNotNullInspection::class.java) | ||||
|             myFixture.configureByFile("ObjectIsNotNullBefore.java") | ||||
|             executeQuickFixes(myFixture, 3) | ||||
|             executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo(null) with isNotNull()"), 3) | ||||
|             myFixture.checkResultByFile("ObjectIsNotNullAfter.java") | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -14,7 +14,7 @@ internal class AssertThatObjectIsNullInspectionTest : AbstractCajonTest() { | ||||
|         runTest { | ||||
|             myFixture.enableInspections(AssertThatObjectIsNullInspection::class.java) | ||||
|             myFixture.configureByFile("ObjectIsNullBefore.java") | ||||
|             executeQuickFixes(myFixture, 3) | ||||
|             executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo(null) with isNull()"), 3) | ||||
|             myFixture.checkResultByFile("ObjectIsNullAfter.java") | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -0,0 +1,32 @@ | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class BooleanIsTrueOrFalse { | ||||
| 
 | ||||
|     private void booleanIsTrueOrFalse() { | ||||
|         boolean primitive = false; | ||||
|         Boolean object = Boolean.TRUE; | ||||
| 
 | ||||
|         assertThat(primitive).isTrue(); | ||||
|         assertThat(primitive).isFalse(); | ||||
|         assertThat(object).isTrue(); | ||||
|         assertThat(object).isFalse(); | ||||
|         assertThat(primitive).isTrue(); | ||||
|         assertThat(primitive).isFalse(); | ||||
|         assertThat(object).isTrue(); | ||||
|         assertThat(object).isFalse(); | ||||
| 
 | ||||
|         assertThat(primitive).isFalse(); | ||||
|         assertThat(primitive).isTrue(); | ||||
|         assertThat(object).isFalse(); | ||||
|         assertThat(object).isTrue(); | ||||
|         assertThat(primitive).isFalse(); | ||||
|         assertThat(primitive).isTrue(); | ||||
|         assertThat(object).isFalse(); | ||||
|         assertThat(object).isTrue(); | ||||
| 
 | ||||
|         assertThat(primitive).as("nah").isFalse(); | ||||
|         assertThat(object).isEqualTo(Boolean.TRUE && !Boolean.TRUE); | ||||
| 
 | ||||
|         assertThat("").isEqualTo(Boolean.TRUE); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,32 @@ | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class BooleanIsTrueOrFalse { | ||||
| 
 | ||||
|     private void booleanIsTrueOrFalse() { | ||||
|         boolean primitive = false; | ||||
|         Boolean object = Boolean.TRUE; | ||||
| 
 | ||||
|         assertThat(primitive).isEqualTo(Boolean.TRUE); | ||||
|         assertThat(primitive).isEqualTo(Boolean.FALSE); | ||||
|         assertThat(object).isEqualTo(Boolean.TRUE); | ||||
|         assertThat(object).isEqualTo(Boolean.FALSE); | ||||
|         assertThat(primitive).isEqualTo(true); | ||||
|         assertThat(primitive).isEqualTo(false); | ||||
|         assertThat(object).isEqualTo(true); | ||||
|         assertThat(object).isEqualTo(false); | ||||
| 
 | ||||
|         assertThat(primitive).isNotEqualTo(Boolean.TRUE); | ||||
|         assertThat(primitive).isNotEqualTo(Boolean.FALSE); | ||||
|         assertThat(object).isNotEqualTo(Boolean.TRUE); | ||||
|         assertThat(object).isNotEqualTo(Boolean.FALSE); | ||||
|         assertThat(primitive).isNotEqualTo(true); | ||||
|         assertThat(primitive).isNotEqualTo(false); | ||||
|         assertThat(object).isNotEqualTo(true); | ||||
|         assertThat(object).isNotEqualTo(false); | ||||
| 
 | ||||
|         assertThat(primitive).as("nah").isEqualTo(true && !true); | ||||
|         assertThat(object).isEqualTo(Boolean.TRUE && !Boolean.TRUE); | ||||
| 
 | ||||
|         assertThat("").isEqualTo(Boolean.TRUE); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user