mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
forbid anonym -> lambda/meth ref if method is synchronized (IDEA-133947)
This commit is contained in:
@@ -24,6 +24,7 @@ import com.intellij.codeInsight.intention.HighPriorityAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
@@ -85,27 +86,23 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitAnonymousClass(PsiAnonymousClass aClass) {
|
||||
public void visitAnonymousClass(final PsiAnonymousClass aClass) {
|
||||
super.visitAnonymousClass(aClass);
|
||||
if (PsiUtil.getLanguageLevel(aClass).isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
final PsiClassType baseClassType = aClass.getBaseClassType();
|
||||
if (LambdaHighlightingUtil.checkInterfaceFunctional(baseClassType) == null) {
|
||||
final PsiElement lambdaContext = aClass.getParent().getParent();
|
||||
if (LambdaUtil.isValidLambdaContext(lambdaContext) || !(lambdaContext instanceof PsiExpressionStatement)) {
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length == 1 && aClass.getFields().length == 0) {
|
||||
final PsiMethod psiMethod = methods[0];
|
||||
final PsiCodeBlock body = psiMethod.getBody();
|
||||
if (body != null && !hasForbiddenRefsInsideBody(psiMethod, aClass) && !hasRuntimeAnnotations(psiMethod)) {
|
||||
final PsiElement lBrace = aClass.getLBrace();
|
||||
LOG.assertTrue(lBrace != null);
|
||||
final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
|
||||
holder.registerProblem(aClass.getParent(), "Anonymous #ref #loc can be replaced with lambda",
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithLambdaFix());
|
||||
}
|
||||
final PsiElement parent = aClass.getParent();
|
||||
final PsiElement lambdaContext = parent != null ? parent.getParent() : null;
|
||||
if (lambdaContext != null &&
|
||||
(LambdaUtil.isValidLambdaContext(lambdaContext) || !(lambdaContext instanceof PsiExpressionStatement)) &&
|
||||
canBeConvertedToLambda(aClass, new Condition<PsiClassType>() {
|
||||
@Override
|
||||
public boolean value(PsiClassType type) {
|
||||
return LambdaHighlightingUtil.checkInterfaceFunctional(type) == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
})) {
|
||||
final PsiElement lBrace = aClass.getLBrace();
|
||||
LOG.assertTrue(lBrace != null);
|
||||
final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
|
||||
holder.registerProblem(parent, "Anonymous #ref #loc can be replaced with lambda",
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithLambdaFix());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -192,6 +189,20 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean canBeConvertedToLambda(PsiAnonymousClass aClass, Condition<PsiClassType> baseClassTypeCondition) {
|
||||
if (PsiUtil.getLanguageLevel(aClass).isAtLeast(LanguageLevel.JDK_1_8) && baseClassTypeCondition.value(aClass.getBaseClassType())) {
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length == 1 && aClass.getFields().length == 0) {
|
||||
final PsiMethod method = methods[0];
|
||||
return method.getBody() != null &&
|
||||
!hasForbiddenRefsInsideBody(method, aClass) &&
|
||||
!hasRuntimeAnnotations(method) &&
|
||||
!method.hasModifierProperty(PsiModifier.SYNCHRONIZED);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class ReplaceWithLambdaFix implements LocalQuickFix, HighPriorityAction {
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
@@ -66,30 +67,30 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI
|
||||
@Override
|
||||
public void visitAnonymousClass(PsiAnonymousClass aClass) {
|
||||
super.visitAnonymousClass(aClass);
|
||||
if (PsiUtil.getLanguageLevel(aClass).isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
final PsiClassType baseClassType = aClass.getBaseClassType();
|
||||
if (LambdaUtil.isFunctionalType(baseClassType)) {
|
||||
final PsiMethod[] methods = aClass.getMethods();
|
||||
if (methods.length == 1 && methods[0].getBody() != null && aClass.getFields().length == 0 &&
|
||||
!AnonymousCanBeLambdaInspection.hasForbiddenRefsInsideBody(methods[0], aClass)) {
|
||||
final PsiCodeBlock body = methods[0].getBody();
|
||||
final PsiCallExpression callExpression =
|
||||
LambdaCanBeMethodReferenceInspection
|
||||
.canBeMethodReferenceProblem(body, methods[0].getParameterList().getParameters(), baseClassType);
|
||||
if (callExpression != null) {
|
||||
final PsiMethod resolveMethod = callExpression.resolveMethod();
|
||||
if (resolveMethod != methods[0] && !AnonymousCanBeLambdaInspection.functionalInterfaceMethodReferenced(resolveMethod, aClass)) {
|
||||
final PsiElement parent = aClass.getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)parent).getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
final PsiElement lBrace = aClass.getLBrace();
|
||||
LOG.assertTrue(lBrace != null);
|
||||
final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
|
||||
holder.registerProblem(parent,
|
||||
"Anonymous #ref #loc can be replaced with method reference", ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithMethodRefFix());
|
||||
}
|
||||
}
|
||||
if (AnonymousCanBeLambdaInspection.canBeConvertedToLambda(aClass, new Condition<PsiClassType>() {
|
||||
@Override
|
||||
public boolean value(PsiClassType type) {
|
||||
return LambdaUtil.isFunctionalType(type);
|
||||
}
|
||||
})) {
|
||||
final PsiMethod method = aClass.getMethods()[0];
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
final PsiCallExpression callExpression =
|
||||
LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(body, method.getParameterList().getParameters(), aClass.getBaseClassType());
|
||||
if (callExpression != null) {
|
||||
final PsiMethod resolveMethod = callExpression.resolveMethod();
|
||||
if (resolveMethod != method &&
|
||||
!AnonymousCanBeLambdaInspection.functionalInterfaceMethodReferenced(resolveMethod, aClass)) {
|
||||
final PsiElement parent = aClass.getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)parent).getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
final PsiElement lBrace = aClass.getLBrace();
|
||||
LOG.assertTrue(lBrace != null);
|
||||
final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
|
||||
holder.registerProblem(parent,
|
||||
"Anonymous #ref #loc can be replaced with method reference",
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithMethodRefFix());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with lambda" "false"
|
||||
class Test {
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
{
|
||||
I i = new I<caret>() {
|
||||
public synchronized void m() {
|
||||
//do smth
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user