Compare commits

..
4 Commits
38 changed files with 1092 additions and 400 deletions
+95 -38
View File
@@ -32,6 +32,15 @@ Then AssertJ would tell you the contents of the collection on failure.
The plugin also supports the conversion of the most common JUnit 4 assertions to AssertJ. The plugin also supports the conversion of the most common JUnit 4 assertions to AssertJ.
## Usage
The plugin will report inspections in your opened editor file as warnings.
You can then quick-fix these with your quick-fix hotkey (usually Alt-Return or Opt-Return).
Or, you can use the "Run Inspection by Name..." action to run one inspection on a bigger scope (e.g. the whole project).
You can toggle the various inspections in the Settings/Editor/Inspections in the AssertJ group.
## Implemented inspections ## Implemented inspections
- AssertThatObjectIsNullOrNotNull - AssertThatObjectIsNullOrNotNull
@@ -42,22 +51,26 @@ The plugin also supports the conversion of the most common JUnit 4 assertions to
from: assertThat(object).isNotEqualTo(null); from: assertThat(object).isNotEqualTo(null);
to: assertThat(object).isNotNull(); to: assertThat(object).isNotNull();
``` ```
- AssertThatBooleanIsTrueOrFalse - AssertThatBooleanIsTrueOrFalse
``` ```
from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE); from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE);
to: assertThat(booleanValue).isTrue()/isFalse(); to: assertThat(booleanValue).isTrue()/isFalse();
``` ```
- AssertThatStringIsEmpty - AssertThatStringIsEmpty
``` ```
from: assertThat(charSequence/string).isEqualTo(""); from: assertThat(charSequence/string).isEqualTo("");
from: assertThat(charSequence/string).hasSize(0); from: assertThat(charSequence/string).hasSize(0);
to: assertThat(charSequence/string).isEmpty(); to: assertThat(charSequence/string).isEmpty();
``` ```
- AssertThatEnumerableIsEmpty - AssertThatEnumerableIsEmpty
``` ```
from: assertThat(enumerable).hasSize(0); from: assertThat(enumerable).hasSize(0);
to: assertThat(enumerable).isEmpty(); to: assertThat(enumerable).isEmpty();
``` ```
- AssertThatSize - AssertThatSize
``` ```
from: assertThat(array.length).isEqualTo(0); from: assertThat(array.length).isEqualTo(0);
@@ -109,6 +122,35 @@ The plugin also supports the conversion of the most common JUnit 4 assertions to
``` ```
and many, many more combinations (more than 150). and many, many more combinations (more than 150).
- AssertThatJava8Optional
```
from: assertThat(opt.isPresent()).isEqualTo(true);
from: assertThat(opt.isPresent()).isNotEqualTo(false);
from: assertThat(opt.isPresent()).isTrue();
to: assertThat(opt).isPresent();
from: assertThat(opt.isPresent()).isEqualTo(false);
from: assertThat(opt.isPresent()).isNotEqualTo(true);
from: assertThat(opt.isPresent()).isFalse();
to: assertThat(opt).isNotPresent();
from: assertThat(opt.get()).isEqualTo("foo");
to: assertThat(opt).contains("foo");
from: assertThat(opt.get()).isSameAs("foo");
to: assertThat(opt).containsSame("foo");
from: assertThat(opt).isEqualTo(Optional.of("foo"));
from: assertThat(opt).isEqualTo(Optional.ofNullable("foo"));
to: assertThat(opt).contains("foo");
from: assertThat(opt).isEqualTo(Optional.empty());
to: assertThat(opt).isNotPresent();
from: assertThat(opt).isNotEqualTo(Optional.empty());
to: assertThat(opt).isPresent();
```
- JUnitAssertToAssertJ - JUnitAssertToAssertJ
``` ```
assertTrue(condition); assertTrue(condition);
@@ -137,51 +179,45 @@ The plugin also supports the conversion of the most common JUnit 4 assertions to
assertArrayEquals(message, expectedDoubleOrFloatArray, actualDoubleOrFloatArray, delta); assertArrayEquals(message, expectedDoubleOrFloatArray, actualDoubleOrFloatArray, delta);
``` ```
- AssertThatGuavaOptional
```
from: assertThat(opt.isPresent()).isEqualTo(true);
from: assertThat(opt.isPresent()).isNotEqualTo(false);
from: assertThat(opt.isPresent()).isTrue();
to: assertThat(opt).isPresent();
from: assertThat(opt.isPresent()).isEqualTo(false);
from: assertThat(opt.isPresent()).isNotEqualTo(true);
from: assertThat(opt.isPresent()).isFalse();
to: assertThat(opt).isAbsent();
from: assertThat(opt.get()).isEqualTo("foo");
to: assertThat(opt).contains("foo");
from: assertThat(opt).isEqualTo(Optional.of("foo"));
from: assertThat(opt).isEqualTo(Optional.fromNullable("foo"));
to: assertThat(opt).contains("foo");
from: assertThat(opt).isEqualTo(Optional.absent());
to: assertThat(opt).isAbsent();
from: assertThat(opt).isNotEqualTo(Optional.absent());
to: assertThat(opt).isPresent();
```
AssertJ for Guava needs to be available in the classpath.
## Development notice ## Development notice
Cajon is written in Kotlin 1.3.
Cajon is probably the only plugin that uses JUnit 5 Jupiter for unit testing so far (or at least the only one that I'm aware of ;) ). Cajon is probably the only plugin that uses JUnit 5 Jupiter for unit testing so far (or at least the only one that I'm aware of ;) ).
The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing and I took me quite a while to make it work with JUnit 5. The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing and I took me quite a while to make it work with JUnit 5.
Feel free to use the code (in package de.platon42.intellij.jupiter) for your projects (with attribution). Feel free to use the code (in package de.platon42.intellij.jupiter) for your projects (with attribution).
## TODO ## TODO
- AssertThatJava8OptionalContains - AssertThatNegatedBooleanExpression
``` - AssertThatInstanceOf
from: assertThat(Optional.of("foo").get()).isEqualTo("foo");
to: assertThat(Optional.of("foo")).contains("foo");
```
- AssertThatJava8OptionalIsPresentOrAbsent
```
from: assertThat(Optional.of("foo").isPresent()).isEqualTo(true);
from: assertThat(!Optional.of("foo").isPresent()).isEqualTo(false);
from: assertThat(Optional.of("foo").isPresent()).isTrue();
from: assertThat(!Optional.of("foo").isPresent()).isFalse();
to: assertThat(Optional.of("foo")).isPresent();
from: assertThat(Optional.of("foo").isPresent()).isEqualTo(false);
from: assertThat(!Optional.of("foo").isPresent()).isEqualTo(true);
from: assertThat(Optional.of("foo").isPresent()).isFalse();
from: assertThat(!Optional.of("foo").isPresent()).isTrue();
to: assertThat(Optional.of("foo")).isNotPresent();
```
- AssertThatGuavaOptionalContains
```
from: assertThat(Optional.of("foo").get()).isEqualTo("foo");
to: assertThat(Optional.of("foo")).contains("foo");
```
- AssertThatGuavaOptionalIsPresentOrAbsent
```
from: assertThat(Optional.of("foo").isPresent()).isEqualTo(true);
from: assertThat(!Optional.of("foo").isPresent()).isEqualTo(false);
from: assertThat(Optional.of("foo").isPresent()).isTrue();
from: assertThat(!Optional.of("foo").isPresent()).isFalse();
to: assertThat(Optional.of("foo")).isPresent();
from: assertThat(Optional.of("foo").isPresent()).isEqualTo(false);
from: assertThat(!Optional.of("foo").isPresent()).isEqualTo(true);
from: assertThat(Optional.of("foo").isPresent()).isFalse();
from: assertThat(!Optional.of("foo").isPresent()).isTrue();
to: assertThat(Optional.of("foo")).isAbsent();
```
- Referencing string properties inside extracting() - Referencing string properties inside extracting()
- Extraction with property names to lambda with Java 8 - Extraction with property names to lambda with Java 8
``` ```
@@ -189,3 +225,24 @@ Feel free to use the code (in package de.platon42.intellij.jupiter) for your pro
to: assertThat(object).extracting(type::getPropOne, it -> it.propNoGetter, it -> it.getPropTwo().getInnerProp())... to: assertThat(object).extracting(type::getPropOne, it -> it.propNoGetter, it -> it.getPropTwo().getInnerProp())...
``` ```
- Kotlin support - Kotlin support
## Changelog
#### V0.4 (11-Apr-19)
- Reduced minimal supported IDEA version from 2018.2 to 2017.2.
- New inspection AssertThatJava8Optional that operates on Java 8 Optional objects and tries to use contains(), containsSame(), isPresent(), and isNotPresent() instead.
- New inspection AssertThatGuavaOptional that operates on Guava Optional objects and tries to use contains(), isPresent(), and isAbsent() instead.
- Added support in AssertThatBinaryExpressionIsTrueOrFalse for is(Not)EqualTo(Boolean.TRUE/FALSE).
#### V0.3 (07-Apr-19)
- New inspection AssertThatBinaryExpressionIsTrueOrFalse that will find and fix common binary expressions and equals() statements (more than 150 combinations) inside assertThat().
- Merged AssertThatObjectIsNull and AssertThatObjectIsNotNull to AssertThatObjectIsNullOrNotNull.
- Support for hasSizeLessThan(), hasSizeLessThanOrEqualTo(), hasSizeGreaterThanOrEqualTo(), and hasSizeGreaterThan() for AssertThatSizeInspection (with AssertJ >=13.2.0).
- Really fixed highlighting for JUnit conversion. Sorry.
#### V0.2 (01-Apr-19)
- Fixed descriptions and quick fix texts.
- Fixed highlighting of found problems and also 'Run inspection by Name' returning nothing.
#### V0.1 (31-Mar-19)
- Initial release.
+9 -11
View File
@@ -1,11 +1,11 @@
plugins { plugins {
id 'java' id 'java'
id 'org.jetbrains.intellij' version '0.4.3' id 'org.jetbrains.intellij' version '0.4.3'
id 'org.jetbrains.kotlin.jvm' version '1.3.21' id 'org.jetbrains.kotlin.jvm' version '1.3.30'
} }
group 'de.platon42' group 'de.platon42'
version '0.3' version '0.4'
repositories { repositories {
mavenCentral() mavenCentral()
@@ -41,6 +41,13 @@ intellij {
patchPluginXml { patchPluginXml {
changeNotes """ changeNotes """
<h4>V0.4 (11-Apr-19)</h4>
<ul>
<li>Reduced minimal supported IDEA version from 2018.2 to 2017.2.
<li>New inspection AssertThatJava8Optional that operates on Java 8 Optional objects and tries to use contains(), containsSame(), isPresent(), and isNotPresent() instead.
<li>New inspection AssertThatGuavaOptional that operates on Guava Optional objects and tries to use contains(), isPresent(), and isAbsent() instead.
<li>Added support in AssertThatBinaryExpressionIsTrueOrFalse for is(Not)EqualTo(Boolean.TRUE/FALSE).
</ul>
<h4>V0.3 (07-Apr-19)</h4> <h4>V0.3 (07-Apr-19)</h4>
<ul> <ul>
<li>New inspection AssertThatBinaryExpressionIsTrueOrFalse that will find and fix common binary expressions and equals() statements (more than 150 combinations) inside assertThat(). <li>New inspection AssertThatBinaryExpressionIsTrueOrFalse that will find and fix common binary expressions and equals() statements (more than 150 combinations) inside assertThat().
@@ -48,15 +55,6 @@ patchPluginXml {
<li>Support for hasSizeLessThan(), hasSizeLessThanOrEqualTo(), hasSizeGreaterThanOrEqualTo(), and hasSizeGreaterThan() for AssertThatSizeInspection (with AssertJ >=13.2.0). <li>Support for hasSizeLessThan(), hasSizeLessThanOrEqualTo(), hasSizeGreaterThanOrEqualTo(), and hasSizeGreaterThan() for AssertThatSizeInspection (with AssertJ >=13.2.0).
<li>Really fixed highlighting for JUnit conversion. Sorry. <li>Really fixed highlighting for JUnit conversion. Sorry.
</ul> </ul>
<h4>V0.2 (01-Apr-19)</h4>
<ul>
<li>Fixed descriptions and quick fix texts.
<li>Fixed highlighting of found problems and also 'Run inspection by Name' returning nothing.
</ul>
<h4>V0.1 (31-Mar-19)</h4>
<ul>
<li>Initial release.
</ul>
""" """
} }
@@ -0,0 +1,34 @@
package de.platon42.intellij.plugins.cajon
import org.jetbrains.annotations.NonNls
class AssertJClassNames {
companion object {
@NonNls
const val ASSERTIONS_CLASSNAME = "org.assertj.core.api.Assertions"
@NonNls
const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert"
@NonNls
const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert"
@NonNls
const val ABSTRACT_INTEGER_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIntegerAssert"
@NonNls
const val ABSTRACT_COMPARABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractComparableAssert"
@NonNls
const val ABSTRACT_STRING_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractStringAssert"
@NonNls
const val ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractCharSequenceAssert"
@NonNls
const val ABSTRACT_ITERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIterableAssert"
@NonNls
const val ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.EnumerableAssert"
@NonNls
const val GUAVA_OPTIONAL_CLASSNAME = "com.google.common.base.Optional"
@NonNls
const val GUAVA_ASSERTIONS_CLASSNAME = "org.assertj.guava.api.Assertions"
@NonNls
const val GUAVA_OPTIONAL_ASSERT_CLASSNAME = "org.assertj.guava.api.OptionalAssert"
}
}
@@ -0,0 +1,19 @@
package de.platon42.intellij.plugins.cajon
import com.intellij.psi.PsiExpression
import com.intellij.psi.PsiMethodCallExpression
val PsiMethodCallExpression.qualifierExpression: PsiExpression get() = this.methodExpression.qualifierExpression!!
val PsiMethodCallExpression.firstArg: PsiExpression get() = this.argumentList.expressions[0]!!
fun PsiMethodCallExpression.replaceQualifier(qualifier: PsiExpression) {
this.qualifierExpression.replace(qualifier)
}
fun PsiMethodCallExpression.replaceQualifierFromMethodCall(oldMethodCall: PsiMethodCallExpression) {
this.qualifierExpression.replace(oldMethodCall.qualifierExpression)
}
fun PsiMethodCallExpression.getArg(n: Int): PsiExpression = this.argumentList.expressions[n]
fun <T> Boolean.map(forTrue: T, forFalse: T) = if (this) forTrue else forFalse
@@ -0,0 +1,79 @@
package de.platon42.intellij.plugins.cajon
import org.jetbrains.annotations.NonNls
class MethodNames {
companion object {
@NonNls
const val EQUALS = "equals"
@NonNls
const val ASSERT_THAT = "assertThat"
@NonNls
const val AS = "as"
@NonNls
const val IS_EQUAL_TO = "isEqualTo"
@NonNls
const val IS_NOT_EQUAL_TO = "isNotEqualTo"
@NonNls
const val IS_SAME_AS = "isSameAs"
@NonNls
const val IS_NOT_SAME_AS = "isNotSameAs"
@NonNls
const val IS_GREATER_THAN = "isGreaterThan"
@NonNls
const val IS_GREATER_THAN_OR_EQUAL_TO = "isGreaterThanOrEqualTo"
@NonNls
const val IS_LESS_THAN = "isLessThan"
@NonNls
const val IS_LESS_THAN_OR_EQUAL_TO = "isLessThanOrEqualTo"
@NonNls
const val IS_ZERO = "isZero"
@NonNls
const val IS_NOT_ZERO = "isNotZero"
@NonNls
const val IS_TRUE = "isTrue"
@NonNls
const val IS_FALSE = "isFalse"
@NonNls
const val IS_NULL = "isNull"
@NonNls
const val IS_NOT_NULL = "isNotNull"
@NonNls
const val IS_CLOSE_TO = "isCloseTo"
@NonNls
const val IS_NOT_CLOSE_TO = "isNotCloseTo"
@NonNls
const val IS_EMPTY = "isEmpty"
@NonNls
const val IS_NOT_EMPTY = "isNotEmpty"
@NonNls
const val HAS_SIZE = "hasSize"
@NonNls
const val HAS_SIZE_LESS_THAN = "hasSizeLessThan"
@NonNls
const val HAS_SIZE_LESS_THAN_OR_EQUAL_TO = "hasSizeLessThanOrEqualTo"
@NonNls
const val HAS_SIZE_GREATER_THAN = "hasSizeGreaterThan"
@NonNls
const val HAS_SIZE_GREATER_THAN_OR_EQUAL_TO = "hasSizeGreaterThanOrEqualTo"
@NonNls
const val HAS_SAME_SIZE_AS = "hasSameSizeAs"
@NonNls
const val CONTAINS = "contains"
@NonNls
const val CONTAINS_EXACTLY = "containsExactly"
@NonNls
const val CONTAINS_SAME = "containsSame"
@NonNls
const val IS_PRESENT = "isPresent"
@NonNls
const val IS_NOT_PRESENT = "isNotPresent"
@NonNls
const val IS_ABSENT = "isAbsent"
}
}
@@ -4,105 +4,145 @@ import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.PsiTypesUtil import com.intellij.psi.util.PsiTypesUtil
import com.siyeh.ig.callMatcher.CallMatcher import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_BOOLEAN_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_COMPARABLE_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_INTEGER_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ASSERTIONS_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_OPTIONAL_CLASSNAME
import de.platon42.intellij.plugins.cajon.MethodNames
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.RemoveExpectedOutmostMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSimpleMethodCallQuickFix
import org.jetbrains.annotations.NonNls
open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() { open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
companion object { companion object {
const val SIMPLIFY_MESSAGE_TEMPLATE = "%s can be simplified to %s" 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" const val REPLACE_DESCRIPTION_TEMPLATE = "Replace %s() with %s()"
@NonNls val TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP = mapOf<IElementType, String>(
const val ASSERTIONS_CLASSNAME = "org.assertj.core.api.Assertions" JavaTokenType.EQEQ to MethodNames.IS_EQUAL_TO,
JavaTokenType.NE to MethodNames.IS_NOT_EQUAL_TO,
JavaTokenType.GT to MethodNames.IS_GREATER_THAN,
JavaTokenType.GE to MethodNames.IS_GREATER_THAN_OR_EQUAL_TO,
JavaTokenType.LT to MethodNames.IS_LESS_THAN,
JavaTokenType.LE to MethodNames.IS_LESS_THAN_OR_EQUAL_TO
)
@NonNls val TOKEN_TO_ASSERTJ_FOR_OBJECT_MAPPINGS = mapOf<IElementType, String>(
const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert" JavaTokenType.EQEQ to MethodNames.IS_SAME_AS,
@NonNls JavaTokenType.NE to MethodNames.IS_NOT_SAME_AS
const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert" )
@NonNls
const val ABSTRACT_INTEGER_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIntegerAssert"
@NonNls
const val ABSTRACT_COMPARABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractComparableAssert"
@NonNls
const val ABSTRACT_STRING_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractStringAssert"
@NonNls
const val ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractCharSequenceAssert"
@NonNls
const val ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.EnumerableAssert"
@NonNls val SWAP_SIDE_OF_BINARY_OPERATOR = mapOf<IElementType, IElementType>(
const val ASSERT_THAT_METHOD = "assertThat" JavaTokenType.GT to JavaTokenType.LT,
@NonNls JavaTokenType.GE to JavaTokenType.LE,
const val IS_EQUAL_TO_METHOD = "isEqualTo" JavaTokenType.LT to JavaTokenType.GT,
@NonNls JavaTokenType.LE to JavaTokenType.GE
const val IS_NOT_EQUAL_TO_METHOD = "isNotEqualTo" )
@NonNls
const val IS_GREATER_THAN_METHOD = "isGreaterThan"
@NonNls
const val IS_GREATER_THAN_OR_EQUAL_TO_METHOD = "isGreaterThanOrEqualTo"
@NonNls
const val IS_LESS_THAN_METHOD = "isLessThan"
@NonNls
const val IS_LESS_THAN_OR_EQUAL_TO_METHOD = "isLessThanOrEqualTo"
@NonNls
const val IS_ZERO_METHOD = "isZero"
@NonNls
const val IS_NOT_ZERO_METHOD = "isNotZero"
@NonNls
const val IS_TRUE_METHOD = "isTrue"
@NonNls
const val IS_FALSE_METHOD = "isFalse"
@NonNls
const val HAS_SIZE_METHOD = "hasSize"
val ASSERT_THAT_INT = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, ASSERT_THAT_METHOD) 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, MethodNames.ASSERT_THAT)
.parameterTypes("int")!! .parameterTypes("int")!!
val ASSERT_THAT_BOOLEAN = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, ASSERT_THAT_METHOD) val ASSERT_THAT_BOOLEAN = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)
.parameterTypes("boolean")!! .parameterTypes("boolean")!!
val IS_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_EQUAL_TO_METHOD) val ASSERT_THAT_ANY = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)
.parameterCount(1)!!
val ASSERT_THAT_JAVA8_OPTIONAL = CallMatcher.staticCall(ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)
.parameterTypes(CommonClassNames.JAVA_UTIL_OPTIONAL)!!
val ASSERT_THAT_GUAVA_OPTIONAL = CallMatcher.staticCall(GUAVA_ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)
.parameterTypes(GUAVA_OPTIONAL_CLASSNAME)!!
val IS_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! .parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val IS_NOT_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_NOT_EQUAL_TO_METHOD) val IS_NOT_EQUAL_TO_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! .parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val IS_EQUAL_TO_BOOLEAN = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_EQUAL_TO_METHOD) val IS_EQUAL_TO_BOOLEAN = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO)
.parameterTypes("boolean")!! .parameterTypes("boolean")!!
val IS_NOT_EQUAL_TO_BOOLEAN = val IS_NOT_EQUAL_TO_BOOLEAN =
CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_NOT_EQUAL_TO_METHOD) CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, MethodNames.IS_NOT_EQUAL_TO)
.parameterTypes("boolean")!! .parameterTypes("boolean")!!
val HAS_SIZE = CallMatcher.instanceCall(ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME, HAS_SIZE_METHOD) val IS_SAME_AS_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, MethodNames.IS_SAME_AS)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val IS_NOT_SAME_AS_OBJECT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, MethodNames.IS_NOT_SAME_AS)
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!!
val HAS_SIZE = CallMatcher.instanceCall(ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME, MethodNames.HAS_SIZE)
.parameterTypes("int")!! .parameterTypes("int")!!
val IS_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, IS_EQUAL_TO_METHOD) val IS_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_ASSERT_CLASSNAME, MethodNames.IS_EQUAL_TO)
.parameterTypes("int")!! .parameterTypes("int")!!
val IS_GREATER_THAN_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, IS_GREATER_THAN_METHOD) val IS_GREATER_THAN_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_GREATER_THAN)
.parameterTypes("int")!! .parameterTypes("int")!!
val IS_GREATER_THAN_OR_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, IS_GREATER_THAN_OR_EQUAL_TO_METHOD) val IS_GREATER_THAN_OR_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_GREATER_THAN_OR_EQUAL_TO)
.parameterTypes("int")!! .parameterTypes("int")!!
val IS_LESS_THAN_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, IS_LESS_THAN_METHOD) val IS_LESS_THAN_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_LESS_THAN)
.parameterTypes("int")!! .parameterTypes("int")!!
val IS_LESS_THAN_OR_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, IS_LESS_THAN_OR_EQUAL_TO_METHOD) val IS_LESS_THAN_OR_EQUAL_TO_INT = CallMatcher.instanceCall(ABSTRACT_COMPARABLE_ASSERT_CLASSNAME, MethodNames.IS_LESS_THAN_OR_EQUAL_TO)
.parameterTypes("int")!! .parameterTypes("int")!!
val IS_ZERO = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, IS_ZERO_METHOD) val IS_ZERO = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_ZERO)
.parameterCount(0)!! .parameterCount(0)!!
val IS_NOT_ZERO = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, IS_NOT_ZERO_METHOD) val IS_NOT_ZERO = CallMatcher.instanceCall(ABSTRACT_INTEGER_ASSERT_CLASSNAME, MethodNames.IS_NOT_ZERO)
.parameterCount(0)!! .parameterCount(0)!!
val IS_TRUE = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_TRUE_METHOD) val IS_TRUE = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, MethodNames.IS_TRUE)
.parameterCount(0)!! .parameterCount(0)!!
val IS_FALSE = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, IS_FALSE_METHOD) val IS_FALSE = CallMatcher.instanceCall(ABSTRACT_BOOLEAN_ASSERT_CLASSNAME, MethodNames.IS_FALSE)
.parameterCount(0)!! .parameterCount(0)!!
val COLLECTION_SIZE = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "size") val COLLECTION_SIZE = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "size")
.parameterCount(0)!! .parameterCount(0)!!
val OBJECT_EQUALS = CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_OBJECT, "equals") val OBJECT_EQUALS = CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_OBJECT, "equals")
.parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)!! .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)!!
val GUAVA_OPTIONAL_GET = CallMatcher.instanceCall(GUAVA_OPTIONAL_CLASSNAME, "get")
.parameterCount(0)!!
val GUAVA_OPTIONAL_IS_PRESENT = CallMatcher.instanceCall(GUAVA_OPTIONAL_CLASSNAME, "isPresent")
.parameterCount(0)!!
val GUAVA_OPTIONAL_OF = CallMatcher.staticCall(GUAVA_OPTIONAL_CLASSNAME, "of")
.parameterCount(1)!!
val GUAVA_OPTIONAL_FROM_NULLABLE = CallMatcher.staticCall(GUAVA_OPTIONAL_CLASSNAME, "fromNullable")
.parameterCount(1)!!
val GUAVA_OPTIONAL_ABSENT = CallMatcher.staticCall(GUAVA_OPTIONAL_CLASSNAME, "absent")
.parameterCount(0)!!
} }
override fun getGroupDisplayName(): String { override fun getGroupDisplayName(): String {
@@ -110,8 +150,8 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
} }
protected fun checkAssertedType(expression: PsiMethodCallExpression, classname: String): Boolean { protected fun checkAssertedType(expression: PsiMethodCallExpression, classname: String): Boolean {
var assertedType = expression.methodExpression.qualifierExpression?.type ?: return false var assertedType = expression.qualifierExpression.type ?: return false
if (assertedType is PsiCapturedWildcardType) { while (assertedType is PsiCapturedWildcardType) {
assertedType = assertedType.upperBound assertedType = assertedType.upperBound
} }
val assertedClass = PsiTypesUtil.getPsiClass(assertedType) ?: return false val assertedClass = PsiTypesUtil.getPsiClass(assertedType) ?: return false
@@ -120,8 +160,7 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
return assertedClass.isEquivalentTo(expectedClass) || assertedClass.isInheritor(expectedClass, true) return assertedClass.isEquivalentTo(expectedClass) || assertedClass.isInheritor(expectedClass, true)
} }
protected fun getOriginalMethodName(expression: PsiMethodCallExpression) = protected fun getOriginalMethodName(expression: PsiMethodCallExpression) = expression.resolveMethod()?.name
expression.resolveMethod()?.name?.plus("()")
protected fun registerSimplifyMethod( protected fun registerSimplifyMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
@@ -131,25 +170,75 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
val originalMethod = getOriginalMethodName(expression) ?: return val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod) val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = SIMPLIFY_MESSAGE_TEMPLATE.format(originalMethod, replacementMethod) val message = SIMPLIFY_MESSAGE_TEMPLATE.format(originalMethod, replacementMethod)
holder.registerProblem( val quickFix = ReplaceSimpleMethodCallQuickFix(description, replacementMethod)
expression, holder.registerProblem(expression, message, quickFix)
message, }
ReplaceSimpleMethodCallQuickFix(description, replacementMethod)
) 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 = RemoveExpectedOutmostMethodCallQuickFix(description, replacementMethod)
holder.registerProblem(expression, message, quickfix)
} }
protected fun calculateConstantParameterValue(expression: PsiMethodCallExpression, argIndex: Int): Any? { protected fun calculateConstantParameterValue(expression: PsiMethodCallExpression, argIndex: Int): Any? {
if (argIndex >= expression.argumentList.expressionCount) return null if (argIndex >= expression.argumentList.expressions.size) return null
val valueExpression = expression.argumentList.expressions[argIndex] ?: return null val valueExpression = expression.getArg(argIndex)
val constantEvaluationHelper = JavaPsiFacade.getInstance(expression.project).constantEvaluationHelper 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 { protected fun getExpectedBooleanResult(expectedCallExpression: PsiMethodCallExpression): Boolean? {
val classname = "org.assertj.core.api.${classAndMethod.substringBeforeLast(".")}" 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, classname: String, methodname: String): Boolean {
val findClass = val findClass =
JavaPsiFacade.getInstance(element.project).findClass(classname, GlobalSearchScope.allScope(element.project)) JavaPsiFacade.getInstance(element.project).findClass(classname, GlobalSearchScope.allScope(element.project))
?: return false ?: return false
return findClass.findMethodsByName(classAndMethod.substringAfterLast(".")).isNotEmpty() return findClass.findMethodsByName(methodname).isNotEmpty()
} }
} }
@@ -9,7 +9,7 @@ open class AbstractJUnitAssertInspection : AbstractBaseJavaLocalInspectionTool()
companion object { companion object {
const val CONVERT_MESSAGE_TEMPLATE = "%s can be converted to AssertJ style" const val CONVERT_MESSAGE_TEMPLATE = "%s can be converted to AssertJ style"
const val REPLACE_DESCRIPTION_TEMPLATE = "Replace %s with assertThat().%s" const val REPLACE_DESCRIPTION_TEMPLATE = "Replace %s() with assertThat().%s()"
@NonNls @NonNls
const val JUNIT_ASSERT_CLASSNAME = "org.junit.Assert" const val JUNIT_ASSERT_CLASSNAME = "org.junit.Assert"
@@ -38,6 +38,5 @@ open class AbstractJUnitAssertInspection : AbstractBaseJavaLocalInspectionTool()
return "AssertJ" return "AssertJ"
} }
protected fun getOriginalMethodName(expression: PsiMethodCallExpression) = protected fun getOriginalMethodName(expression: PsiMethodCallExpression) = expression.resolveMethod()?.name
expression.resolveMethod()?.name?.plus("()")
} }
@@ -2,9 +2,13 @@ package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.TypeConversionUtil import com.intellij.psi.util.TypeConversionUtil
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.MethodNames.Companion.IS_NOT_NULL
import de.platon42.intellij.plugins.cajon.MethodNames.Companion.IS_NULL
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.quickfixes.SplitBinaryExpressionMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.SplitBinaryExpressionMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.SplitEqualsExpressionMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.SplitEqualsExpressionMethodCallQuickFix
@@ -12,33 +16,8 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
companion object { companion object {
private const val DISPLAY_NAME = "Asserting a binary expression" private const val DISPLAY_NAME = "Asserting a binary expression"
private const val SPLIT_BINARY_EXPRESSION_DESCRIPTION = "Split binary expression out of assertThat()" private const val SPLIT_EXPRESSION_DESCRIPTION_TEMPLATE = "Split %s expression out of assertThat()"
private const val SPLIT_EQUALS_EXPRESSION_DESCRIPTION = "Split equals() expression out of assertThat()" private const val MORE_MEANINGFUL_MESSAGE_TEMPLATE = "Moving %s expression out of assertThat() would be more meaningful"
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 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()")
)
} }
override fun getDisplayName() = DISPLAY_NAME override fun getDisplayName() = DISPLAY_NAME
@@ -53,16 +32,16 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::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.argumentList.expressions[0] ?: return val assertThatArgument = expression.firstArg
if (assertThatArgument is PsiMethodCallExpression && OBJECT_EQUALS.test(assertThatArgument)) { if (assertThatArgument is PsiMethodCallExpression && OBJECT_EQUALS.test(assertThatArgument)) {
val replacementMethod = if (isInverted) "isNotEqualTo()" else "isEqualTo()" val replacementMethod = if (expectedResult) MethodNames.IS_EQUAL_TO else MethodNames.IS_NOT_EQUAL_TO
holder.registerProblem( val type = "${MethodNames.EQUALS}()"
expression, val description = SPLIT_EXPRESSION_DESCRIPTION_TEMPLATE.format(type)
EQUALS_MORE_MEANINGFUL_MESSAGE, val message = MORE_MEANINGFUL_MESSAGE_TEMPLATE.format(type)
SplitEqualsExpressionMethodCallQuickFix(SPLIT_EQUALS_EXPRESSION_DESCRIPTION, replacementMethod) val quickFix = SplitEqualsExpressionMethodCallQuickFix(description, replacementMethod)
) holder.registerProblem(expression, message, quickFix)
return return
} }
@@ -71,55 +50,35 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
val leftType = binaryExpression.lOperand.type ?: return val leftType = binaryExpression.lOperand.type ?: return
val rightType = binaryExpression.rOperand?.type ?: return val rightType = binaryExpression.rOperand?.type ?: return
val isLeftNull = TypeConversionUtil.isNullType(leftType) val bothTypes = listOf(leftType, rightType)
val isRightNull = TypeConversionUtil.isNullType(rightType) val (isLeftNull, isRightNull) = bothTypes.map(TypeConversionUtil::isNullType)
if (isLeftNull && isRightNull) { if (isLeftNull && isRightNull) {
return return
} else if (isLeftNull || isRightNull) { } else if (isLeftNull || isRightNull) {
registerSplitBinaryExpressionMethod( val replacementMethod = if (expectedResult) IS_NULL else IS_NOT_NULL
holder, registerSplitBinaryExpressionMethod(holder, expression, replacementMethod, pickRightOperand = isLeftNull, noExpectedExpression = true)
expression,
if (isInverted) "isNotNull()" else "isNull()",
pickRightOperand = isLeftNull,
noExpectedExpression = true
)
return return
} }
val isPrimitive = TypeConversionUtil.isPrimitiveAndNotNull(leftType) && TypeConversionUtil.isPrimitiveAndNotNull(rightType) val isPrimitive = bothTypes.all(TypeConversionUtil::isPrimitiveAndNotNull)
val isNumericType = TypeConversionUtil.isNumericType(leftType) && TypeConversionUtil.isNumericType(rightType) val isNumericType = bothTypes.all(TypeConversionUtil::isNumericType)
val constantEvaluationHelper = JavaPsiFacade.getInstance(expression.project).constantEvaluationHelper val constantEvaluationHelper = JavaPsiFacade.getInstance(expression.project).constantEvaluationHelper
val swapExpectedAndActual = constantEvaluationHelper.computeConstantExpression(binaryExpression.lOperand) != null val swapExpectedAndActual = constantEvaluationHelper.computeConstantExpression(binaryExpression.lOperand) != null
val tokenType = binaryExpression.operationSign.tokenType val tokenType = binaryExpression.operationSign.tokenType
val mappingToUse = .let {
if (isPrimitive || isNumericType) { if (swapExpectedAndActual) SWAP_SIDE_OF_BINARY_OPERATOR.getOrDefault(it, it) else it
if (swapExpectedAndActual) PRIMITIVE_MAPPINGS_SWAPPED else PRIMITIVE_MAPPINGS
} else {
OBJECT_MAPPINGS
} }
val mapping = mappingToUse.find { it.tokenType == tokenType } ?: return .let {
val replacementMethod = if (isInverted) mapping.replacementInverted else mapping.replacement if (expectedResult) it else INVERT_BINARY_OPERATOR.getOrDefault(it, it)
} ?: return
val mappingToUse =
(isPrimitive || isNumericType).map(TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP, TOKEN_TO_ASSERTJ_FOR_OBJECT_MAPPINGS)
val replacementMethod = mappingToUse[tokenType] ?: return
registerSplitBinaryExpressionMethod(holder, expression, replacementMethod, pickRightOperand = swapExpectedAndActual) 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
}
private fun registerSplitBinaryExpressionMethod( private fun registerSplitBinaryExpressionMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
expression: PsiMethodCallExpression, expression: PsiMethodCallExpression,
@@ -127,18 +86,12 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
pickRightOperand: Boolean = false, pickRightOperand: Boolean = false,
noExpectedExpression: Boolean = false noExpectedExpression: Boolean = false
) { ) {
holder.registerProblem( val type = "binary"
expression, val description = SPLIT_EXPRESSION_DESCRIPTION_TEMPLATE.format(type)
BINARY_MORE_MEANINGFUL_MESSAGE, val message = MORE_MEANINGFUL_MESSAGE_TEMPLATE.format(type)
SplitBinaryExpressionMethodCallQuickFix(SPLIT_BINARY_EXPRESSION_DESCRIPTION, replacementMethod, pickRightOperand, noExpectedExpression) val quickFix = SplitBinaryExpressionMethodCallQuickFix(description, replacementMethod, pickRightOperand, noExpectedExpression)
) holder.registerProblem(expression, message, quickFix)
} }
} }
} }
private class Mapping(
val tokenType: IElementType,
val replacement: String,
val replacementInverted: String
)
} }
@@ -1,8 +1,14 @@
package de.platon42.intellij.plugins.cajon.inspections package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder 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 com.intellij.psi.util.TypeConversionUtil
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_BOOLEAN_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() { class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() {
@@ -16,36 +22,25 @@ class AssertThatBooleanIsTrueOrFalseInspection : AbstractAssertJInspection() {
return object : JavaElementVisitor() { return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) { override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression) super.visitMethodCallExpression(expression)
val isEqualToObject = IS_EQUAL_TO_OBJECT.test(expression) val matchingCalls = listOf(
val isEqualToBoolean = IS_EQUAL_TO_BOOLEAN.test(expression) IS_EQUAL_TO_OBJECT, IS_EQUAL_TO_BOOLEAN,
val isNotEqualToObject = IS_NOT_EQUAL_TO_OBJECT.test(expression) IS_NOT_EQUAL_TO_OBJECT, IS_NOT_EQUAL_TO_BOOLEAN
val isNotEqualToBoolean = IS_NOT_EQUAL_TO_BOOLEAN.test(expression) ).map { it.test(expression) }
val normalBooleanTest = isEqualToObject || isEqualToBoolean if (matchingCalls.none { it }) {
val flippedBooleanTest = isNotEqualToObject || isNotEqualToBoolean
if (!(normalBooleanTest || flippedBooleanTest)) {
return return
} }
if (!checkAssertedType(expression, ABSTRACT_BOOLEAN_ASSERT_CLASSNAME)) { if (!checkAssertedType(expression, ABSTRACT_BOOLEAN_ASSERT_CLASSNAME)) {
return return
} }
val equalToExpression = expression.argumentList.expressions[0] ?: return val expectedExpression = expression.firstArg
if (!TypeConversionUtil.isBooleanType(equalToExpression.type)) { if (!TypeConversionUtil.isBooleanType(expectedExpression.type)) {
return return
} }
var value = calculateConstantParameterValue(expression, 0) val expectedResult = calculateConstantParameterValue(expression, 0) as? Boolean ?: return
if (value == null) { val flippedBooleanTest = matchingCalls.drop(2).any { it }
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 replacementMethod = if (expectedResult xor flippedBooleanTest) "isTrue()" else "isFalse()" val replacementMethod = (expectedResult xor flippedBooleanTest).map(MethodNames.IS_TRUE, MethodNames.IS_FALSE)
registerSimplifyMethod(holder, expression, replacementMethod) registerSimplifyMethod(holder, expression, replacementMethod)
} }
} }
@@ -4,6 +4,7 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.JavaElementVisitor import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.MethodNames
class AssertThatEnumerableIsEmptyInspection : AbstractAssertJInspection() { class AssertThatEnumerableIsEmptyInspection : AbstractAssertJInspection() {
@@ -17,14 +18,13 @@ class AssertThatEnumerableIsEmptyInspection : AbstractAssertJInspection() {
return object : JavaElementVisitor() { return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) { override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression) super.visitMethodCallExpression(expression)
val hasSize = HAS_SIZE.test(expression) if (!HAS_SIZE.test(expression)) {
if (!hasSize) {
return return
} }
val value = calculateConstantParameterValue(expression, 0) ?: return val value = calculateConstantParameterValue(expression, 0) ?: return
if (value == 0) { if (value == 0) {
registerSimplifyMethod(holder, expression, "isEmpty()") registerSimplifyMethod(holder, expression, MethodNames.IS_EMPTY)
} }
} }
} }
@@ -0,0 +1,61 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.AssertJClassNames
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
class AssertThatGuavaOptionalInspection : AbstractAssertJInspection() {
companion object {
private const val DISPLAY_NAME = "Asserting an Optional (Guava)"
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
JavaPsiFacade.getInstance(expression.project)
.findClass(AssertJClassNames.GUAVA_ASSERTIONS_CLASSNAME, GlobalSearchScope.allScope(expression.project)) ?: return
val assertThatGuava = ASSERT_THAT_GUAVA_OPTIONAL.test(expression)
if (!(ASSERT_THAT_ANY.test(expression) || assertThatGuava)) {
return
}
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
if (assertThatGuava) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (GUAVA_OPTIONAL_OF.test(innerExpectedCall) || GUAVA_OPTIONAL_FROM_NULLABLE.test(innerExpectedCall)) {
registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS)
} else if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_ABSENT)
}
} else if (IS_NOT_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_PRESENT)
}
}
} else {
val actualExpression = expression.firstArg as? PsiMethodCallExpression ?: return
if (GUAVA_OPTIONAL_GET.test(actualExpression) && IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS)
} else if (GUAVA_OPTIONAL_IS_PRESENT.test(actualExpression)) {
val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return
val replacementMethod = expectedPresence.map(MethodNames.IS_PRESENT, MethodNames.IS_ABSENT)
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true)
}
}
}
}
}
}
@@ -0,0 +1,63 @@
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.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
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, MethodNames.CONTAINS)
} else if (OPTIONAL_EMPTY.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_NOT_PRESENT)
}
} else if (IS_NOT_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (OPTIONAL_EMPTY.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_PRESENT)
}
}
} else {
val actualExpression = expression.firstArg as? PsiMethodCallExpression ?: return
if (OPTIONAL_GET.test(actualExpression)) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS)
} else if (IS_SAME_AS_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS_SAME)
}
} else if (OPTIONAL_IS_PRESENT.test(actualExpression)) {
val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return
val replacementMethod = expectedPresence.map(MethodNames.IS_PRESENT, MethodNames.IS_NOT_PRESENT)
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true)
}
}
}
}
}
}
@@ -5,6 +5,9 @@ import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiType import com.intellij.psi.PsiType
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
class AssertThatObjectIsNullOrNotNullInspection : AbstractAssertJInspection() { class AssertThatObjectIsNullOrNotNullInspection : AbstractAssertJInspection() {
@@ -24,8 +27,8 @@ class AssertThatObjectIsNullOrNotNullInspection : AbstractAssertJInspection() {
return return
} }
if (expression.argumentList.expressions[0].type == PsiType.NULL) { if (expression.firstArg.type == PsiType.NULL) {
registerSimplifyMethod(holder, expression, if (isEqualTo) "isNull()" else "isNotNull()") registerSimplifyMethod(holder, expression, isEqualTo.map(MethodNames.IS_NULL, MethodNames.IS_NOT_NULL))
} }
} }
} }
@@ -3,13 +3,23 @@ package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_ITERABLE_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSizeMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSizeMethodCallQuickFix
class AssertThatSizeInspection : AbstractAssertJInspection() { class AssertThatSizeInspection : AbstractAssertJInspection() {
companion object { companion object {
private const val DISPLAY_NAME = "Asserting the size of an collection or array" 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_LESS_THAN_INT to MethodNames.HAS_SIZE_LESS_THAN,
IS_LESS_THAN_OR_EQUAL_TO_INT to MethodNames.HAS_SIZE_LESS_THAN_OR_EQUAL_TO,
IS_GREATER_THAN_INT to MethodNames.HAS_SIZE_GREATER_THAN,
IS_GREATER_THAN_OR_EQUAL_TO_INT to MethodNames.HAS_SIZE_GREATER_THAN_OR_EQUAL_TO
)
} }
override fun getDisplayName() = DISPLAY_NAME override fun getDisplayName() = DISPLAY_NAME
@@ -21,7 +31,7 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
if (!ASSERT_THAT_INT.test(expression)) { if (!ASSERT_THAT_INT.test(expression)) {
return return
} }
val actualExpression = expression.argumentList.expressions[0] ?: return val actualExpression = expression.firstArg
if (isArrayLength(actualExpression) || isCollectionSize(actualExpression)) { if (isArrayLength(actualExpression) || isCollectionSize(actualExpression)) {
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return
@@ -29,42 +39,29 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
val constValue = calculateConstantParameterValue(expectedCallExpression, 0) val constValue = calculateConstantParameterValue(expectedCallExpression, 0)
if (IS_EQUAL_TO_INT.test(expectedCallExpression)) { if (IS_EQUAL_TO_INT.test(expectedCallExpression)) {
if (constValue == 0) { if (constValue == 0) {
registerSizeMethod(holder, expression, expectedCallExpression, "isEmpty()", noExpectedExpression = true) registerReplaceSizeMethod(holder, expression, expectedCallExpression, MethodNames.IS_EMPTY, noExpectedExpression = true)
return
}
val equalToExpression = expectedCallExpression.argumentList.expressions[0]
if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) {
registerSizeMethod(holder, expression, expectedCallExpression, "hasSameSizeAs()", expectedIsCollection = true)
return
}
registerSizeMethod(holder, expression, expectedCallExpression, "hasSize()")
} else { } else {
if ((IS_LESS_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 0)) val equalToExpression = expectedCallExpression.firstArg
if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, MethodNames.HAS_SAME_SIZE_AS, expectedIsCollection = true)
} else {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, MethodNames.HAS_SIZE)
}
}
} else {
val isTestForEmpty = ((IS_LESS_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 0))
|| (IS_LESS_THAN_INT.test(expectedCallExpression) && (constValue == 1)) || (IS_LESS_THAN_INT.test(expectedCallExpression) && (constValue == 1))
|| IS_ZERO.test(expectedCallExpression) || IS_ZERO.test(expectedCallExpression))
) { val isTestForNotEmpty = ((IS_GREATER_THAN_INT.test(expectedCallExpression) && (constValue == 0))
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_GREATER_THAN_OR_EQUAL_TO_INT.test(expectedCallExpression) && (constValue == 1))
|| IS_NOT_ZERO.test(expectedCallExpression) || IS_NOT_ZERO.test(expectedCallExpression))
) { if (isTestForEmpty || isTestForNotEmpty) {
registerSizeMethod(holder, expression, expectedCallExpression, "isNotEmpty()", noExpectedExpression = true) val replacementMethod = isTestForEmpty.map(MethodNames.IS_EMPTY, MethodNames.IS_NOT_EMPTY)
return registerReplaceSizeMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true)
} } else if (hasAssertJMethod(expression, ABSTRACT_ITERABLE_ASSERT_CLASSNAME, MethodNames.HAS_SIZE_LESS_THAN)) {
// new stuff in AssertJ 13.2.0 // new stuff in AssertJ 13.2.0
if (hasAssertJMethod(expression, "AbstractIterableAssert.hasSizeLessThan")) { val matchedMethod = BONUS_EXPRESSIONS_CALL_MATCHER_MAP.find { it.first.test(expectedCallExpression) }?.second ?: return
val matchedMethod = listOf( registerReplaceSizeMethod(holder, expression, expectedCallExpression, matchedMethod)
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()")
).find { it.first.test(expectedCallExpression) }?.second
if (matchedMethod != null) {
registerSizeMethod(holder, expression, expectedCallExpression, matchedMethod)
return
}
} }
} }
} }
@@ -78,7 +75,7 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
&& ((psiReferenceExpression.resolve() as? PsiField)?.name == "length")) && ((psiReferenceExpression.resolve() as? PsiField)?.name == "length"))
} }
private fun registerSizeMethod( private fun registerReplaceSizeMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
expression: PsiMethodCallExpression, expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression, expectedCallExpression: PsiMethodCallExpression,
@@ -89,11 +86,8 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod) val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod) val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod)
holder.registerProblem( val quickfix = ReplaceSizeMethodCallQuickFix(description, replacementMethod, noExpectedExpression, expectedIsCollection)
expression, holder.registerProblem(expression, message, quickfix)
message,
ReplaceSizeMethodCallQuickFix(description, replacementMethod, noExpectedExpression, expectedIsCollection)
)
} }
} }
} }
@@ -4,6 +4,8 @@ import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.JavaElementVisitor import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_CHAR_SEQUENCE_ASSERT_CLASSNAME
import de.platon42.intellij.plugins.cajon.MethodNames
class AssertThatStringIsEmptyInspection : AbstractAssertJInspection() { class AssertThatStringIsEmptyInspection : AbstractAssertJInspection() {
@@ -29,7 +31,7 @@ class AssertThatStringIsEmptyInspection : AbstractAssertJInspection() {
val value = calculateConstantParameterValue(expression, 0) ?: return val value = calculateConstantParameterValue(expression, 0) ?: return
if ((isEqual && (value == "")) || (hasSize && (value == 0))) { if ((isEqual && (value == "")) || (hasSize && (value == 0))) {
registerSimplifyMethod(holder, expression, "isEmpty()") registerSimplifyMethod(holder, expression, MethodNames.IS_EMPTY)
} }
} }
} }
@@ -1,12 +1,12 @@
package de.platon42.intellij.plugins.cajon.inspections package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.CommonClassNames import com.intellij.psi.*
import com.intellij.psi.JavaElementVisitor import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.siyeh.ig.callMatcher.CallMatcher import com.siyeh.ig.callMatcher.CallMatcher
import com.siyeh.ig.callMatcher.CallMatcher.anyOf import com.siyeh.ig.callMatcher.CallMatcher.anyOf
import de.platon42.intellij.plugins.cajon.AssertJClassNames
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitAssertMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitAssertMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitDeltaAssertMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitDeltaAssertMethodCallQuickFix
@@ -21,28 +21,28 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes("boolean") CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes("boolean")
), ),
"isTrue()", false MethodNames.IS_TRUE, false
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes("boolean") CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes("boolean")
), ),
"isFalse()", false MethodNames.IS_FALSE, false
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, CommonClassNames.JAVA_LANG_OBJECT), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, CommonClassNames.JAVA_LANG_OBJECT),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)
), ),
"isNull()", false MethodNames.IS_NULL, false
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, CommonClassNames.JAVA_LANG_OBJECT), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, CommonClassNames.JAVA_LANG_OBJECT),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)
), ),
"isNotNull()", false MethodNames.IS_NOT_NULL, false
), ),
Mapping( Mapping(
anyOf( anyOf(
@@ -51,14 +51,14 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("float", "float", "float") CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("float", "float", "float")
), ),
"isCloseTo()", hasDelta = true MethodNames.IS_CLOSE_TO, hasDelta = true
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2)
), ),
"isEqualTo()" MethodNames.IS_EQUAL_TO
), ),
Mapping( Mapping(
anyOf( anyOf(
@@ -67,28 +67,28 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("float", "float", "float") CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("float", "float", "float")
), ),
"isNotCloseTo()", hasDelta = true MethodNames.IS_NOT_CLOSE_TO, hasDelta = true
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2)
), ),
"isNotEqualTo()" MethodNames.IS_NOT_EQUAL_TO
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2)
), ),
"isSameAs()" MethodNames.IS_SAME_AS
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2)
), ),
"isNotSameAs()" MethodNames.IS_NOT_SAME_AS
), ),
Mapping( Mapping(
anyOf( anyOf(
@@ -97,14 +97,14 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float[]", "float[]", "float"), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float[]", "float[]", "float"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("float[]", "float[]", "float") CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("float[]", "float[]", "float")
), ),
"containsExactly()", hasDelta = true MethodNames.CONTAINS_EXACTLY, hasDelta = true
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2), CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3) CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3)
), ),
"containsExactly()" MethodNames.CONTAINS_EXACTLY
) )
) )
} }
@@ -119,6 +119,8 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
if (!isJUnitAssertCall) { if (!isJUnitAssertCall) {
return // early exit return // early exit
} }
JavaPsiFacade.getInstance(expression.project)
.findClass(AssertJClassNames.ASSERTIONS_CLASSNAME, GlobalSearchScope.allScope(expression.project)) ?: return
for (mapping in MAPPINGS) { for (mapping in MAPPINGS) {
if (mapping.callMatcher.test(expression)) { if (mapping.callMatcher.test(expression)) {
if (mapping.hasDelta) { if (mapping.hasDelta) {
@@ -142,11 +144,8 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
val originalMethod = getOriginalMethodName(expression) ?: return val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod) val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod) val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
holder.registerProblem( val quickFix = ReplaceJUnitAssertMethodCallQuickFix(description, !hasExpected, replacementMethod)
expression, holder.registerProblem(expression, message, quickFix)
message,
ReplaceJUnitAssertMethodCallQuickFix(description, hasExpected, replacementMethod)
)
} }
private fun registerDeltaReplacementMethod( private fun registerDeltaReplacementMethod(
@@ -157,11 +156,8 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
val originalMethod = getOriginalMethodName(expression) ?: return val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod) val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod) val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
holder.registerProblem( val quickFix = ReplaceJUnitDeltaAssertMethodCallQuickFix(description, replacementMethod)
expression, holder.registerProblem(expression, message, quickFix)
message,
ReplaceJUnitDeltaAssertMethodCallQuickFix(description, replacementMethod)
)
} }
private class Mapping( private class Mapping(
@@ -1,21 +1,15 @@
package de.platon42.intellij.plugins.cajon.quickfixes package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.LocalQuickFix import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElementFactory import com.intellij.psi.*
import com.intellij.psi.PsiJavaFile import de.platon42.intellij.plugins.cajon.AssertJClassNames
import com.intellij.psi.PsiMethod import de.platon42.intellij.plugins.cajon.MethodNames
import com.intellij.psi.PsiMethodCallExpression import de.platon42.intellij.plugins.cajon.firstArg
import org.jetbrains.annotations.NonNls
abstract class AbstractCommonQuickFix(private val description: String) : LocalQuickFix { abstract class AbstractCommonQuickFix(private val description: String) : LocalQuickFix {
override fun getFamilyName() = description override fun getFamilyName() = description
companion object {
@NonNls
const val GUAVA_ASSERTIONS_CLASSNAME = "org.assertj.guava.api.Assertions"
}
protected fun addStaticImport(method: PsiMethod, element: PsiMethodCallExpression, factory: PsiElementFactory, vararg allowedClashes: String) { protected fun addStaticImport(method: PsiMethod, element: PsiMethodCallExpression, factory: PsiElementFactory, vararg allowedClashes: String) {
val methodName = method.name val methodName = method.name
val containingClass = method.containingClass ?: return val containingClass = method.containingClass ?: return
@@ -29,4 +23,13 @@ abstract class AbstractCommonQuickFix(private val description: String) : LocalQu
importList.add(factory.createImportStaticStatement(containingClass, methodName)) importList.add(factory.createImportStaticStatement(containingClass, methodName))
} }
} }
protected fun createAssertThat(context: PsiElement, actualExpression: PsiExpression): PsiMethodCallExpression {
val factory = JavaPsiFacade.getElementFactory(context.project)
val newMethodCall = factory.createExpressionFromText(
"${AssertJClassNames.ASSERTIONS_CLASSNAME}.${MethodNames.ASSERT_THAT}(a)", context
) as PsiMethodCallExpression
newMethodCall.firstArg.replace(actualExpression)
return newMethodCall
}
} }
@@ -0,0 +1,38 @@
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.map
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.$replacementMethod${noExpectedExpression.map("()", "(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 RemoveExpectedOutmostMethodCallQuickFix(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(e)", element) as PsiMethodCallExpression
val expectedMethodCallExpression = oldExpectedExpression.firstArg as? PsiMethodCallExpression ?: return
expectedExpression.firstArg.replace(expectedMethodCallExpression.firstArg)
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression)
}
}
@@ -6,45 +6,47 @@ import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.JavaCodeStyleManager import com.intellij.psi.codeStyle.JavaCodeStyleManager
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.replaceQualifier
class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val hasExpected: Boolean, private val replacementMethod: String) : class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val noExpectedExpression: Boolean, private val replacementMethod: String) :
AbstractCommonQuickFix(description) { AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList val args = methodCallExpression.argumentList
val count = args.expressionCount val count = args.expressions.size
val actualExpression = args.expressions[count - 1] ?: return val actualExpression = args.expressions[count - 1] ?: return
val (expectedExpression, messageExpression) = if (hasExpected) { val (expectedExpression, messageExpression) = if (noExpectedExpression) {
val message = if (count > 1) args.expressions[0] else null
null to message
} else {
val expected = args.expressions[count - 2] ?: return val expected = args.expressions[count - 2] ?: return
val message = if (count > 2) args.expressions[0] else null val message = if (count > 2) args.expressions[0] else null
Pair(expected, message) expected to message
} else {
val message = if (count > 1) args.expressions[0] else null
Pair(null, message)
} }
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedMethodCall = factory.createExpressionFromText( val expectedMethodCall = factory.createExpressionFromText(
"a.${if (hasExpected) replacementMethod.replace("()", "(e)") else replacementMethod}", element "a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element
) as PsiMethodCallExpression ) as PsiMethodCallExpression
if (hasExpected) { if (!noExpectedExpression) {
expectedMethodCall.argumentList.expressions[0].replace(expectedExpression!!) expectedMethodCall.firstArg.replace(expectedExpression!!)
} }
val newMethodCall = factory.createExpressionFromText( val newMethodCall = createAssertThat(element, actualExpression)
"org.assertj.core.api.Assertions.assertThat(a)", element
) as PsiMethodCallExpression
newMethodCall.argumentList.expressions[0].replace(actualExpression)
if (messageExpression != null) { if (messageExpression != null) {
val asExpression = factory.createExpressionFromText("a.as(desc)", element) as PsiMethodCallExpression val asExpression = factory.createExpressionFromText("a.${MethodNames.AS}(desc)", element) as PsiMethodCallExpression
asExpression.argumentList.expressions[0].replace(messageExpression) asExpression.firstArg.replace(messageExpression)
asExpression.methodExpression.qualifierExpression!!.replace(newMethodCall) asExpression.replaceQualifier(newMethodCall)
expectedMethodCall.methodExpression.qualifierExpression!!.replace(asExpression) expectedMethodCall.replaceQualifier(asExpression)
} else { } else {
expectedMethodCall.methodExpression.qualifierExpression!!.replace(newMethodCall) expectedMethodCall.replaceQualifier(newMethodCall)
} }
val assertThatMethod = newMethodCall.resolveMethod() ?: return val assertThatMethod = newMethodCall.resolveMethod() ?: return
@@ -6,45 +6,46 @@ import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.JavaCodeStyleManager import com.intellij.psi.codeStyle.JavaCodeStyleManager
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.getArg
import de.platon42.intellij.plugins.cajon.replaceQualifier
class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) { class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList val args = methodCallExpression.argumentList
val count = args.expressionCount val count = args.expressions.size
val actualExpression = args.expressions[count - 2] ?: return val actualExpression = args.expressions[count - 2] ?: return
val messageExpression = if (count > 3) args.expressions[0] else null val messageExpression = if (count > 3) args.expressions[0] else null
val expectedExpression = args.expressions[count - 3] ?: return val expectedExpression = args.expressions[count - 3] ?: return
val deltaExpression = args.expressions[count - 1] ?: return val deltaExpression = args.expressions[count - 1] ?: return
val factory = JavaPsiFacade.getElementFactory(element.project)
val offsetMethodCall = factory.createExpressionFromText( val offsetMethodCall = factory.createExpressionFromText(
"org.assertj.core.data.Offset.offset(c)", element "org.assertj.core.data.Offset.offset(c)", element
) as PsiMethodCallExpression ) as PsiMethodCallExpression
offsetMethodCall.argumentList.expressions[0].replace(deltaExpression) offsetMethodCall.firstArg.replace(deltaExpression)
val expectedMethodCall = factory.createExpressionFromText( val expectedMethodCall = factory.createExpressionFromText(
"a.${replacementMethod.removeSuffix("()")}(e, offs)", element "a.$replacementMethod(e, offs)", element
) as PsiMethodCallExpression ) as PsiMethodCallExpression
expectedMethodCall.argumentList.expressions[0].replace(expectedExpression) expectedMethodCall.firstArg.replace(expectedExpression)
expectedMethodCall.argumentList.expressions[1].replace(offsetMethodCall) expectedMethodCall.getArg(1).replace(offsetMethodCall)
val newMethodCall = factory.createExpressionFromText( val newMethodCall = createAssertThat(element, actualExpression)
"org.assertj.core.api.Assertions.assertThat(a)", element
) as PsiMethodCallExpression
newMethodCall.argumentList.expressions[0].replace(actualExpression)
if (messageExpression != null) { if (messageExpression != null) {
val asExpression = factory.createExpressionFromText("a.as(desc)", element) as PsiMethodCallExpression val asExpression = factory.createExpressionFromText("a.as(desc)", element) as PsiMethodCallExpression
asExpression.argumentList.expressions[0].replace(messageExpression) asExpression.firstArg.replace(messageExpression)
asExpression.methodExpression.qualifierExpression!!.replace(newMethodCall) asExpression.replaceQualifier(newMethodCall)
expectedMethodCall.methodExpression.qualifierExpression!!.replace(asExpression) expectedMethodCall.replaceQualifier(asExpression)
} else { } else {
expectedMethodCall.methodExpression.qualifierExpression!!.replace(newMethodCall) expectedMethodCall.replaceQualifier(newMethodCall)
} }
val assertThatMethod = newMethodCall.resolveMethod() ?: return val assertThatMethod = newMethodCall.resolveMethod() ?: return
@@ -4,17 +4,18 @@ import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class ReplaceSimpleMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) { class ReplaceSimpleMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val oldQualifier = methodCallExpression.methodExpression.qualifierExpression ?: return
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression = val expectedExpression =
factory.createExpressionFromText("a.$replacementMethod", element) as PsiMethodCallExpression factory.createExpressionFromText("a.$replacementMethod()", element) as PsiMethodCallExpression
expectedExpression.methodExpression.qualifierExpression!!.replace(oldQualifier) expectedExpression.replaceQualifierFromMethodCall(methodCallExpression)
element.replace(expectedExpression) element.replace(expectedExpression)
} }
} }
@@ -4,6 +4,10 @@ import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.qualifierExpression
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class ReplaceSizeMethodCallQuickFix( class ReplaceSizeMethodCallQuickFix(
description: String, description: String,
@@ -14,21 +18,23 @@ class ReplaceSizeMethodCallQuickFix(
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val assertExpression = methodCallExpression.argumentList.expressions[0] ?: return val assertExpression = methodCallExpression.firstArg
replaceCollectionSizeOrArrayLength(assertExpression) replaceCollectionSizeOrArrayLength(assertExpression)
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val expectedExpression =
factory.createExpressionFromText("a.${if (noExpectedExpression) replacementMethod else replacementMethod.replace("()", "(e)")}", element) as PsiMethodCallExpression val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression = factory.createExpressionFromText(
"a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element
) as PsiMethodCallExpression
if (!noExpectedExpression) { if (!noExpectedExpression) {
if (expectedIsCollection) { if (expectedIsCollection) {
replaceCollectionSizeOrArrayLength(oldExpectedExpression.argumentList.expressions[0]) replaceCollectionSizeOrArrayLength(oldExpectedExpression.firstArg)
} }
expectedExpression.argumentList.expressions[0].replace(oldExpectedExpression.argumentList.expressions[0]) expectedExpression.firstArg.replace(oldExpectedExpression.firstArg)
} }
expectedExpression.methodExpression.qualifierExpression!!.replace(oldExpectedExpression.methodExpression.qualifierExpression!!) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
@@ -36,7 +42,7 @@ class ReplaceSizeMethodCallQuickFix(
assertExpression.replace( assertExpression.replace(
when (assertExpression) { when (assertExpression) {
is PsiReferenceExpression -> assertExpression.qualifierExpression!! is PsiReferenceExpression -> assertExpression.qualifierExpression!!
is PsiMethodCallExpression -> assertExpression.methodExpression.qualifierExpression!! is PsiMethodCallExpression -> assertExpression.qualifierExpression
else -> return else -> return
} }
) )
@@ -7,6 +7,9 @@ import com.intellij.psi.PsiBinaryExpression
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement import com.intellij.psi.PsiStatement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class SplitBinaryExpressionMethodCallQuickFix( class SplitBinaryExpressionMethodCallQuickFix(
description: String, description: String,
@@ -17,20 +20,22 @@ class SplitBinaryExpressionMethodCallQuickFix(
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val binaryExpression = methodCallExpression.argumentList.expressions[0] as? PsiBinaryExpression ?: return val binaryExpression = methodCallExpression.firstArg as? PsiBinaryExpression ?: return
val expectedArgument = (if (pickRightOperand) binaryExpression.lOperand else binaryExpression.rOperand)?.copy() ?: return val expectedArgument = (if (pickRightOperand) binaryExpression.lOperand else binaryExpression.rOperand)?.copy() ?: return
binaryExpression.replace(if (pickRightOperand) binaryExpression.rOperand!! else binaryExpression.lOperand) binaryExpression.replace(if (pickRightOperand) binaryExpression.rOperand!! else binaryExpression.lOperand)
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val expectedExpression =
factory.createExpressionFromText("a.${if (noExpectedExpression) replacementMethod else replacementMethod.replace("()", "(e)")}", element) as PsiMethodCallExpression val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression = factory.createExpressionFromText(
"a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element
) as PsiMethodCallExpression
if (!noExpectedExpression) { if (!noExpectedExpression) {
expectedExpression.argumentList.expressions[0].replace(expectedArgument) expectedExpression.firstArg.replace(expectedArgument)
} }
expectedExpression.methodExpression.qualifierExpression!!.replace(oldExpectedExpression.methodExpression.qualifierExpression!!) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
} }
@@ -6,23 +6,28 @@ import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement import com.intellij.psi.PsiStatement
import com.intellij.psi.util.PsiTreeUtil 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 SplitEqualsExpressionMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) { class SplitEqualsExpressionMethodCallQuickFix(description: String, private val replacementMethod: String) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val factory = JavaPsiFacade.getElementFactory(element.project)
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val equalsMethodCall = methodCallExpression.argumentList.expressions[0] as? PsiMethodCallExpression ?: return val equalsMethodCall = methodCallExpression.firstArg as? PsiMethodCallExpression ?: return
val expectedArgument = equalsMethodCall.argumentList.expressions[0].copy() val expectedArgument = equalsMethodCall.firstArg.copy()
equalsMethodCall.replace(equalsMethodCall.methodExpression.qualifierExpression!!) equalsMethodCall.replace(equalsMethodCall.qualifierExpression)
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val expectedExpression =
factory.createExpressionFromText("a.${replacementMethod.replace("()", "(e)")}", element) as PsiMethodCallExpression val factory = JavaPsiFacade.getElementFactory(element.project)
expectedExpression.argumentList.expressions[0].replace(expectedArgument) val expectedExpression = factory.createExpressionFromText(
expectedExpression.methodExpression.qualifierExpression!!.replace(oldExpectedExpression.methodExpression.qualifierExpression!!) "a.$replacementMethod(e)", element
) as PsiMethodCallExpression
expectedExpression.firstArg.replace(expectedArgument)
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
} }
+6 -1
View File
@@ -10,7 +10,7 @@
]]></description> ]]></description>
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description --> <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
<idea-version since-build="182.0"/> <idea-version since-build="172.0"/>
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products --> on how to target different products -->
@@ -34,6 +34,11 @@
<localInspection groupPath="Java" shortName="AssertThatBinaryExpressionIsTrueOrFalse" enabledByDefault="true" level="WARNING" <localInspection groupPath="Java" shortName="AssertThatBinaryExpressionIsTrueOrFalse" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatBinaryExpressionIsTrueOrFalseInspection"/> implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatBinaryExpressionIsTrueOrFalseInspection"/>
<localInspection groupPath="Java" shortName="AssertThatJava8Optional" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatJava8OptionalInspection"/>
<localInspection groupPath="Java" shortName="AssertThatGuavaOptional" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatGuavaOptionalInspection"/>
<localInspection groupPath="Java" shortName="JUnitAssertToAssertJ" enabledByDefault="true" level="WARNING" <localInspection groupPath="Java" shortName="JUnitAssertToAssertJ" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.JUnitAssertToAssertJInspection"/> implementationClass="de.platon42.intellij.plugins.cajon.inspections.JUnitAssertToAssertJInspection"/>
</extensions> </extensions>
@@ -0,0 +1,8 @@
<html>
<body>
Looks at expected and actual expression being of Guava Optional type and whether the statement effectively tries to assert the
presence, absence or content and then replaces the statement by isPresent(), isAbsent(), or contains().
<!-- tooltip end -->
Requires AssertJ-Guava to be in classpath.
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
Looks at expected and actual expression being of Java 8 Optional type and whether the statement effectively tries to assert the
presence, absence or content and then replaces the statement by isPresent(), isNotPresent(), contains(), or containsSame().
<!-- tooltip end -->
</body>
</html>
@@ -129,27 +129,61 @@ public class Playground {
} }
private void java8Optional() { private void java8Optional() {
Optional<String> foo = Optional.empty(); Optional<String> opt = Optional.empty();
assertThat(foo.get()).isEqualTo("bla");
assertThat(foo).contains("bla"); assertThat(opt.isPresent()).isEqualTo(true);
assertThat(foo.isPresent()).isTrue(); assertThat(opt.isPresent()).isEqualTo(Boolean.TRUE);
assertThat(!foo.isPresent()).isFalse(); assertThat(opt.isPresent()).isNotEqualTo(false);
assertThat(foo).isPresent(); assertThat(opt.isPresent()).isNotEqualTo(Boolean.FALSE);
assertThat(foo.isPresent()).isFalse(); assertThat(opt.isPresent()).isTrue();
assertThat(!foo.isPresent()).isTrue();
assertThat(foo).isNotPresent(); assertThat(opt.isPresent()).isEqualTo(false);
assertThat(opt.isPresent()).isEqualTo(Boolean.FALSE);
assertThat(opt.isPresent()).isNotEqualTo(true);
assertThat(opt.isPresent()).isNotEqualTo(Boolean.TRUE);
assertThat(opt.isPresent()).isFalse();
assertThat(opt.get()).isEqualTo("foo");
assertThat(opt.get()).isSameAs("foo");
assertThat(opt).isEqualTo(Optional.of("foo"));
assertThat(opt).isEqualTo(Optional.ofNullable("foo"));
assertThat(opt).isNotEqualTo(Optional.of("foo"));
assertThat(opt).isNotEqualTo(Optional.ofNullable("foo"));
assertThat(opt).isEqualTo(Optional.empty());
assertThat(opt).isNotEqualTo(Optional.empty());
assertThat(opt).isPresent();
} }
private void guavaOptional() { private void assertThatGuavaOptional() {
com.google.common.base.Optional<String> foo = com.google.common.base.Optional.absent(); com.google.common.base.Optional<String> opt = com.google.common.base.Optional.absent();
assertThat(foo.get()).isEqualTo("bla");
assertThat(foo).contains("bla"); assertThat(opt.isPresent()).isEqualTo(true);
assertThat(foo.isPresent()).isTrue(); assertThat(opt.isPresent()).isEqualTo(Boolean.TRUE);
assertThat(!foo.isPresent()).isFalse(); assertThat(opt.isPresent()).isNotEqualTo(false);
assertThat(foo).isPresent(); assertThat(opt.isPresent()).isNotEqualTo(Boolean.FALSE);
assertThat(foo.isPresent()).isFalse(); assertThat(opt.isPresent()).isTrue();
assertThat(!foo.isPresent()).isTrue();
assertThat(foo).isAbsent(); assertThat(opt.isPresent()).isEqualTo(false);
assertThat(opt.isPresent()).isEqualTo(Boolean.FALSE);
assertThat(opt.isPresent()).isNotEqualTo(true);
assertThat(opt.isPresent()).isNotEqualTo(Boolean.TRUE);
assertThat(opt.isPresent()).isFalse();
assertThat(opt.get()).isEqualTo("foo");
assertThat(opt.get()).isSameAs("foo");
assertThat(opt.get()).isNotEqualTo("foo");
assertThat(opt.get()).isNotSameAs("foo");
assertThat(opt).isEqualTo(com.google.common.base.Optional.of("foo"));
assertThat(opt).isEqualTo(com.google.common.base.Optional.fromNullable("foo"));
assertThat(opt).isNotEqualTo(com.google.common.base.Optional.of("foo"));
assertThat(opt).isNotEqualTo(com.google.common.base.Optional.fromNullable("foo"));
assertThat(opt).isEqualTo(com.google.common.base.Optional.absent());
assertThat(opt).isNotEqualTo(com.google.common.base.Optional.absent());
assertThat(opt).isAbsent();
} }
private void junitAssertions() { private void junitAssertions() {
@@ -14,7 +14,7 @@ internal class AssertThatBinaryExpressionIsTrueOrFalseInspectionTest : AbstractC
runTest { runTest {
myFixture.enableInspections(AssertThatBinaryExpressionIsTrueOrFalseInspection::class.java) myFixture.enableInspections(AssertThatBinaryExpressionIsTrueOrFalseInspection::class.java)
myFixture.configureByFile("BinaryExpressionBefore.java") myFixture.configureByFile("BinaryExpressionBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Split binary expression out of assertThat()"), 144) executeQuickFixes(myFixture, Regex.fromLiteral("Split binary expression out of assertThat()"), 148)
executeQuickFixes(myFixture, Regex.fromLiteral("Split equals() expression out of assertThat()"), 12) executeQuickFixes(myFixture, Regex.fromLiteral("Split equals() expression out of assertThat()"), 12)
myFixture.checkResultByFile("BinaryExpressionAfter.java") myFixture.checkResultByFile("BinaryExpressionAfter.java")
} }
@@ -0,0 +1,30 @@
package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
import de.platon42.intellij.jupiter.AddLocalJarToModule
import de.platon42.intellij.jupiter.MyFixture
import de.platon42.intellij.jupiter.TestDataSubPath
import de.platon42.intellij.plugins.cajon.AbstractCajonTest
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
@AddLocalJarToModule(com.google.common.base.Optional::class, org.assertj.guava.api.Assertions::class, Assertions::class)
internal class AssertThatGuavaOptionalInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/AssertThatGuavaOptional")
internal fun assertThat_get_or_isPresent_for_Guava_Optional_can_be_simplified(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.enableInspections(AssertThatGuavaOptionalInspection::class.java)
myFixture.configureByFile("AssertThatGuavaOptionalBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isPresent()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isAbsent()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isAbsent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isTrue() with isPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isFalse() with isAbsent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with contains()"), 3)
myFixture.checkResultByFile("AssertThatGuavaOptionalAfter.java")
}
}
}
@@ -0,0 +1,28 @@
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 AssertThatJava8OptionalInspectionTest : AbstractCajonTest() {
@Test
@TestDataSubPath("inspections/AssertThatJava8Optional")
internal fun assertThat_get_or_isPresent_for_Java8_Optional_can_be_simplified(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.enableInspections(AssertThatJava8OptionalInspection::class.java)
myFixture.configureByFile("AssertThatJava8OptionalBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isPresent()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isNotPresent()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isNotPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isTrue() with isPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isFalse() with isNotPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with contains()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isSameAs() with containsSame()"), 1)
myFixture.checkResultByFile("AssertThatJava8OptionalAfter.java")
}
}
}
@@ -0,0 +1,36 @@
import com.google.common.base.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat;
public class AssertThatGuavaOptional {
private void assertThatGuavaOptional() {
Optional<String> opt = Optional.absent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isAbsent();
assertThat(opt).isAbsent();
assertThat(opt).isAbsent();
assertThat(opt).isAbsent();
assertThat(opt).isAbsent();
assertThat(opt).contains("foo");
assertThat(opt.get()).isSameAs("foo");
assertThat(opt.get()).isNotEqualTo("foo");
assertThat(opt.get()).isNotSameAs("foo");
assertThat(opt).contains("foo");
assertThat(opt).contains("foo");
assertThat(opt).isNotEqualTo(Optional.of("foo"));
assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
assertThat(opt).isAbsent();
assertThat(opt).isPresent();
}
}
@@ -0,0 +1,36 @@
import com.google.common.base.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat;
public class AssertThatGuavaOptional {
private void assertThatGuavaOptional() {
Optional<String> opt = Optional.absent();
assertThat(opt.isPresent()).isEqualTo(true);
assertThat(opt.isPresent()).isEqualTo(Boolean.TRUE);
assertThat(opt.isPresent()).isNotEqualTo(false);
assertThat(opt.isPresent()).isNotEqualTo(Boolean.FALSE);
assertThat(opt.isPresent()).isTrue();
assertThat(opt.isPresent()).isEqualTo(false);
assertThat(opt.isPresent()).isEqualTo(Boolean.FALSE);
assertThat(opt.isPresent()).isNotEqualTo(true);
assertThat(opt.isPresent()).isNotEqualTo(Boolean.TRUE);
assertThat(opt.isPresent()).isFalse();
assertThat(opt.get()).isEqualTo("foo");
assertThat(opt.get()).isSameAs("foo");
assertThat(opt.get()).isNotEqualTo("foo");
assertThat(opt.get()).isNotSameAs("foo");
assertThat(opt).isEqualTo(Optional.of("foo"));
assertThat(opt).isEqualTo(Optional.fromNullable("foo"));
assertThat(opt).isNotEqualTo(Optional.of("foo"));
assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
assertThat(opt).isEqualTo(Optional.absent());
assertThat(opt).isNotEqualTo(Optional.absent());
}
}
@@ -0,0 +1,35 @@
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
public class AssertThatJava8Optional {
private void assertThatJava8Optional() {
Optional<String> opt = Optional.empty();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isPresent();
assertThat(opt).isNotPresent();
assertThat(opt).isNotPresent();
assertThat(opt).isNotPresent();
assertThat(opt).isNotPresent();
assertThat(opt).isNotPresent();
assertThat(opt).contains("foo");
assertThat(opt).containsSame("foo");
assertThat(opt.get()).isNotEqualTo("foo");
assertThat(opt.get()).isNotSameAs("foo");
assertThat(opt).contains("foo");
assertThat(opt).contains("foo");
assertThat(opt).isNotEqualTo(Optional.of("foo"));
assertThat(opt).isNotEqualTo(Optional.ofNullable("foo"));
assertThat(opt).isNotPresent();
assertThat(opt).isPresent();
}
}
@@ -0,0 +1,35 @@
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
public class AssertThatJava8Optional {
private void assertThatJava8Optional() {
Optional<String> opt = Optional.empty();
assertThat(opt.isPresent()).isEqualTo(true);
assertThat(opt.isPresent()).isEqualTo(Boolean.TRUE);
assertThat(opt.isPresent()).isNotEqualTo(false);
assertThat(opt.isPresent()).isNotEqualTo(Boolean.FALSE);
assertThat(opt.isPresent()).isTrue();
assertThat(opt.isPresent()).isEqualTo(false);
assertThat(opt.isPresent()).isEqualTo(Boolean.FALSE);
assertThat(opt.isPresent()).isNotEqualTo(true);
assertThat(opt.isPresent()).isNotEqualTo(Boolean.TRUE);
assertThat(opt.isPresent()).isFalse();
assertThat(opt.get()).isEqualTo("foo");
assertThat(opt.get()).isSameAs("foo");
assertThat(opt.get()).isNotEqualTo("foo");
assertThat(opt.get()).isNotSameAs("foo");
assertThat(opt).isEqualTo(Optional.of("foo"));
assertThat(opt).isEqualTo(Optional.ofNullable("foo"));
assertThat(opt).isNotEqualTo(Optional.of("foo"));
assertThat(opt).isNotEqualTo(Optional.ofNullable("foo"));
assertThat(opt).isEqualTo(Optional.empty());
assertThat(opt).isNotEqualTo(Optional.empty());
}
}
@@ -10,6 +10,8 @@ public class BinaryExpression {
String stringExp = "foo"; String stringExp = "foo";
String stringAct = "bar"; String stringAct = "bar";
assertThat(primAct).isEqualTo(primExp);
assertThat(primAct).isEqualTo(primExp);
assertThat(primAct).isEqualTo(primExp); assertThat(primAct).isEqualTo(primExp);
assertThat(primAct).isEqualTo(primExp); assertThat(primAct).isEqualTo(primExp);
assertThat(primAct).isEqualTo(primExp); assertThat(primAct).isEqualTo(primExp);
@@ -18,6 +20,8 @@ public class BinaryExpression {
assertThat(primAct).isNotEqualTo(primExp); assertThat(primAct).isNotEqualTo(primExp);
assertThat(primAct).isNotEqualTo(primExp); assertThat(primAct).isNotEqualTo(primExp);
assertThat(primAct).isNotEqualTo(primExp); assertThat(primAct).isNotEqualTo(primExp);
assertThat(primAct).isNotEqualTo(primExp);
assertThat(primAct).isNotEqualTo(primExp);
assertThat(primAct).isNotEqualTo(1); assertThat(primAct).isNotEqualTo(1);
assertThat(primAct).isNotEqualTo(1); assertThat(primAct).isNotEqualTo(1);
@@ -12,12 +12,16 @@ public class BinaryExpression {
assertThat(primAct == primExp).isTrue(); assertThat(primAct == primExp).isTrue();
assertThat(primAct == primExp).isEqualTo(true); assertThat(primAct == primExp).isEqualTo(true);
assertThat(primAct == primExp).isEqualTo(Boolean.TRUE);
assertThat(primAct == primExp).isNotEqualTo(false); assertThat(primAct == primExp).isNotEqualTo(false);
assertThat(primAct == primExp).isNotEqualTo(Boolean.FALSE);
assertThat(primAct == 1).isTrue(); assertThat(primAct == 1).isTrue();
assertThat(1 == primAct).isTrue(); assertThat(1 == primAct).isTrue();
assertThat(primAct == primExp).isFalse(); assertThat(primAct == primExp).isFalse();
assertThat(primAct == primExp).isEqualTo(false); assertThat(primAct == primExp).isEqualTo(false);
assertThat(primAct == primExp).isEqualTo(Boolean.FALSE);
assertThat(primAct == primExp).isNotEqualTo(true); assertThat(primAct == primExp).isNotEqualTo(true);
assertThat(primAct == primExp).isNotEqualTo(Boolean.TRUE);
assertThat(primAct == 1).isFalse(); assertThat(primAct == 1).isFalse();
assertThat(1 == primAct).isFalse(); assertThat(1 == primAct).isFalse();