junit 5: support migration of assertions in method references (IDEA-187308)

This commit is contained in:
Anna.Kozlova
2018-05-09 18:28:38 +02:00
parent f99269157d
commit 13739a831d
4 changed files with 110 additions and 20 deletions
@@ -121,6 +121,38 @@ public class AssertHint {
return new AssertHint(argumentIndex, messageOnFirstPosition, message, method);
}
public static AssertHint create(PsiMethodReferenceExpression methodExpression,
Function<String, Integer> methodNameToParamCount,
boolean checkTestNG) {
@NonNls final String methodName = methodExpression.getReferenceName();
Integer minimumParamCount = methodNameToParamCount.apply(methodName);
if (minimumParamCount == null) {
return null;
}
JavaResolveResult resolveResult = methodExpression.advancedResolve(false);
PsiElement element = resolveResult.getElement();
if (!(element instanceof PsiMethod)) {
return null;
}
final PsiMethod method = (PsiMethod)element;
if (method.hasModifierProperty(PsiModifier.PRIVATE) || !resolveResult.isValidResult()) {
return null;
}
final boolean messageOnLastPosition = isMessageOnLastPosition(method, checkTestNG);
final boolean messageOnFirstPosition = isMessageOnFirstPosition(method, checkTestNG);
if (!messageOnFirstPosition && !messageOnLastPosition) {
return null;
}
final PsiParameterList parameterList = method.getParameterList();
final PsiParameter[] parameters = parameterList.getParameters();
if (parameters.length != minimumParamCount) {
return null;
}
return new AssertHint(0, messageOnFirstPosition, null, method);
}
public static boolean isMessageOnFirstPosition(PsiMethod method, boolean checkTestNG) {
PsiClass containingClass = method.getContainingClass();
final String qualifiedName = containingClass.getQualifiedName();
@@ -20,11 +20,13 @@ import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testIntegration.TestFramework;
import com.intellij.util.Consumer;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -72,19 +74,51 @@ public class JUnit5AssertionsConverterInspection extends BaseInspection {
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
doCheck(expression,
() -> AssertHint.create(expression, methodName -> AssertHint.JUnitCommonAssertNames.ASSERT_METHOD_2_PARAMETER_COUNT.get(methodName), false),
psiMethod -> {
final PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass == null) {
return;
}
String methodName = psiMethod.getName();
registerMethodCallError(expression, containingClass.getName(),
getNewAssertClassName(methodName),
absentInJUnit5(psiMethod, methodName));
});
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
doCheck(expression,
() -> AssertHint.create(expression, methodName -> AssertHint.JUnitCommonAssertNames.ASSERT_METHOD_2_PARAMETER_COUNT.get(methodName), false),
psiMethod -> {
final PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass == null) {
return;
}
String methodName = psiMethod.getName();
registerError(expression, containingClass.getQualifiedName(), getNewAssertClassName(methodName), absentInJUnit5(psiMethod, methodName));
});
}
private void doCheck(PsiElement expression,
Computable<? extends AssertHint> computable,
Consumer<? super PsiMethod> registerError) {
final Project project = expression.getProject();
final Module module = ModuleUtilCore.findModuleForPsiElement(expression);
if (module == null) {
return;
}
final PsiClass newAssertClass = JavaPsiFacade.getInstance(project)
.findClass(JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_ASSERTIONS, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module));
final PsiClass newAssertClass = JavaPsiFacade.getInstance(project).findClass(JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_ASSERTIONS,
GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module));
if (newAssertClass == null) {
return;
}
AssertHint hint = AssertHint.create(expression, methodName ->
AssertHint.JUnitCommonAssertNames.ASSERT_METHOD_2_PARAMETER_COUNT.get(methodName), false);
AssertHint hint = computable.compute();
if (hint == null) {
return;
}
@@ -94,27 +128,18 @@ public class JUnit5AssertionsConverterInspection extends BaseInspection {
return;
}
final PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass == null) {
return;
}
final String name = containingClass.getQualifiedName();
if (hint.isMessageOnFirstPosition()) {
PsiFile file = expression.getContainingFile();
if (file instanceof PsiClassOwner) {
for (PsiClass psiClass : ((PsiClassOwner)file).getClasses()) {
TestFramework testFramework = TestFrameworks.detectFramework(psiClass);
if (testFramework != null && myFrameworkName.equals(testFramework.getName())) {
String methodName = psiMethod.getName();
registerMethodCallError(expression, name,
getNewAssertClassName(methodName),
absentInJUnit5(psiMethod, methodName));
registerError.consume(psiMethod);
break;
}
}
}
}
}
@@ -153,8 +178,17 @@ public class JUnit5AssertionsConverterInspection extends BaseInspection {
@Override
protected void doFix(Project project, ProblemDescriptor descriptor) {
final PsiMethodCallExpression methodCallExpression =
PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class);
PsiElement element = descriptor.getPsiElement();
if (element instanceof PsiMethodReferenceExpression) {
AssertHint assertHint =
AssertHint.create((PsiMethodReferenceExpression)element, methodName -> AssertHint.JUnitCommonAssertNames.ASSERT_METHOD_2_PARAMETER_COUNT.get(methodName), false);
if (assertHint != null) {
replaceQualifier(project, assertHint.getMethod().getName(), (PsiReferenceExpression)element);
}
return;
}
final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
if (methodCallExpression == null) {
return;
}
@@ -167,9 +201,6 @@ public class JUnit5AssertionsConverterInspection extends BaseInspection {
}
String methodName = assertHint.getMethod().getName();
PsiClass newAssertClass = JavaPsiFacade.getInstance(project).findClass(getNewAssertClassName(methodName),
methodCallExpression.getResolveScope());
if (!"assertThat".equals(methodName)) {
PsiExpression message = assertHint.getMessage();
if (message != null) {
@@ -177,6 +208,14 @@ public class JUnit5AssertionsConverterInspection extends BaseInspection {
message.delete();
}
}
replaceQualifier(project, methodName, methodCallExpression.getMethodExpression());
}
private static void replaceQualifier(Project project,
String methodName,
final PsiReferenceExpression methodExpression) {
PsiClass newAssertClass = JavaPsiFacade.getInstance(project).findClass(getNewAssertClassName(methodName),
methodExpression.getResolveScope());
if (newAssertClass == null) {
return;
@@ -186,7 +225,6 @@ public class JUnit5AssertionsConverterInspection extends BaseInspection {
return;
}
PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
methodExpression.setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass));
JavaCodeStyleManager.getInstance(project).shortenClassReferences(methodExpression);
}
@@ -1,5 +1,7 @@
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
public class FullConversion {
@@ -8,4 +10,12 @@ public class FullConversion {
fail("fail");
assertTrue(true, "always");
}
@Test
public void testMethodRefs() {
List<Boolean> booleanList = new ArrayList<>();
booleanList.add(true);
booleanList.forEach(Assertions::assertTrue);
}
}
@@ -1,6 +1,8 @@
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.Assert;
import java.util.*;
public class Full<caret>Conversion {
@Test
@@ -8,4 +10,12 @@ public class Full<caret>Conversion {
fail("fail");
assertTrue("always", true);
}
@Test
public void testMethodRefs() {
List<Boolean> booleanList = new ArrayList<>();
booleanList.add(true);
booleanList.forEach(Assert::assertTrue);
}
}