Compare commits

..
2 Commits
Author SHA1 Message Date
chrisly42 9f91fb3ccf Added support for referencing and refactoring inside ``.extracting()`` methods with fields, properties and methods (though getter renaming does not work that perfect, but I'm giving up for now as the IntelliJ SDK docs are seriously lacking).
Fixed an exception in batch mode if the description string was the same but for different fixes. Now descriptions are different for quick fixes triggered by AssertThatJava8OptionalInspection and AssertThatGuavaOptionalInspection. Minor refactorings. Extended documentation.
2019-04-18 22:12:48 +02:00
chrisly42 b58d8cfd2f Fix for incompatible method call regarding IDEA <2018.2.
Heavy refactoring regarding quick fixes (using more extensions).
Even more refactoring.
Fixed/extended AssertThatGuavaOptionalInspection regarding static.
imports and wrong reference to core assertThat() where Guava assertThat() actually was necessary.
2019-04-13 18:35:49 +02:00
45 changed files with 1074 additions and 343 deletions
+59 -10
View File
@@ -17,7 +17,7 @@ For example:
assertThat(collection.size()).isEqualTo(5); assertThat(collection.size()).isEqualTo(5);
``` ```
If the collection has more or less than 5 elements, the assertion will fail, but will not If the collection has more or less than five elements, the assertion will fail, but will not
tell you about the contents, making it hard to guess what went wrong. tell you about the contents, making it hard to guess what went wrong.
Instead, if you wrote the same assertion the following way: Instead, if you wrote the same assertion the following way:
@@ -26,12 +26,24 @@ Instead, if you wrote the same assertion the following way:
assertThat(collection).hasSize(5); assertThat(collection).hasSize(5);
``` ```
Then AssertJ would tell you the contents of the collection on failure. Then AssertJ would tell you the _actual contents_ of the collection on failure.
## Conversion of JUnit assertions to AssertJ ## Conversion of JUnit assertions to AssertJ
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.
## Lookup and refactoring of string-based extracting()
AssertJ allows [extracting POJO fields/properties on iterables/arrays](http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#extracted-properties-assertion).
Using strings is not safe for refactoring (and before Java 8 Lambdas were available,
creating extractor functions just for testing purpose was a bit too tedious).
This plugin adds support for referencing these fields (so you can ctrl(/cmd)-click on the
string to go to the definition) and also allows safe refactoring on the
fields (refactoring a getter method without a corresponding field will not work
correctly right now).
## Usage ## Usage
The plugin will report inspections in your opened editor file as warnings. The plugin will report inspections in your opened editor file as warnings.
@@ -103,7 +115,6 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the
from: assertThat(array.length).isGreaterThanOrEqualTo(expression); from: assertThat(array.length).isGreaterThanOrEqualTo(expression);
to: assertThat(array).hasSizeGreaterThanOrEqualTo(expression); to: assertThat(array).hasSizeGreaterThanOrEqualTo(expression);
``` ```
and analogously for collections... and analogously for collections...
- AssertThatBinaryExpressionIsTrueOrFalse - AssertThatBinaryExpressionIsTrueOrFalse
@@ -120,7 +131,7 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the
from: assertThat(null == objActual).isFalse(); from: assertThat(null == objActual).isFalse();
to: assertThat(objActual).isNotNull(); to: assertThat(objActual).isNotNull();
``` ```
and many, many more combinations (more than 150). ...and many, many more combinations (more than 150).
- AssertThatJava8Optional - AssertThatJava8Optional
``` ```
@@ -207,6 +218,23 @@ You can toggle the various inspections in the Settings/Editor/Inspections in the
AssertJ for Guava needs to be available in the classpath. AssertJ for Guava needs to be available in the classpath.
### Implemented referencing
```
.extracting("field")
.extracting("outerfield.fieldInsideObjectTypeOfOuterfield.andSoOn")
.extracting("property") // where the class has a getProperty() (or isProperty() for boolean) method
.extracting("bareMethod") // supported with AssertJ 13.12.0
.extracting(Extractors.byName("fieldOrPropertyOrBareMethod")
.extracting(Extractors.byName("fieldOrPropertyOrBareMethod.orAPathLikeAbove")
.extracting(Extractors.resultOf("bareMethod")
.extractingResultOf("bareMethod")
.flatExtracting("fieldOrPropertyOrBareMethod.orAPathLikeAbove")
.flatExtracting(Extractors.byName("fieldOrPropertyOrBareMethod.orAPathLikeAbove")
.flatExtracting(Extractors.resultOf("bareMethod")
```
Works on both POJOs and ```Iterable```s/```Array```s.
## Development notice ## Development notice
Cajon is written in Kotlin 1.3. Cajon is written in Kotlin 1.3.
@@ -218,7 +246,20 @@ Feel free to use the code (in package de.platon42.intellij.jupiter) for your pro
## TODO ## TODO
- AssertThatNegatedBooleanExpression - AssertThatNegatedBooleanExpression
- AssertThatInstanceOf - AssertThatInstanceOf
- Referencing string properties inside extracting() - AssertThatStringOps
```
from: assertThat(string.contains(foobar)).isTrue();
to: assertThat(string).contains(foobar);
from: assertThat(string.startsWith(foobar)).isTrue();
to: assertThat(string).startsWith(foobar);
from: assertThat(string.endsWith(foobar)).isTrue();
to: assertThat(string).endsWith(foobar);
from: assertThat(string.equalsIgnoreCase(foobar)).isTrue();
to: assertThat(string).isEqualToIgnoringCase(foobar);
```
Analogously with ```isFalse()```.
- AssumeInsteadOfReturn
- Extraction with property names to lambda with Java 8 - Extraction with property names to lambda with Java 8
``` ```
from: assertThat(object).extracting("propOne", "propNoGetter", "propTwo.innerProp")... from: assertThat(object).extracting("propOne", "propNoGetter", "propTwo.innerProp")...
@@ -228,16 +269,24 @@ Feel free to use the code (in package de.platon42.intellij.jupiter) for your pro
## Changelog ## Changelog
#### V0.5 (13-Apr-19)
- Fixed incompatibility with IDEA versions < 2018.2 (affected AssertThatSizeInspection). Minimal version is now 2017.3.
- Fixed missing Guava imports (if not already present) for AssertThatGuavaInspection. This was a major PITA to get right.
- Added support for referencing and refactoring inside ```.extracting()``` methods with fields, properties and methods (though
getter renaming does not work that perfect, but I'm giving up for now as the IntelliJ SDK docs are seriously lacking).
- Fixed an exception in batch mode if the description string was the same but for different fixes.
Now descriptions are different for quick fixes triggered by AssertThatJava8OptionalInspection and AssertThatGuavaOptionalInspection.
#### V0.4 (11-Apr-19) #### V0.4 (11-Apr-19)
- Reduced minimal supported IDEA version from 2018.2 to 2017.2. - 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 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. - 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). - Added support in AssertThatBinaryExpressionIsTrueOrFalse for ```is(Not)EqualTo(Boolean.TRUE/FALSE)```.
#### V0.3 (07-Apr-19) #### 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(). - 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. - Merged AssertThatObjectIsNull and AssertThatObjectIsNotNull to AssertThatObjectIsNullOrNotNull.
- Support for hasSizeLessThan(), hasSizeLessThanOrEqualTo(), hasSizeGreaterThanOrEqualTo(), and hasSizeGreaterThan() for AssertThatSizeInspection (with AssertJ >=13.2.0). - Support for ```hasSizeLessThan()```, ```hasSizeLessThanOrEqualTo()```, ```hasSizeGreaterThanOrEqualTo()```, and ```hasSizeGreaterThan()``` for AssertThatSizeInspection (with AssertJ >=13.2.0).
- Really fixed highlighting for JUnit conversion. Sorry. - Really fixed highlighting for JUnit conversion. Sorry.
#### V0.2 (01-Apr-19) #### V0.2 (01-Apr-19)
+11 -3
View File
@@ -5,7 +5,7 @@ plugins {
} }
group 'de.platon42' group 'de.platon42'
version '0.4' version '0.5'
repositories { repositories {
mavenCentral() mavenCentral()
@@ -22,9 +22,8 @@ dependencies {
testCompile "org.assertj:assertj-guava:3.2.1" testCompile "org.assertj:assertj-guava:3.2.1"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.0'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.4.0'
testImplementation "org.jetbrains.kotlin:kotlin-test" testImplementation "org.jetbrains.kotlin:kotlin-test"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit" // testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
} }
compileKotlin { compileKotlin {
@@ -41,6 +40,15 @@ intellij {
patchPluginXml { patchPluginXml {
changeNotes """ changeNotes """
<h4>V0.5 (18-Apr-19)</h4>
<ul>
<li>Fixed incompatibility with IDEA versions < 2018.2 (affected AssertThatSizeInspection). Minimal version is now 2017.3.
<li>Fixed missing Guava imports (if not already present) for AssertThatGuavaInspection. This was a major PITA to get right.
<li>Added support for referencing and refactoring inside .extracting() methods with fields, properties and methods (though
getter renaming does not work that perfect, but I'm giving up for now as the IntelliJ SDK docs are seriously lacking).
<li>Fixed an exception in batch mode if the description string was the same but for different fixes.
Now descriptions are different for quick fixes triggered by AssertThatJava8OptionalInspection and AssertThatGuavaOptionalInspection.
</ul>
<h4>V0.4 (11-Apr-19)</h4> <h4>V0.4 (11-Apr-19)</h4>
<ul> <ul>
<li>Reduced minimal supported IDEA version from 2018.2 to 2017.2. <li>Reduced minimal supported IDEA version from 2018.2 to 2017.2.
@@ -10,6 +10,8 @@ class AssertJClassNames {
@NonNls @NonNls
const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert" const val ABSTRACT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractAssert"
@NonNls @NonNls
const val ABSTRACT_OBJECT_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractObjectAssert"
@NonNls
const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert" const val ABSTRACT_BOOLEAN_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractBooleanAssert"
@NonNls @NonNls
const val ABSTRACT_INTEGER_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIntegerAssert" const val ABSTRACT_INTEGER_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIntegerAssert"
@@ -23,6 +25,8 @@ class AssertJClassNames {
const val ABSTRACT_ITERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIterableAssert" const val ABSTRACT_ITERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.AbstractIterableAssert"
@NonNls @NonNls
const val ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.EnumerableAssert" const val ABSTRACT_ENUMERABLE_ASSERT_CLASSNAME = "org.assertj.core.api.EnumerableAssert"
@NonNls
const val EXTRACTORS_CLASSNAME = "org.assertj.core.extractor.Extractors"
@NonNls @NonNls
const val GUAVA_OPTIONAL_CLASSNAME = "com.google.common.base.Optional" const val GUAVA_OPTIONAL_CLASSNAME = "com.google.common.base.Optional"
@@ -1,12 +1,14 @@
package de.platon42.intellij.plugins.cajon package de.platon42.intellij.plugins.cajon
import com.intellij.psi.PsiExpression import com.intellij.psi.*
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.JavaCodeStyleManager
import com.intellij.psi.util.PsiTreeUtil
val PsiMethodCallExpression.qualifierExpression: PsiExpression get() = this.methodExpression.qualifierExpression!! val PsiMethodCallExpression.qualifierExpression: PsiExpression get() = this.methodExpression.qualifierExpression!!
val PsiMethodCallExpression.firstArg: PsiExpression get() = this.argumentList.expressions[0]!! val PsiMethodCallExpression.firstArg: PsiExpression get() = this.argumentList.expressions[0]!!
fun PsiMethodCallExpression.replaceQualifier(qualifier: PsiExpression) { fun PsiMethodCallExpression.replaceQualifier(qualifier: PsiElement) {
this.qualifierExpression.replace(qualifier) this.qualifierExpression.replace(qualifier)
} }
@@ -14,6 +16,32 @@ fun PsiMethodCallExpression.replaceQualifierFromMethodCall(oldMethodCall: PsiMet
this.qualifierExpression.replace(oldMethodCall.qualifierExpression) this.qualifierExpression.replace(oldMethodCall.qualifierExpression)
} }
fun PsiElement.findOutmostMethodCall(): PsiMethodCallExpression? {
val statement = PsiTreeUtil.getParentOfType(this, PsiStatement::class.java) ?: return null
return PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java)
}
fun PsiMethodCallExpression.getArg(n: Int): PsiExpression = this.argumentList.expressions[n] fun PsiMethodCallExpression.getArg(n: Int): PsiExpression = this.argumentList.expressions[n]
fun <T> Boolean.map(forTrue: T, forFalse: T) = if (this) forTrue else forFalse fun <T> Boolean.map(forTrue: T, forFalse: T) = if (this) forTrue else forFalse
fun PsiMethod.addAsStaticImport(context: PsiElement, vararg allowedClashes: String) {
val factory = JavaPsiFacade.getElementFactory(context.project)
val methodName = this.name
val containingClass = this.containingClass ?: return
val importList = (context.containingFile as PsiJavaFile).importList ?: return
val notImportedStatically = importList.importStaticStatements.none {
val targetClass = it.resolveTargetClass() ?: return@none false
((it.referenceName == methodName) && !allowedClashes.contains(targetClass.qualifiedName))
|| (it.isOnDemand && (targetClass == this.containingClass))
}
if (notImportedStatically) {
importList.add(factory.createImportStaticStatement(containingClass, methodName))
}
}
fun PsiElement.shortenAndReformat() {
val codeStyleManager = JavaCodeStyleManager.getInstance(project)
codeStyleManager.shortenClassReferences(this)
CodeStyleManager.getInstance(project).reformat(this)
}
@@ -0,0 +1,35 @@
package de.platon42.intellij.plugins.cajon
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiExpression
import com.intellij.psi.PsiMethodCallExpression
import com.siyeh.ig.callMatcher.CallMatcher
val CORE_ASSERT_THAT_MATCHER = CallMatcher.staticCall(AssertJClassNames.ASSERTIONS_CLASSNAME, MethodNames.ASSERT_THAT)!!
fun createAssertThat(context: PsiElement, actualExpression: PsiExpression): PsiMethodCallExpression {
return createAssertThat(context, AssertJClassNames.ASSERTIONS_CLASSNAME, actualExpression)
}
fun createGuavaAssertThat(context: PsiElement, actualExpression: PsiExpression): PsiMethodCallExpression {
return createAssertThat(context, AssertJClassNames.GUAVA_ASSERTIONS_CLASSNAME, actualExpression)
}
fun createAssertThat(context: PsiElement, baseclass: String, actualExpression: PsiExpression): PsiMethodCallExpression {
return createMethodCall(context, "$baseclass.${MethodNames.ASSERT_THAT}", actualExpression)
}
fun createExpectedMethodCall(context: PsiElement, methodName: String, vararg arguments: PsiElement): PsiMethodCallExpression {
return createMethodCall(context, "a.$methodName", *arguments)
}
fun createMethodCall(context: PsiElement, fullQualifiedMethodName: String, vararg arguments: PsiElement): PsiMethodCallExpression {
val factory = JavaPsiFacade.getElementFactory(context.project)
val argString = generateSequence('b') { it + 1 }.take(arguments.size).joinToString(", ")
val expectedExpression = factory.createExpressionFromText(
"$fullQualifiedMethodName($argString)", context
) as PsiMethodCallExpression
arguments.forEachIndexed { index, newArg -> expectedExpression.getArg(index).replace(newArg) }
return expectedExpression
}
@@ -1,6 +1,7 @@
package de.platon42.intellij.plugins.cajon.inspections package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool
import com.intellij.codeInspection.LocalQuickFix
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
@@ -18,8 +19,6 @@ import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_OPTI
import de.platon42.intellij.plugins.cajon.MethodNames import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.getArg import de.platon42.intellij.plugins.cajon.getArg
import de.platon42.intellij.plugins.cajon.qualifierExpression 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
open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() { open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
@@ -29,6 +28,8 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
const val MORE_CONCISE_MESSAGE_TEMPLATE = "%s() would be more concise than %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()"
const val REMOVE_EXPECTED_OUTMOST_DESCRIPTION_TEMPLATE = "Unwrap expected expression and replace %s() with %s()"
const val REMOVE_ACTUAL_OUTMOST_DESCRIPTION_TEMPLATE = "Unwrap actual expression and replace %s() with %s()"
val TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP = mapOf<IElementType, String>( val TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP = mapOf<IElementType, String>(
JavaTokenType.EQEQ to MethodNames.IS_EQUAL_TO, JavaTokenType.EQEQ to MethodNames.IS_EQUAL_TO,
@@ -174,31 +175,49 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
holder.registerProblem(expression, message, quickFix) holder.registerProblem(expression, message, quickFix)
} }
protected fun registerRemoveActualOutmostMethod( protected fun registerReplaceMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
expression: PsiMethodCallExpression, expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression, oldExpectedCallExpression: PsiMethodCallExpression,
replacementMethod: String, replacementMethod: String,
noExpectedExpression: Boolean = false quickFixSupplier: (String, String) -> LocalQuickFix
) { ) {
val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return registerConciseMethod(REPLACE_DESCRIPTION_TEMPLATE, oldExpectedCallExpression, replacementMethod, quickFixSupplier, holder, expression)
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod) }
private fun registerConciseMethod(
descriptionTemplate: String,
oldExpectedCallExpression: PsiMethodCallExpression,
replacementMethod: String,
quickFixSupplier: (String, String) -> LocalQuickFix,
holder: ProblemsHolder,
expression: PsiMethodCallExpression
) {
val originalMethod = getOriginalMethodName(oldExpectedCallExpression) ?: return
val description = descriptionTemplate.format(originalMethod, replacementMethod)
val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod) val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod)
val quickfix = RemoveActualOutmostMethodCallQuickFix(description, replacementMethod, noExpectedExpression) val quickfix = quickFixSupplier(description, replacementMethod)
holder.registerProblem(expression, message, quickfix) holder.registerProblem(expression, message, quickfix)
} }
protected fun registerRemoveExpectedOutmostMethod( protected fun registerRemoveExpectedOutmostMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
expression: PsiMethodCallExpression, expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression, oldExpectedCallExpression: PsiMethodCallExpression,
replacementMethod: String replacementMethod: String,
quickFixSupplier: (String, String) -> LocalQuickFix
) { ) {
val originalMethod = getOriginalMethodName(expectedCallExpression) ?: return registerConciseMethod(REMOVE_EXPECTED_OUTMOST_DESCRIPTION_TEMPLATE, oldExpectedCallExpression, replacementMethod, quickFixSupplier, holder, expression)
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod) }
val message = MORE_CONCISE_MESSAGE_TEMPLATE.format(replacementMethod, originalMethod)
val quickfix = RemoveExpectedOutmostMethodCallQuickFix(description, replacementMethod) protected fun registerRemoveActualOutmostMethod(
holder.registerProblem(expression, message, quickfix) holder: ProblemsHolder,
expression: PsiMethodCallExpression,
oldExpectedCallExpression: PsiMethodCallExpression,
replacementMethod: String,
quickFixSupplier: (String, String) -> LocalQuickFix
) {
registerConciseMethod(REMOVE_ACTUAL_OUTMOST_DESCRIPTION_TEMPLATE, oldExpectedCallExpression, replacementMethod, quickFixSupplier, holder, expression)
} }
protected fun calculateConstantParameterValue(expression: PsiMethodCallExpression, argIndex: Int): Any? { protected fun calculateConstantParameterValue(expression: PsiMethodCallExpression, argIndex: Int): Any? {
@@ -239,6 +258,6 @@ open class AbstractAssertJInspection : AbstractBaseJavaLocalInspectionTool() {
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(methodname).isNotEmpty() return findClass.allMethods.any { it.name == methodname }
} }
} }
@@ -1,12 +1,13 @@
package de.platon42.intellij.plugins.cajon.inspections package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.LocalQuickFix
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.TypeConversionUtil import com.intellij.psi.util.TypeConversionUtil
import de.platon42.intellij.plugins.cajon.MethodNames 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_NOT_NULL
import de.platon42.intellij.plugins.cajon.MethodNames.Companion.IS_NULL import de.platon42.intellij.plugins.cajon.MethodNames.Companion.IS_NULL
import de.platon42.intellij.plugins.cajon.findOutmostMethodCall
import de.platon42.intellij.plugins.cajon.firstArg import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.quickfixes.SplitBinaryExpressionMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.SplitBinaryExpressionMethodCallQuickFix
@@ -30,18 +31,13 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
return return
} }
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return val expectedCallExpression = expression.findOutmostMethodCall() ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val expectedResult = getExpectedBooleanResult(expectedCallExpression) ?: return val expectedResult = getExpectedBooleanResult(expectedCallExpression) ?: return
val assertThatArgument = expression.firstArg val assertThatArgument = expression.firstArg
if (assertThatArgument is PsiMethodCallExpression && OBJECT_EQUALS.test(assertThatArgument)) { if (assertThatArgument is PsiMethodCallExpression && OBJECT_EQUALS.test(assertThatArgument)) {
val replacementMethod = if (expectedResult) MethodNames.IS_EQUAL_TO else MethodNames.IS_NOT_EQUAL_TO val replacementMethod = if (expectedResult) MethodNames.IS_EQUAL_TO else MethodNames.IS_NOT_EQUAL_TO
val type = "${MethodNames.EQUALS}()" registerSplitMethod(holder, expression, "${MethodNames.EQUALS}()", replacementMethod, ::SplitEqualsExpressionMethodCallQuickFix)
val description = SPLIT_EXPRESSION_DESCRIPTION_TEMPLATE.format(type)
val message = MORE_MEANINGFUL_MESSAGE_TEMPLATE.format(type)
val quickFix = SplitEqualsExpressionMethodCallQuickFix(description, replacementMethod)
holder.registerProblem(expression, message, quickFix)
return return
} }
@@ -56,7 +52,9 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
return return
} else if (isLeftNull || isRightNull) { } else if (isLeftNull || isRightNull) {
val replacementMethod = if (expectedResult) IS_NULL else IS_NOT_NULL val replacementMethod = if (expectedResult) IS_NULL else IS_NOT_NULL
registerSplitBinaryExpressionMethod(holder, expression, replacementMethod, pickRightOperand = isLeftNull, noExpectedExpression = true) registerSplitMethod(holder, expression, "binary", replacementMethod) { desc, method ->
SplitBinaryExpressionMethodCallQuickFix(desc, method, pickRightOperand = isLeftNull, noExpectedExpression = true)
}
return return
} }
@@ -76,21 +74,22 @@ class AssertThatBinaryExpressionIsTrueOrFalseInspection : AbstractAssertJInspect
(isPrimitive || isNumericType).map(TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP, TOKEN_TO_ASSERTJ_FOR_OBJECT_MAPPINGS) (isPrimitive || isNumericType).map(TOKEN_TO_ASSERTJ_FOR_PRIMITIVE_MAP, TOKEN_TO_ASSERTJ_FOR_OBJECT_MAPPINGS)
val replacementMethod = mappingToUse[tokenType] ?: return val replacementMethod = mappingToUse[tokenType] ?: return
registerSplitBinaryExpressionMethod(holder, expression, replacementMethod, pickRightOperand = swapExpectedAndActual) registerSplitMethod(holder, expression, "binary", replacementMethod) { desc, method ->
SplitBinaryExpressionMethodCallQuickFix(desc, method, pickRightOperand = swapExpectedAndActual)
}
} }
private fun registerSplitBinaryExpressionMethod( private fun registerSplitMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
expression: PsiMethodCallExpression, expression: PsiMethodCallExpression,
type: String,
replacementMethod: String, replacementMethod: String,
pickRightOperand: Boolean = false, quickFixSupplier: (String, String) -> LocalQuickFix
noExpectedExpression: Boolean = false
) { ) {
val type = "binary"
val description = SPLIT_EXPRESSION_DESCRIPTION_TEMPLATE.format(type) val description = SPLIT_EXPRESSION_DESCRIPTION_TEMPLATE.format(type)
val message = MORE_MEANINGFUL_MESSAGE_TEMPLATE.format(type) val message = MORE_MEANINGFUL_MESSAGE_TEMPLATE.format(type)
val quickFix = SplitBinaryExpressionMethodCallQuickFix(description, replacementMethod, pickRightOperand, noExpectedExpression) val quickfix = quickFixSupplier(description, replacementMethod)
holder.registerProblem(expression, message, quickFix) holder.registerProblem(expression, message, quickfix)
} }
} }
} }
@@ -1,13 +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.JavaPsiFacade
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.AssertJClassNames import de.platon42.intellij.plugins.cajon.*
import de.platon42.intellij.plugins.cajon.MethodNames import de.platon42.intellij.plugins.cajon.quickfixes.*
import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
class AssertThatGuavaOptionalInspection : AbstractAssertJInspection() { class AssertThatGuavaOptionalInspection : AbstractAssertJInspection() {
@@ -27,35 +28,83 @@ class AssertThatGuavaOptionalInspection : AbstractAssertJInspection() {
if (!(ASSERT_THAT_ANY.test(expression) || assertThatGuava)) { if (!(ASSERT_THAT_ANY.test(expression) || assertThatGuava)) {
return return
} }
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return val expectedCallExpression = expression.findOutmostMethodCall() ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val isEqualTo = IS_EQUAL_TO_OBJECT.test(expectedCallExpression)
val isNotEqualTo = IS_NOT_EQUAL_TO_OBJECT.test(expectedCallExpression)
if (assertThatGuava) { if (assertThatGuava) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) { if (isEqualTo) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (GUAVA_OPTIONAL_OF.test(innerExpectedCall) || GUAVA_OPTIONAL_FROM_NULLABLE.test(innerExpectedCall)) { if (CallMatcher.anyOf(GUAVA_OPTIONAL_OF, GUAVA_OPTIONAL_FROM_NULLABLE).test(innerExpectedCall)) {
registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS) registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS, ::RemoveExpectedOutmostMethodCallQuickFix)
} else if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) { } else if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_ABSENT) registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_ABSENT)
} }
} else if (IS_NOT_EQUAL_TO_OBJECT.test(expectedCallExpression)) { } else if (isNotEqualTo) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) { if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_PRESENT) registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_PRESENT)
} }
} }
} else { } else {
val actualExpression = expression.firstArg as? PsiMethodCallExpression ?: return // we're not calling an assertThat() from Guava, but a core-AssertJ one!
// We need to replace that by the Guava one, if we want to apply a formally correct fix.
if (GUAVA_OPTIONAL_GET.test(actualExpression) && IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) { val actualExpression = expression.firstArg as? PsiMethodCallExpression
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS) if (actualExpression != null) {
} else if (GUAVA_OPTIONAL_IS_PRESENT.test(actualExpression)) { if (GUAVA_OPTIONAL_GET.test(actualExpression) && isEqualTo) {
val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return registerRemoveActualOutmostForGuavaMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS)
val replacementMethod = expectedPresence.map(MethodNames.IS_PRESENT, MethodNames.IS_ABSENT) } else if (GUAVA_OPTIONAL_IS_PRESENT.test(actualExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true) val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return
val replacementMethod = expectedPresence.map(MethodNames.IS_PRESENT, MethodNames.IS_ABSENT)
registerRemoveActualOutmostForGuavaMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true)
}
}
if (isEqualTo) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (CallMatcher.anyOf(GUAVA_OPTIONAL_OF, GUAVA_OPTIONAL_FROM_NULLABLE).test(innerExpectedCall)) {
registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS) { desc, method ->
QuickFixWithPostfixDelegate(
RemoveExpectedOutmostMethodCallQuickFix(desc, method),
ForGuavaPostFix.REPLACE_BY_GUAVA_ASSERT_THAT_AND_STATIC_IMPORT
)
}
} else if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) {
registerSimplifyForGuavaMethod(holder, expectedCallExpression, MethodNames.IS_ABSENT)
}
} else if (isNotEqualTo) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (GUAVA_OPTIONAL_ABSENT.test(innerExpectedCall)) {
registerSimplifyForGuavaMethod(holder, expectedCallExpression, MethodNames.IS_PRESENT)
}
} }
} }
} }
} }
} }
private fun registerRemoveActualOutmostForGuavaMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
oldExpectedCallExpression: PsiMethodCallExpression,
replacementMethod: String,
noExpectedExpression: Boolean = false
) {
registerRemoveActualOutmostMethod(holder, expression, oldExpectedCallExpression, replacementMethod) { desc, method ->
QuickFixWithPostfixDelegate(
RemoveActualOutmostMethodCallQuickFix(desc, method, noExpectedExpression),
ForGuavaPostFix.REPLACE_BY_GUAVA_ASSERT_THAT_AND_STATIC_IMPORT
)
}
}
private fun registerSimplifyForGuavaMethod(holder: ProblemsHolder, expression: PsiMethodCallExpression, replacementMethod: String) {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = SIMPLIFY_MESSAGE_TEMPLATE.format(originalMethod, replacementMethod)
val quickFix = QuickFixWithPostfixDelegate(
ReplaceSimpleMethodCallQuickFix(description, replacementMethod),
ForGuavaPostFix.REPLACE_BY_GUAVA_ASSERT_THAT_AND_STATIC_IMPORT
)
holder.registerProblem(expression, message, quickFix)
}
} }
@@ -4,11 +4,13 @@ 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 com.intellij.psi.PsiStatement import com.siyeh.ig.callMatcher.CallMatcher
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.MethodNames import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.findOutmostMethodCall
import de.platon42.intellij.plugins.cajon.firstArg import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.quickfixes.RemoveActualOutmostMethodCallQuickFix
import de.platon42.intellij.plugins.cajon.quickfixes.RemoveExpectedOutmostMethodCallQuickFix
class AssertThatJava8OptionalInspection : AbstractAssertJInspection() { class AssertThatJava8OptionalInspection : AbstractAssertJInspection() {
@@ -25,14 +27,13 @@ class AssertThatJava8OptionalInspection : AbstractAssertJInspection() {
if (!ASSERT_THAT_ANY.test(expression)) { if (!ASSERT_THAT_ANY.test(expression)) {
return return
} }
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return val expectedCallExpression = expression.findOutmostMethodCall() ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
if (ASSERT_THAT_JAVA8_OPTIONAL.test(expression)) { if (ASSERT_THAT_JAVA8_OPTIONAL.test(expression)) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) { if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return val innerExpectedCall = expectedCallExpression.firstArg as? PsiMethodCallExpression ?: return
if (OPTIONAL_OF.test(innerExpectedCall) || OPTIONAL_OF_NULLABLE.test(innerExpectedCall)) { if (CallMatcher.anyOf(OPTIONAL_OF, OPTIONAL_OF_NULLABLE).test(innerExpectedCall)) {
registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS) registerRemoveExpectedOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS, ::RemoveExpectedOutmostMethodCallQuickFix)
} else if (OPTIONAL_EMPTY.test(innerExpectedCall)) { } else if (OPTIONAL_EMPTY.test(innerExpectedCall)) {
registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_NOT_PRESENT) registerSimplifyMethod(holder, expectedCallExpression, MethodNames.IS_NOT_PRESENT)
} }
@@ -47,14 +48,20 @@ class AssertThatJava8OptionalInspection : AbstractAssertJInspection() {
if (OPTIONAL_GET.test(actualExpression)) { if (OPTIONAL_GET.test(actualExpression)) {
if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) { if (IS_EQUAL_TO_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS) registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS) { desc, method ->
RemoveActualOutmostMethodCallQuickFix(desc, method)
}
} else if (IS_SAME_AS_OBJECT.test(expectedCallExpression)) { } else if (IS_SAME_AS_OBJECT.test(expectedCallExpression)) {
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS_SAME) registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, MethodNames.CONTAINS_SAME) { desc, method ->
RemoveActualOutmostMethodCallQuickFix(desc, method)
}
} }
} else if (OPTIONAL_IS_PRESENT.test(actualExpression)) { } else if (OPTIONAL_IS_PRESENT.test(actualExpression)) {
val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return val expectedPresence = getExpectedBooleanResult(expectedCallExpression) ?: return
val replacementMethod = expectedPresence.map(MethodNames.IS_PRESENT, MethodNames.IS_NOT_PRESENT) val replacementMethod = expectedPresence.map(MethodNames.IS_PRESENT, MethodNames.IS_NOT_PRESENT)
registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true) registerRemoveActualOutmostMethod(holder, expression, expectedCallExpression, replacementMethod) { desc, method ->
RemoveActualOutmostMethodCallQuickFix(desc, method, noExpectedExpression = true)
}
} }
} }
} }
@@ -2,9 +2,9 @@ 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 de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.ABSTRACT_ITERABLE_ASSERT_CLASSNAME 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.MethodNames
import de.platon42.intellij.plugins.cajon.findOutmostMethodCall
import de.platon42.intellij.plugins.cajon.firstArg import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSizeMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceSizeMethodCallQuickFix
@@ -34,18 +34,23 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
val actualExpression = expression.firstArg val actualExpression = expression.firstArg
if (isArrayLength(actualExpression) || isCollectionSize(actualExpression)) { if (isArrayLength(actualExpression) || isCollectionSize(actualExpression)) {
val statement = PsiTreeUtil.getParentOfType(expression, PsiStatement::class.java) ?: return val expectedCallExpression = expression.findOutmostMethodCall() ?: return
val expectedCallExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
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) {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, MethodNames.IS_EMPTY, noExpectedExpression = true) registerReplaceMethod(holder, expression, expectedCallExpression, MethodNames.IS_EMPTY) { desc, method ->
ReplaceSizeMethodCallQuickFix(desc, method, noExpectedExpression = true)
}
} else { } else {
val equalToExpression = expectedCallExpression.firstArg val equalToExpression = expectedCallExpression.firstArg
if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) { if (isCollectionSize(equalToExpression) || isArrayLength(equalToExpression)) {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, MethodNames.HAS_SAME_SIZE_AS, expectedIsCollection = true) registerReplaceMethod(holder, expression, expectedCallExpression, MethodNames.HAS_SAME_SIZE_AS) { desc, method ->
ReplaceSizeMethodCallQuickFix(desc, method, expectedIsCollection = true)
}
} else { } else {
registerReplaceSizeMethod(holder, expression, expectedCallExpression, MethodNames.HAS_SIZE) registerReplaceMethod(holder, expression, expectedCallExpression, MethodNames.HAS_SIZE) { desc, method ->
ReplaceSizeMethodCallQuickFix(desc, method)
}
} }
} }
} else { } else {
@@ -57,11 +62,15 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
|| IS_NOT_ZERO.test(expectedCallExpression)) || IS_NOT_ZERO.test(expectedCallExpression))
if (isTestForEmpty || isTestForNotEmpty) { if (isTestForEmpty || isTestForNotEmpty) {
val replacementMethod = isTestForEmpty.map(MethodNames.IS_EMPTY, MethodNames.IS_NOT_EMPTY) val replacementMethod = isTestForEmpty.map(MethodNames.IS_EMPTY, MethodNames.IS_NOT_EMPTY)
registerReplaceSizeMethod(holder, expression, expectedCallExpression, replacementMethod, noExpectedExpression = true) registerReplaceMethod(holder, expression, expectedCallExpression, replacementMethod) { desc, method ->
ReplaceSizeMethodCallQuickFix(desc, method, noExpectedExpression = true)
}
} else if (hasAssertJMethod(expression, ABSTRACT_ITERABLE_ASSERT_CLASSNAME, MethodNames.HAS_SIZE_LESS_THAN)) { } 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
val matchedMethod = BONUS_EXPRESSIONS_CALL_MATCHER_MAP.find { it.first.test(expectedCallExpression) }?.second ?: return val matchedMethod = BONUS_EXPRESSIONS_CALL_MATCHER_MAP.find { it.first.test(expectedCallExpression) }?.second ?: return
registerReplaceSizeMethod(holder, expression, expectedCallExpression, matchedMethod) registerReplaceMethod(holder, expression, expectedCallExpression, matchedMethod) { desc, method ->
ReplaceSizeMethodCallQuickFix(desc, method)
}
} }
} }
} }
@@ -74,21 +83,6 @@ class AssertThatSizeInspection : AbstractAssertJInspection() {
return ((psiReferenceExpression.qualifierExpression?.type is PsiArrayType) return ((psiReferenceExpression.qualifierExpression?.type is PsiArrayType)
&& ((psiReferenceExpression.resolve() as? PsiField)?.name == "length")) && ((psiReferenceExpression.resolve() as? PsiField)?.name == "length"))
} }
private fun registerReplaceSizeMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
expectedCallExpression: PsiMethodCallExpression,
replacementMethod: String,
noExpectedExpression: Boolean = false,
expectedIsCollection: 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 = ReplaceSizeMethodCallQuickFix(description, replacementMethod, noExpectedExpression, expectedIsCollection)
holder.registerProblem(expression, message, quickfix)
}
} }
} }
} }
@@ -1,10 +1,12 @@
package de.platon42.intellij.plugins.cajon.inspections package de.platon42.intellij.plugins.cajon.inspections
import com.intellij.codeInspection.LocalQuickFix
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.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 com.siyeh.ig.callMatcher.CallMatcher.staticCall
import de.platon42.intellij.plugins.cajon.AssertJClassNames import de.platon42.intellij.plugins.cajon.AssertJClassNames
import de.platon42.intellij.plugins.cajon.MethodNames import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitAssertMethodCallQuickFix import de.platon42.intellij.plugins.cajon.quickfixes.ReplaceJUnitAssertMethodCallQuickFix
@@ -18,91 +20,91 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
private val MAPPINGS = listOf( private val MAPPINGS = listOf(
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes("boolean") staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_TRUE_METHOD).parameterTypes("boolean")
), ),
MethodNames.IS_TRUE, false MethodNames.IS_TRUE, false
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "boolean"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes("boolean") staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_FALSE_METHOD).parameterTypes("boolean")
), ),
MethodNames.IS_FALSE, 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), 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) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)
), ),
MethodNames.IS_NULL, 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), 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) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_NULL_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_OBJECT)
), ),
MethodNames.IS_NOT_NULL, false MethodNames.IS_NOT_NULL, false
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double", "double", "double"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("double", "double", "double"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"), 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") staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterTypes("float", "float", "float")
), ),
MethodNames.IS_CLOSE_TO, hasDelta = true MethodNames.IS_CLOSE_TO, hasDelta = true
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_EQUALS_METHOD).parameterCount(2)
), ),
MethodNames.IS_EQUAL_TO MethodNames.IS_EQUAL_TO
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double", "double", "double"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("double", "double", "double"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("double", "double", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float", "float", "float"), 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") staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterTypes("float", "float", "float")
), ),
MethodNames.IS_NOT_CLOSE_TO, hasDelta = true MethodNames.IS_NOT_CLOSE_TO, hasDelta = true
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_EQUALS_METHOD).parameterCount(2)
), ),
MethodNames.IS_NOT_EQUAL_TO MethodNames.IS_NOT_EQUAL_TO
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_SAME_METHOD).parameterCount(2)
), ),
MethodNames.IS_SAME_AS MethodNames.IS_SAME_AS
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(3),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_NOT_SAME_METHOD).parameterCount(2)
), ),
MethodNames.IS_NOT_SAME_AS MethodNames.IS_NOT_SAME_AS
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double[]", "double[]", "double"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "double[]", "double[]", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("double[]", "double[]", "double"), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("double[]", "double[]", "double"),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes(CommonClassNames.JAVA_LANG_STRING, "float[]", "float[]", "float"), 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") staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterTypes("float[]", "float[]", "float")
), ),
MethodNames.CONTAINS_EXACTLY, hasDelta = true MethodNames.CONTAINS_EXACTLY, hasDelta = true
), ),
Mapping( Mapping(
anyOf( anyOf(
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2), staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(2),
CallMatcher.staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3) staticCall(JUNIT_ASSERT_CLASSNAME, ASSERT_ARRAY_EQUALS_METHOD).parameterCount(3)
), ),
MethodNames.CONTAINS_EXACTLY MethodNames.CONTAINS_EXACTLY
) )
@@ -121,43 +123,29 @@ class JUnitAssertToAssertJInspection : AbstractJUnitAssertInspection() {
} }
JavaPsiFacade.getInstance(expression.project) JavaPsiFacade.getInstance(expression.project)
.findClass(AssertJClassNames.ASSERTIONS_CLASSNAME, GlobalSearchScope.allScope(expression.project)) ?: return .findClass(AssertJClassNames.ASSERTIONS_CLASSNAME, GlobalSearchScope.allScope(expression.project)) ?: return
for (mapping in MAPPINGS) { val mapping = MAPPINGS.firstOrNull { it.callMatcher.test(expression) } ?: return
if (mapping.callMatcher.test(expression)) { if (mapping.hasDelta) {
if (mapping.hasDelta) { registerConvertMethod(holder, expression, mapping.replacement, ::ReplaceJUnitDeltaAssertMethodCallQuickFix)
registerDeltaReplacementMethod(holder, expression, mapping.replacement) } else {
} else { registerConvertMethod(holder, expression, mapping.replacement) { desc, method ->
registerSimpleReplacementMethod(holder, expression, mapping.hasExpected, mapping.replacement) ReplaceJUnitAssertMethodCallQuickFix(desc, method, !mapping.hasExpected)
}
return
} }
} }
} }
} }
} }
private fun registerSimpleReplacementMethod( private fun registerConvertMethod(
holder: ProblemsHolder, holder: ProblemsHolder,
expression: PsiMethodCallExpression, expression: PsiMethodCallExpression,
hasExpected: Boolean, replacementMethod: String,
replacementMethod: String quickFixSupplier: (String, String) -> LocalQuickFix
) { ) {
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)
val quickFix = ReplaceJUnitAssertMethodCallQuickFix(description, !hasExpected, replacementMethod) val quickfix = quickFixSupplier(description, replacementMethod)
holder.registerProblem(expression, message, quickFix) holder.registerProblem(expression, message, quickfix)
}
private fun registerDeltaReplacementMethod(
holder: ProblemsHolder,
expression: PsiMethodCallExpression,
replacementMethod: String
) {
val originalMethod = getOriginalMethodName(expression) ?: return
val description = REPLACE_DESCRIPTION_TEMPLATE.format(originalMethod, replacementMethod)
val message = CONVERT_MESSAGE_TEMPLATE.format(originalMethod)
val quickFix = ReplaceJUnitDeltaAssertMethodCallQuickFix(description, replacementMethod)
holder.registerProblem(expression, message, quickFix)
} }
private class Mapping( private class Mapping(
@@ -1,35 +1,9 @@
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.*
import de.platon42.intellij.plugins.cajon.AssertJClassNames
import de.platon42.intellij.plugins.cajon.MethodNames
import de.platon42.intellij.plugins.cajon.firstArg
abstract class AbstractCommonQuickFix(private val description: String) : LocalQuickFix { abstract class AbstractCommonQuickFix(private val description: String) : LocalQuickFix {
override fun getFamilyName() = description override fun getFamilyName() = description
protected fun addStaticImport(method: PsiMethod, element: PsiMethodCallExpression, factory: PsiElementFactory, vararg allowedClashes: String) {
val methodName = method.name
val containingClass = method.containingClass ?: return
val importList = (element.containingFile as PsiJavaFile).importList ?: return
val notImportedStatically = importList.importStaticStatements.none {
val targetClass = it.resolveTargetClass() ?: return@none false
((it.referenceName == methodName) && !allowedClashes.contains(targetClass.qualifiedName))
|| (it.isOnDemand && (targetClass == method.containingClass))
}
if (notImportedStatically) {
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,25 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.cajon.*
class ForGuavaPostFix {
companion object {
val REPLACE_BY_GUAVA_ASSERT_THAT_AND_STATIC_IMPORT: (Project, ProblemDescriptor) -> Unit = exit@
{ _, descriptor ->
val element = descriptor.startElement
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return@exit
val assertThatCall = PsiTreeUtil.findChildrenOfType(statement, PsiMethodCallExpression::class.java).find { CORE_ASSERT_THAT_MATCHER.test(it) } ?: return@exit
val newMethodCall = createGuavaAssertThat(element, assertThatCall.firstArg)
newMethodCall.resolveMethod()?.addAsStaticImport(element, AssertJClassNames.ASSERTIONS_CLASSNAME)
val parentCall = PsiTreeUtil.getParentOfType(assertThatCall, PsiMethodCallExpression::class.java) ?: return@exit
parentCall.replaceQualifier(newMethodCall)
parentCall.shortenAndReformat()
}
}
}
@@ -0,0 +1,16 @@
package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
class QuickFixWithPostfixDelegate(
private val mainFix: LocalQuickFix,
private val postfix: (Project, ProblemDescriptor) -> Unit
) : LocalQuickFix by mainFix {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
mainFix.applyFix(project, descriptor)
postfix(project, descriptor)
}
}
@@ -2,19 +2,13 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement import de.platon42.intellij.plugins.cajon.*
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( class RemoveActualOutmostMethodCallQuickFix(
description: String, description: String,
private val replacementMethod: String, private val replacementMethod: String,
private val noExpectedExpression: Boolean private val noExpectedExpression: Boolean = false
) : AbstractCommonQuickFix(description) { ) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
@@ -22,16 +16,10 @@ class RemoveActualOutmostMethodCallQuickFix(
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val assertExpression = methodCallExpression.firstArg as? PsiMethodCallExpression ?: return val assertExpression = methodCallExpression.firstArg as? PsiMethodCallExpression ?: return
assertExpression.replace(assertExpression.qualifierExpression) 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 oldExpectedExpression = element.findOutmostMethodCall() ?: return
val expectedExpression = factory.createExpressionFromText( val args = if (noExpectedExpression) emptyArray() else oldExpectedExpression.argumentList.expressions
"a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element val expectedExpression = createExpectedMethodCall(element, replacementMethod, *args)
) as PsiMethodCallExpression
if (!noExpectedExpression) {
expectedExpression.firstArg.replace(oldExpectedExpression.firstArg)
}
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
@@ -2,10 +2,9 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement import de.platon42.intellij.plugins.cajon.createExpectedMethodCall
import com.intellij.psi.util.PsiTreeUtil import de.platon42.intellij.plugins.cajon.findOutmostMethodCall
import de.platon42.intellij.plugins.cajon.firstArg import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
@@ -13,14 +12,9 @@ class RemoveExpectedOutmostMethodCallQuickFix(description: String, private val r
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.startElement val element = descriptor.startElement
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return val oldExpectedExpression = element.findOutmostMethodCall() ?: 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 val expectedMethodCallExpression = oldExpectedExpression.firstArg as? PsiMethodCallExpression ?: return
expectedExpression.firstArg.replace(expectedMethodCallExpression.firstArg) val expectedExpression = createExpectedMethodCall(element, replacementMethod, expectedMethodCallExpression.firstArg)
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
@@ -2,17 +2,12 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiExpression
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.codeStyle.CodeStyleManager import de.platon42.intellij.plugins.cajon.*
import com.intellij.psi.codeStyle.JavaCodeStyleManager
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME 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 noExpectedExpression: Boolean, private val replacementMethod: String) : class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val replacementMethod: String, private val noExpectedExpression: Boolean) :
AbstractCommonQuickFix(description) { AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
@@ -22,39 +17,26 @@ class ReplaceJUnitAssertMethodCallQuickFix(description: String, private val noEx
val count = args.expressions.size val count = args.expressions.size
val actualExpression = args.expressions[count - 1] ?: return val actualExpression = args.expressions[count - 1] ?: return
val (expectedExpression, messageExpression) = if (noExpectedExpression) { val (expectedExpression, messageExpression) = if (noExpectedExpression) {
val message = if (count > 1) args.expressions[0] else null val message = args.expressions.getOrNull(count - 2)
null to message emptyArray<PsiExpression>() to message
} else { } 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 = args.expressions.getOrNull(count - 3)
expected to message arrayOf(expected) to message
}
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedMethodCall = factory.createExpressionFromText(
"a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element
) as PsiMethodCallExpression
if (!noExpectedExpression) {
expectedMethodCall.firstArg.replace(expectedExpression!!)
} }
val expectedMethodCall = createExpectedMethodCall(element, replacementMethod, *expectedExpression)
val newMethodCall = createAssertThat(element, actualExpression) val newMethodCall = createAssertThat(element, actualExpression)
if (messageExpression != null) { if (messageExpression != null) {
val asExpression = factory.createExpressionFromText("a.${MethodNames.AS}(desc)", element) as PsiMethodCallExpression val asExpression = createExpectedMethodCall(element, MethodNames.AS, messageExpression)
asExpression.firstArg.replace(messageExpression)
asExpression.replaceQualifier(newMethodCall) asExpression.replaceQualifier(newMethodCall)
expectedMethodCall.replaceQualifier(asExpression) expectedMethodCall.replaceQualifier(asExpression)
} else { } else {
expectedMethodCall.replaceQualifier(newMethodCall) expectedMethodCall.replaceQualifier(newMethodCall)
} }
val assertThatMethod = newMethodCall.resolveMethod() ?: return newMethodCall.resolveMethod()?.addAsStaticImport(element, GUAVA_ASSERTIONS_CLASSNAME)
addStaticImport(assertThatMethod, element, factory, GUAVA_ASSERTIONS_CLASSNAME) element.replace(expectedMethodCall).shortenAndReformat()
val codeStyleManager = JavaCodeStyleManager.getInstance(element.project)
val newElement = element.replace(expectedMethodCall)
val shortened = codeStyleManager.shortenClassReferences(newElement)
CodeStyleManager.getInstance(element.project).reformat(shortened)
} }
} }
@@ -2,14 +2,9 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.codeStyle.CodeStyleManager import de.platon42.intellij.plugins.cajon.*
import com.intellij.psi.codeStyle.JavaCodeStyleManager
import de.platon42.intellij.plugins.cajon.AssertJClassNames.Companion.GUAVA_ASSERTIONS_CLASSNAME 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) {
@@ -18,44 +13,25 @@ class ReplaceJUnitDeltaAssertMethodCallQuickFix(description: String, private val
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val args = methodCallExpression.argumentList val args = methodCallExpression.argumentList
val count = args.expressions.size val count = args.expressions.size
val actualExpression = args.expressions[count - 2] ?: return val messageExpression = args.expressions.getOrNull(count - 4)
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 actualExpression = args.expressions[count - 2] ?: return
val deltaExpression = args.expressions[count - 1] ?: return val deltaExpression = args.expressions[count - 1] ?: return
val factory = JavaPsiFacade.getElementFactory(element.project) val offsetMethodCall = createMethodCall(element, "org.assertj.core.data.Offset.offset", deltaExpression)
val offsetMethodCall = factory.createExpressionFromText( val expectedMethodCall = createExpectedMethodCall(element, replacementMethod, expectedExpression, offsetMethodCall)
"org.assertj.core.data.Offset.offset(c)", element
) as PsiMethodCallExpression
offsetMethodCall.firstArg.replace(deltaExpression)
val expectedMethodCall = factory.createExpressionFromText(
"a.$replacementMethod(e, offs)", element
) as PsiMethodCallExpression
expectedMethodCall.firstArg.replace(expectedExpression)
expectedMethodCall.getArg(1).replace(offsetMethodCall)
val newMethodCall = createAssertThat(element, actualExpression) val newMethodCall = createAssertThat(element, actualExpression)
if (messageExpression != null) { if (messageExpression != null) {
val asExpression = factory.createExpressionFromText("a.as(desc)", element) as PsiMethodCallExpression val asExpression = createExpectedMethodCall(element, MethodNames.AS, messageExpression)
asExpression.firstArg.replace(messageExpression)
asExpression.replaceQualifier(newMethodCall) asExpression.replaceQualifier(newMethodCall)
expectedMethodCall.replaceQualifier(asExpression) expectedMethodCall.replaceQualifier(asExpression)
} else { } else {
expectedMethodCall.replaceQualifier(newMethodCall) expectedMethodCall.replaceQualifier(newMethodCall)
} }
val assertThatMethod = newMethodCall.resolveMethod() ?: return newMethodCall.resolveMethod()?.addAsStaticImport(element, GUAVA_ASSERTIONS_CLASSNAME)
addStaticImport(assertThatMethod, element, factory, GUAVA_ASSERTIONS_CLASSNAME) offsetMethodCall.resolveMethod()?.addAsStaticImport(element)
val offsetMethod = offsetMethodCall.resolveMethod() ?: return element.replace(expectedMethodCall).shortenAndReformat()
addStaticImport(offsetMethod, element, factory)
val codeStyleManager = JavaCodeStyleManager.getInstance(element.project)
val newElement = element.replace(expectedMethodCall)
val shortened = codeStyleManager.shortenClassReferences(newElement)
CodeStyleManager.getInstance(element.project).reformat(shortened)
} }
} }
@@ -2,19 +2,19 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.createExpectedMethodCall
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall 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 methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val expectedExpression = createExpectedMethodCall(element, replacementMethod)
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression =
factory.createExpressionFromText("a.$replacementMethod()", element) as PsiMethodCallExpression
expectedExpression.replaceQualifierFromMethodCall(methodCallExpression) expectedExpression.replaceQualifierFromMethodCall(methodCallExpression)
element.replace(expectedExpression) element.replace(expectedExpression)
} }
@@ -2,18 +2,16 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiExpression
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.PsiMethodCallExpression
import de.platon42.intellij.plugins.cajon.firstArg import com.intellij.psi.PsiReferenceExpression
import de.platon42.intellij.plugins.cajon.map import de.platon42.intellij.plugins.cajon.*
import de.platon42.intellij.plugins.cajon.qualifierExpression
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class ReplaceSizeMethodCallQuickFix( class ReplaceSizeMethodCallQuickFix(
description: String, description: String,
private val replacementMethod: String, private val replacementMethod: String,
private val noExpectedExpression: Boolean, private val noExpectedExpression: Boolean = false,
private val expectedIsCollection: Boolean private val expectedIsCollection: Boolean = false
) : AbstractCommonQuickFix(description) { ) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
@@ -21,19 +19,15 @@ class ReplaceSizeMethodCallQuickFix(
val methodCallExpression = element as? PsiMethodCallExpression ?: return val methodCallExpression = element as? PsiMethodCallExpression ?: return
val assertExpression = methodCallExpression.firstArg val assertExpression = methodCallExpression.firstArg
replaceCollectionSizeOrArrayLength(assertExpression) replaceCollectionSizeOrArrayLength(assertExpression)
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return val oldExpectedExpression = element.findOutmostMethodCall() ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return
val factory = JavaPsiFacade.getElementFactory(element.project) if (expectedIsCollection) {
val expectedExpression = factory.createExpressionFromText( replaceCollectionSizeOrArrayLength(oldExpectedExpression.firstArg)
"a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element
) as PsiMethodCallExpression
if (!noExpectedExpression) {
if (expectedIsCollection) {
replaceCollectionSizeOrArrayLength(oldExpectedExpression.firstArg)
}
expectedExpression.firstArg.replace(oldExpectedExpression.firstArg)
} }
val args = if (noExpectedExpression) emptyArray() else arrayOf(oldExpectedExpression.firstArg)
val expectedExpression = createExpectedMethodCall(element, replacementMethod, *args)
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
@@ -2,20 +2,18 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiBinaryExpression import com.intellij.psi.PsiBinaryExpression
import com.intellij.psi.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement import de.platon42.intellij.plugins.cajon.createExpectedMethodCall
import com.intellij.psi.util.PsiTreeUtil import de.platon42.intellij.plugins.cajon.findOutmostMethodCall
import de.platon42.intellij.plugins.cajon.firstArg import de.platon42.intellij.plugins.cajon.firstArg
import de.platon42.intellij.plugins.cajon.map
import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall import de.platon42.intellij.plugins.cajon.replaceQualifierFromMethodCall
class SplitBinaryExpressionMethodCallQuickFix( class SplitBinaryExpressionMethodCallQuickFix(
description: String, description: String,
private val replacementMethod: String, private val replacementMethod: String,
private val pickRightOperand: Boolean, private val pickRightOperand: Boolean = false,
private val noExpectedExpression: Boolean private val noExpectedExpression: Boolean = false
) : AbstractCommonQuickFix(description) { ) : AbstractCommonQuickFix(description) {
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
@@ -25,16 +23,9 @@ class SplitBinaryExpressionMethodCallQuickFix(
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 oldExpectedExpression = element.findOutmostMethodCall() ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return val args = if (noExpectedExpression) emptyArray() else arrayOf(expectedArgument)
val expectedExpression = createExpectedMethodCall(element, replacementMethod, *args)
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression = factory.createExpressionFromText(
"a.$replacementMethod${noExpectedExpression.map("()", "(e)")}", element
) as PsiMethodCallExpression
if (!noExpectedExpression) {
expectedExpression.firstArg.replace(expectedArgument)
}
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
@@ -2,13 +2,8 @@ package de.platon42.intellij.plugins.cajon.quickfixes
import com.intellij.codeInspection.ProblemDescriptor 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.PsiMethodCallExpression import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiStatement import de.platon42.intellij.plugins.cajon.*
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) {
@@ -19,14 +14,8 @@ class SplitEqualsExpressionMethodCallQuickFix(description: String, private val r
val expectedArgument = equalsMethodCall.firstArg.copy() val expectedArgument = equalsMethodCall.firstArg.copy()
equalsMethodCall.replace(equalsMethodCall.qualifierExpression) equalsMethodCall.replace(equalsMethodCall.qualifierExpression)
val statement = PsiTreeUtil.getParentOfType(element, PsiStatement::class.java) ?: return val oldExpectedExpression = element.findOutmostMethodCall() ?: return
val oldExpectedExpression = PsiTreeUtil.findChildOfType(statement, PsiMethodCallExpression::class.java) ?: return val expectedExpression = createExpectedMethodCall(element, replacementMethod, expectedArgument)
val factory = JavaPsiFacade.getElementFactory(element.project)
val expectedExpression = factory.createExpressionFromText(
"a.$replacementMethod(e)", element
) as PsiMethodCallExpression
expectedExpression.firstArg.replace(expectedArgument)
expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression) expectedExpression.replaceQualifierFromMethodCall(oldExpectedExpression)
oldExpectedExpression.replace(expectedExpression) oldExpectedExpression.replace(expectedExpression)
} }
@@ -0,0 +1,162 @@
package de.platon42.intellij.plugins.cajon.references
import com.intellij.lang.jvm.JvmModifier
import com.intellij.openapi.util.TextRange
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.*
import com.intellij.psi.util.PropertyUtilBase
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.PsiTypesUtil
import com.intellij.util.ProcessingContext
import com.siyeh.ig.callMatcher.CallMatcher
import de.platon42.intellij.plugins.cajon.AssertJClassNames
import de.platon42.intellij.plugins.cajon.CORE_ASSERT_THAT_MATCHER
import de.platon42.intellij.plugins.cajon.firstArg
class ExtractorReferenceContributor : PsiReferenceContributor() {
companion object {
private val EXTRACTING_FROM_OBJECT = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_OBJECT_ASSERT_CLASSNAME, "extracting")
private val EXTRACTING_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "extracting")
private val FLAT_EXTRACTING_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "flatExtracting")
private val EXTRACTING_RESULT_OF_FROM_ITERABLE = CallMatcher.instanceCall(AssertJClassNames.ABSTRACT_ITERABLE_ASSERT_CLASSNAME, "extractingResultOf")
private val BY_NAME = CallMatcher.staticCall(AssertJClassNames.EXTRACTORS_CLASSNAME, "byName")
private val RESULT_OF = CallMatcher.staticCall(AssertJClassNames.EXTRACTORS_CLASSNAME, "resultOf")
.parameterTypes(CommonClassNames.JAVA_LANG_STRING)!!
private val propertyOrFieldReferenceProvider = PropertyOrFieldReferenceProvider()
private val iterablePropertyOrFieldReferenceProvider = IterablePropertyOrFieldReferenceProvider()
private val iterableResultOfReferenceProvider = IterableResultOfReferenceProvider()
private fun lookupFieldOrProperty(containingClass: PsiClass, path: String, startOffset: Int): List<Pair<TextRange, List<PsiElement>>> {
val partName = path.substring(startOffset).substringBefore(".")
val nextOffset = startOffset + partName.length + 1
val matchedGetter = PropertyUtilBase.findPropertyGetter(containingClass, partName, false, true)
val fieldResult = PropertyUtilBase.findPropertyField(containingClass, partName, false)
val textRange = TextRange(startOffset + 1, nextOffset)
val matchedBareMethod = containingClass.allMethods.find { (it.name == partName) && !it.hasModifier(JvmModifier.STATIC) }
val targets = listOfNotNull<PsiElement>(fieldResult, matchedGetter, matchedBareMethod)
if (targets.isNotEmpty()) {
val results = listOf(textRange to targets)
if (nextOffset >= path.length) {
return results
}
val nextClass = PsiTypesUtil.getPsiClass(matchedGetter?.returnType ?: fieldResult?.type) ?: return results
return listOf(results, lookupFieldOrProperty(nextClass, path, nextOffset)).flatten()
}
return emptyList()
}
private fun lookupMethod(containingClass: PsiClass, methodName: String): List<Pair<TextRange, List<PsiElement>>>? {
val matchedMethod = containingClass.allMethods.find { (it.name == methodName) && !it.hasModifier(JvmModifier.STATIC) } ?: return null
val textRange = TextRange(1, methodName.length + 1)
return listOf(textRange to listOf(matchedMethod))
}
private fun findActualType(element: PsiElement): PsiClassType? {
val assertThatCall = PsiTreeUtil.findChildrenOfType(element, PsiMethodCallExpression::class.java)
.find { CORE_ASSERT_THAT_MATCHER.test(it) } ?: return null
return assertThatCall.firstArg.type as? PsiClassType
}
private fun findAndCreateReferences(element: PsiElement, finder: (PsiLiteralExpression) -> List<Pair<TextRange, List<PsiElement>>>?): Array<PsiReference> {
val literal = element as PsiLiteralExpression
val results = finder(literal)
if (results != null) {
return results.map { ExtractorReference(literal, it.first, it.second) }.toTypedArray()
}
return PsiReference.EMPTY_ARRAY
}
}
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralExpression::class.java), propertyOrFieldReferenceProvider)
registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralExpression::class.java), iterablePropertyOrFieldReferenceProvider)
registrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiLiteralExpression::class.java), iterableResultOfReferenceProvider)
}
class ExtractorReference(literal: PsiLiteralExpression, range: TextRange, private val targets: List<PsiElement>) :
PsiPolyVariantReferenceBase<PsiLiteralExpression>(literal, range, true) {
override fun resolve(): PsiElement? {
return multiResolve(false).map(ResolveResult::getElement).firstOrNull()
}
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> {
return PsiElementResolveResult.createResults(targets)
}
}
class PropertyOrFieldReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return findAndCreateReferences(element, ::findReferences)
}
fun findReferences(element: PsiLiteralExpression): List<Pair<TextRange, List<PsiElement>>>? {
val literal = element.value as? String ?: return null
var methodCallExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression::class.java) ?: return null
var isResultOf = false
if (BY_NAME.test(methodCallExpression)) {
methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression::class.java) ?: return null
} else if (RESULT_OF.test(methodCallExpression)) {
methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression::class.java) ?: return null
isResultOf = true
}
if (!EXTRACTING_FROM_OBJECT.test(methodCallExpression)) {
return emptyList()
}
val containingClass = PsiTypesUtil.getPsiClass(findActualType(methodCallExpression)) ?: return null
return if (isResultOf) lookupMethod(containingClass, literal) else lookupFieldOrProperty(containingClass, literal, 0)
}
}
class IterablePropertyOrFieldReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return findAndCreateReferences(element, ::findReferences)
}
fun findReferences(element: PsiLiteralExpression): List<Pair<TextRange, List<PsiElement>>>? {
val literal = element.value as? String ?: return null
var methodCallExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression::class.java) ?: return null
var isResultOf = false
if (BY_NAME.test(methodCallExpression)) {
methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression::class.java) ?: return null
} else if (RESULT_OF.test(methodCallExpression)) {
methodCallExpression = PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression::class.java) ?: return null
isResultOf = true
}
if (!CallMatcher.anyOf(EXTRACTING_FROM_ITERABLE, FLAT_EXTRACTING_FROM_ITERABLE).test(methodCallExpression)) {
return null
}
val iterableType = findActualType(methodCallExpression) ?: return null
val innerType = iterableType.resolveGenerics().substitutor.substitute(iterableType.parameters[0])
val containingClass = PsiTypesUtil.getPsiClass(innerType) ?: return null
return if (isResultOf) lookupMethod(containingClass, literal) else lookupFieldOrProperty(containingClass, literal, 0)
}
}
class IterableResultOfReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return findAndCreateReferences(element, ::findReferences)
}
fun findReferences(element: PsiLiteralExpression): List<Pair<TextRange, List<PsiElement>>>? {
val literal = element.value as? String ?: return null
val methodCallExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression::class.java) ?: return null
if (!EXTRACTING_RESULT_OF_FROM_ITERABLE.test(methodCallExpression)) {
return null
}
val iterableType = findActualType(methodCallExpression) ?: return null
val innerType = iterableType.resolveGenerics().substitutor.substitute(iterableType.parameters[0])
val containingClass = PsiTypesUtil.getPsiClass(innerType) ?: return null
return lookupMethod(containingClass, literal)
}
}
}
+3 -1
View File
@@ -7,10 +7,11 @@
Cajon is an IntelliJ IDEA Plugin for shortening and optimizing AssertJ assertions. Cajon is an IntelliJ IDEA Plugin for shortening and optimizing AssertJ assertions.
It adds inspections and quick fixes to fully make use of the AssertJ methods It adds inspections and quick fixes to fully make use of the AssertJ methods
to make the intention clear and concise. It can also convert JUnit 4 assertions to AssertJ. to make the intention clear and concise. It can also convert JUnit 4 assertions to AssertJ.
It supports referencing inside extracting()-methods with strings, adding refactoring safety.
]]></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="172.0"/> <idea-version since-build="173.2290.1"/>
<!-- 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 -->
@@ -19,6 +20,7 @@
<depends>com.intellij.modules.java</depends> <depends>com.intellij.modules.java</depends>
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<psi.referenceContributor implementation="de.platon42.intellij.plugins.cajon.references.ExtractorReferenceContributor"/>
<localInspection groupPath="Java" shortName="AssertThatObjectIsNullOrNotNull" enabledByDefault="true" level="WARNING" <localInspection groupPath="Java" shortName="AssertThatObjectIsNullOrNotNull" enabledByDefault="true" level="WARNING"
implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatObjectIsNullOrNotNullInspection"/> implementationClass="de.platon42.intellij.plugins.cajon.inspections.AssertThatObjectIsNullOrNotNullInspection"/>
<localInspection groupPath="Java" shortName="AssertThatBooleanIsTrueOrFalse" enabledByDefault="true" level="WARNING" <localInspection groupPath="Java" shortName="AssertThatBooleanIsTrueOrFalse" enabledByDefault="true" level="WARNING"
@@ -2,8 +2,11 @@ package de.platon42.intellij.playground;
import org.assertj.core.api.ListAssert; import org.assertj.core.api.ListAssert;
import org.assertj.core.data.Offset; import org.assertj.core.data.Offset;
import org.assertj.core.extractor.Extractors;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -122,10 +125,27 @@ public class Playground {
assertThat(!false).isTrue(); assertThat(!false).isTrue();
} }
private void stringIsEmpty() { private void stringStuff() {
String foo = "bar"; String foo = "bar";
assertThat(foo).isEqualTo(""); assertThat(foo).isEqualTo("");
assertThat(foo).hasSize(0); assertThat(foo).hasSize(0);
assertThat(foo.contains("foobar")).isTrue();
assertThat(foo).contains("foobar");
assertThat(foo.startsWith("foobar")).isTrue();
assertThat(foo).startsWith("foobar");
assertThat(foo.endsWith("foobar")).isTrue();
assertThat(foo).endsWith("foobar");
assertThat(foo.equalsIgnoreCase("foo")).isTrue();
assertThat(foo).isEqualToIgnoringCase("foo");
assertThat(foo.contains("foobar")).isFalse();
assertThat(foo).doesNotContain("foobar");
assertThat(foo.startsWith("foobar")).isFalse();
assertThat(foo).doesNotStartWith("foobar");
assertThat(foo.endsWith("foobar")).isFalse();
assertThat(foo).doesNotEndWith("foobar");
assertThat(foo.equalsIgnoreCase("foo")).isFalse();
assertThat(foo).isNotEqualToIgnoringCase("foo");
} }
private void java8Optional() { private void java8Optional() {
@@ -291,6 +311,60 @@ public class Playground {
assertThat(new float[1]).containsExactly(new float[2], offset(1.0f)); assertThat(new float[1]).containsExactly(new float[2], offset(1.0f));
assertThat(new float[1]).as("array equals").containsExactly(new float[2], offset(1.0f)); assertThat(new float[1]).as("array equals").containsExactly(new float[2], offset(1.0f));
assertThat(new Object()).extracting("toString");
assertThat(new Object()).extracting(Object::toString, Object::hashCode); assertThat(new Object()).extracting(Object::toString, Object::hashCode);
} }
private void findReferences() {
Contact contact = new Contact();
List<Contact> contactList = Collections.emptyList();
assertThat(contact).extracting("name").isEqualTo("foo");
assertThat(contact).extracting("age", "country", "address.street", "street", "address.noMailings", "address.REALLYnoMAILINGS").containsExactly(1, "Elmst. 42");
assertThat(contact).extracting(Extractors.byName("name")).isEqualTo("foo");
assertThat(contact).extracting(Extractors.resultOf("getStreet")).isEqualTo("foo");
assertThat(contact).extracting(Extractors.resultOf("getStreet"), Extractors.byName("narf")).isEqualTo("foo");
assertThat(contactList).extracting("name").isEqualTo("foo");
assertThat(contactList).extracting("name", "moar").isEqualTo("foo");
assertThat(contactList).extracting("name", String.class).isEqualTo("foo");
assertThat(contactList).extracting(Extractors.byName("name")).isEqualTo("foo");
assertThat(contactList).extracting(Extractors.resultOf("getStreet"), Extractors.byName("narf")).isEqualTo("foo");
assertThat(contactList).extractingResultOf("getStreet").isEqualTo("foo");
assertThat(contactList).extractingResultOf("getStreet", String.class).isEqualTo("foo");
assertThat(contactList).flatExtracting("age", "address.street", "street").containsExactly(1, "Elmst. 42");
assertThat(contactList).flatExtracting("age").containsExactly(1, "Elmst. 42");
}
public class Contact {
private String name;
private Integer age;
private Address address;
public String getStreet() {
return address.getStreet();
}
}
public class Address {
private String street;
private String country;
public String getStreet() {
return street;
}
public String getCountry() {
return country;
}
public boolean isNoMailings() {
return true;
}
public Boolean getREALLYnoMAILINGS() {
return true;
}
}
} }
@@ -20,7 +20,7 @@ import java.lang.reflect.InvocationTargetException
@AddLocalJarToModule(Assertions::class) @AddLocalJarToModule(Assertions::class)
abstract class AbstractCajonTest { abstract class AbstractCajonTest {
// See https://github.com/junit-team/junit5/issues/157 // See https://github.com/junit-team/junit5/issues/157, should be resolved with junit5 5.5 M2
protected fun runTest(body: () -> Unit) { protected fun runTest(body: () -> Unit) {
val throwables = arrayOfNulls<Throwable>(1) val throwables = arrayOfNulls<Throwable>(1)
@@ -9,22 +9,46 @@ import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@AddLocalJarToModule(com.google.common.base.Optional::class, org.assertj.guava.api.Assertions::class, Assertions::class) @AddLocalJarToModule(com.google.common.base.Optional::class, org.assertj.guava.api.Assertions::class, Assertions::class)
@TestDataSubPath("inspections/AssertThatGuavaOptional")
internal class AssertThatGuavaOptionalInspectionTest : AbstractCajonTest() { internal class AssertThatGuavaOptionalInspectionTest : AbstractCajonTest() {
@Test @Test
@TestDataSubPath("inspections/AssertThatGuavaOptional")
internal fun assertThat_get_or_isPresent_for_Guava_Optional_can_be_simplified(@MyFixture myFixture: JavaCodeInsightTestFixture) { internal fun assertThat_get_or_isPresent_for_Guava_Optional_can_be_simplified(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest { runTest {
myFixture.enableInspections(AssertThatGuavaOptionalInspection::class.java) myFixture.enableInspections(AssertThatGuavaOptionalInspection::class.java)
myFixture.configureByFile("AssertThatGuavaOptionalBefore.java") myFixture.configureByFile("AssertThatGuavaOptionalBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isPresent()"), 2) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isEqualTo() with isPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isNotEqualTo() with isPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isPresent()"), 3) executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isPresent()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isEqualTo() with isAbsent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isAbsent()"), 3) executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isAbsent()"), 3)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isAbsent()"), 2) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isNotEqualTo() with isAbsent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isTrue() with isPresent()"), 1) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isTrue() with isPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isFalse() with isAbsent()"), 1) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isFalse() with isAbsent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with contains()"), 3) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isEqualTo() with contains()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap expected expression and replace isEqualTo() with contains()"), 6)
myFixture.checkResultByFile("AssertThatGuavaOptionalAfter.java") myFixture.checkResultByFile("AssertThatGuavaOptionalAfter.java")
} }
} }
@Test
internal fun adds_missing_Guava_import_any_order(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.enableInspections(AssertThatGuavaOptionalInspection::class.java)
myFixture.configureByFile("WithoutPriorGuavaImportBefore.java")
executeQuickFixes(myFixture, Regex(".*eplace .* with .*"), 7)
myFixture.checkResultByFile("WithoutPriorGuavaImportAfter.java")
}
}
@Test
internal fun adds_missing_Guava_import_isAbsent_first(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.enableInspections(AssertThatGuavaOptionalInspection::class.java)
myFixture.configureByFile("WithoutPriorGuavaImportBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isAbsent()"), 1)
executeQuickFixes(myFixture, Regex(".*eplace .* with .*"), 6)
myFixture.checkResultByFile("WithoutPriorGuavaImportAfter.java")
}
}
} }
@@ -14,14 +14,17 @@ internal class AssertThatJava8OptionalInspectionTest : AbstractCajonTest() {
runTest { runTest {
myFixture.enableInspections(AssertThatJava8OptionalInspection::class.java) myFixture.enableInspections(AssertThatJava8OptionalInspection::class.java)
myFixture.configureByFile("AssertThatJava8OptionalBefore.java") myFixture.configureByFile("AssertThatJava8OptionalBefore.java")
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isPresent()"), 2) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isEqualTo() with isPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isPresent()"), 3) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isNotEqualTo() with isPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isNotPresent()"), 3) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isEqualTo() with isNotPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isNotPresent()"), 2) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isNotEqualTo() with isNotPresent()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isTrue() with isPresent()"), 1) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isTrue() with isPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isFalse() with isNotPresent()"), 1) executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with isNotPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isEqualTo() with contains()"), 3) executeQuickFixes(myFixture, Regex.fromLiteral("Replace isNotEqualTo() with isPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Replace isSameAs() with containsSame()"), 1) executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isFalse() with isNotPresent()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap expected expression and replace isEqualTo() with contains()"), 2)
executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isEqualTo() with contains()"), 1)
executeQuickFixes(myFixture, Regex.fromLiteral("Unwrap actual expression and replace isSameAs() with containsSame()"), 1)
myFixture.checkResultByFile("AssertThatJava8OptionalAfter.java") myFixture.checkResultByFile("AssertThatJava8OptionalAfter.java")
} }
} }
@@ -0,0 +1,93 @@
package de.platon42.intellij.plugins.cajon.references
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.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
@TestDataSubPath("references")
internal class ExtractorReferenceContributorTest : AbstractCajonTest() {
@Test
internal fun extractor_is_able_to_find_reference_for_field_extracting(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference1.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).isEqualTo("private String name;")
}
}
@Test
internal fun extractor_is_able_to_find_reference_for_first_part_of_a_path(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference2.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).isEqualTo("protected Address address;")
}
}
@Test
internal fun extractor_is_able_to_find_reference_for_second_part_of_a_path_and_both_getter_and_field(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference3.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).startsWith("private String street;")
}
}
@Test
internal fun extractor_is_able_to_find_reference_on_a_bare_method_call(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference4.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).startsWith("public Boolean getREALLYnoMAILINGS()")
}
}
@Test
internal fun extractor_is_able_to_find_reference_with_only_Getter_on_second_part(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference5.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).startsWith("public boolean isNoMailings()")
}
}
@Test
internal fun extractor_is_able_to_find_reference_using_byName_extractor(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference6.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).isEqualTo("private String name;")
}
}
@Test
internal fun extractor_is_able_to_find_reference_using_resultOf_extractor(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference7.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).startsWith("public String getStreetName()")
}
}
@Test
internal fun extractor_is_able_to_find_reference_for_field_extraction_on_list(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference8.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).isEqualTo("private String name;")
}
}
@Test
internal fun extractor_is_able_to_find_reference_for_field_flat_extraction_of_path_on_list(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference9.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).startsWith("private String street;")
}
}
@Test
internal fun extractor_is_able_to_find_reference_for_extraction_on_result_of_method(@MyFixture myFixture: JavaCodeInsightTestFixture) {
runTest {
myFixture.configureByFiles("FindReference10.java", "Address.java", "Contact.java")
assertThat(myFixture.elementAtCaret.text).startsWith("public String getStreetName()")
}
}
}
@@ -32,5 +32,21 @@ public class AssertThatGuavaOptional {
assertThat(opt).isAbsent(); assertThat(opt).isAbsent();
assertThat(opt).isPresent(); assertThat(opt).isPresent();
org.assertj.guava.api.Assertions.assertThat(opt).contains("foo");
org.assertj.guava.api.Assertions.assertThat(opt).contains("foo");
org.assertj.guava.api.Assertions.assertThat(opt).isNotEqualTo(Optional.of("foo"));
org.assertj.guava.api.Assertions.assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
org.assertj.guava.api.Assertions.assertThat(opt).isAbsent();
org.assertj.guava.api.Assertions.assertThat(opt).isPresent();
assertThat(opt).contains("foo");
assertThat(opt).contains("foo");
org.assertj.core.api.Assertions.assertThat(opt).isNotEqualTo(Optional.of("foo"));
org.assertj.core.api.Assertions.assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
assertThat(opt).isAbsent();
assertThat(opt).isPresent();
} }
} }
@@ -32,5 +32,21 @@ public class AssertThatGuavaOptional {
assertThat(opt).isEqualTo(Optional.absent()); assertThat(opt).isEqualTo(Optional.absent());
assertThat(opt).isNotEqualTo(Optional.absent()); assertThat(opt).isNotEqualTo(Optional.absent());
org.assertj.guava.api.Assertions.assertThat(opt).isEqualTo(Optional.of("foo"));
org.assertj.guava.api.Assertions.assertThat(opt).isEqualTo(Optional.fromNullable("foo"));
org.assertj.guava.api.Assertions.assertThat(opt).isNotEqualTo(Optional.of("foo"));
org.assertj.guava.api.Assertions.assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
org.assertj.guava.api.Assertions.assertThat(opt).isEqualTo(Optional.absent());
org.assertj.guava.api.Assertions.assertThat(opt).isNotEqualTo(Optional.absent());
org.assertj.core.api.Assertions.assertThat(opt).isEqualTo(Optional.of("foo"));
org.assertj.core.api.Assertions.assertThat(opt).isEqualTo(Optional.fromNullable("foo"));
org.assertj.core.api.Assertions.assertThat(opt).isNotEqualTo(Optional.of("foo"));
org.assertj.core.api.Assertions.assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
org.assertj.core.api.Assertions.assertThat(opt).isEqualTo(Optional.absent());
org.assertj.core.api.Assertions.assertThat(opt).isNotEqualTo(Optional.absent());
} }
} }
@@ -0,0 +1,27 @@
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).contains("foo");
assertThat(opt).contains("foo");
assertThat(opt).isNotEqualTo(Optional.of("foo"));
assertThat(opt).isNotEqualTo(Optional.fromNullable("foo"));
assertThat(opt).isPresent();
assertThat(opt).isAbsent();
assertThat(opt).contains("foo");
assertThat(opt.get()).isSameAs("foo");
assertThat(opt.get()).isNotEqualTo("foo");
assertThat(opt.get()).isNotSameAs("foo");
assertThat(opt).isAbsent();
assertThat(opt).isPresent();
}
}
@@ -0,0 +1,26 @@
import com.google.common.base.Optional;
import static org.assertj.core.api.Assertions.assertThat;
public class AssertThatGuavaOptional {
private void assertThatGuavaOptional() {
Optional<String> opt = Optional.absent();
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.isPresent()).isTrue();
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.absent());
assertThat(opt).isNotEqualTo(Optional.absent());
}
}
@@ -0,0 +1,20 @@
public class Address {
private String street;
private String country;
private String getStreet() {
return street;
}
public String getCountry() {
return country;
}
public boolean isNoMailings() {
return true;
}
public Boolean getREALLYnoMAILINGS() {
return true;
}
}
@@ -0,0 +1,9 @@
public class Contact {
private String name;
public Integer age;
protected Address address;
public String getStreetName()
{
return address.getStreet();
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference1 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting("name<caret>").isEqualTo("foo");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference10 {
private void findReferences() {
List<Contact> contactList = Collections.emptyList();
assertThat(contactList).extractingResultOf("getStreetName<caret>").isEqualTo("foo");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference2 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting("address<caret>.street", "streetName").containsExactly(1, "Elmst. 42");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference3 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting("address.street<caret>", "address.REALLYnoMAILINGS").containsExactly(1, "Elmst. 42");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference4 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting("address.getREALLYnoMAILINGS<caret>", "address.country").containsExactly(1, "Elmst. 42");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference5 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting("address.noMailings<caret>").containsExactly(1, "Elmst. 42");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference6 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting(Extractors.byName("name<caret>")).isEqualTo("foo");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference7 {
private void findReferences() {
Contact contact = new Contact();
assertThat(contact).extracting(Extractors.resultOf("getStreetName<caret>")).isEqualTo("foo");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference8 {
private void findReferences() {
List<Contact> contactList = Collections.emptyList();
assertThat(contactList).extracting("name<caret>").isEqualTo("foo");
}
}
@@ -0,0 +1,15 @@
import org.assertj.core.extractor.Extractors;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FindReference9 {
private void findReferences() {
List<Contact> contactList = Collections.emptyList();
assertThat(contactList).flatExtracting("age", "address.street<caret>", "streetName").containsExactly(1, "Elmst. 42");
}
}