mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-07 05:09:37 +07:00
[java-inspections] FunctionalExpressionCanBeFolded: disable if qualifier subtype overrides default methods of function
Fixes IDEA-310524 "Method reference can be replaced with qualifier changes" suggestion changes behavior in unwanted ways. (Spring Security) GitOrigin-RevId: f927ab534894188fa418a499c98af3a7c169b0cd
This commit is contained in:
committed by
intellij-monorepo-bot
parent
78a77d064c
commit
5778a45943
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
package com.intellij.codeInspection;
|
package com.intellij.codeInspection;
|
||||||
|
|
||||||
|
import com.intellij.codeInspection.dataFlow.CommonDataflow;
|
||||||
|
import com.intellij.codeInspection.dataFlow.types.DfReferenceType;
|
||||||
import com.intellij.codeInspection.util.InspectionMessage;
|
import com.intellij.codeInspection.util.InspectionMessage;
|
||||||
import com.intellij.modcommand.ModPsiUpdater;
|
import com.intellij.modcommand.ModPsiUpdater;
|
||||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
||||||
@@ -8,7 +10,9 @@ import com.intellij.openapi.project.Project;
|
|||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.util.MethodSignatureUtil;
|
import com.intellij.psi.util.MethodSignatureUtil;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.psi.util.PsiUtil;
|
||||||
import com.intellij.psi.util.TypeConversionUtil;
|
import com.intellij.psi.util.TypeConversionUtil;
|
||||||
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.siyeh.InspectionGadgetsBundle;
|
import com.siyeh.InspectionGadgetsBundle;
|
||||||
import org.jetbrains.annotations.Nls;
|
import org.jetbrains.annotations.Nls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -48,20 +52,47 @@ public final class FunctionalExpressionCanBeFoldedInspection extends AbstractBas
|
|||||||
if (qualifierExpression != null && referenceNameElement != null && !(qualifierExpression instanceof PsiSuperExpression)) {
|
if (qualifierExpression != null && referenceNameElement != null && !(qualifierExpression instanceof PsiSuperExpression)) {
|
||||||
final PsiType qualifierType = qualifierExpression.getType();
|
final PsiType qualifierType = qualifierExpression.getType();
|
||||||
if (qualifierType != null) {
|
if (qualifierType != null) {
|
||||||
//don't get ground type as check is required over expected type instead
|
//don't get the ground type as check is required over the expected type instead
|
||||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, true);
|
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, true);
|
||||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||||
if (interfaceMethod != null) {
|
if (interfaceMethod != null) {
|
||||||
final PsiElement resolve = resolver.get();
|
final PsiElement resolve = resolver.get();
|
||||||
if (resolve instanceof PsiMethod &&
|
if (resolve instanceof PsiMethod &&
|
||||||
(interfaceMethod == resolve || MethodSignatureUtil.isSuperMethod(interfaceMethod, (PsiMethod)resolve)) &&
|
(interfaceMethod == resolve || MethodSignatureUtil.isSuperMethod(interfaceMethod, (PsiMethod)resolve)) &&
|
||||||
TypeConversionUtil.isAssignable(functionalInterfaceType, qualifierType)) {
|
TypeConversionUtil.isAssignable(functionalInterfaceType, qualifierType) &&
|
||||||
|
!mayOverrideDefaultMethods(qualifierExpression, functionalInterfaceType)) {
|
||||||
holder.registerProblem(referenceNameElement, errorMessage, new ReplaceMethodRefWithQualifierFix());
|
holder.registerProblem(referenceNameElement, errorMessage, new ReplaceMethodRefWithQualifierFix());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean mayOverrideDefaultMethods(PsiExpression expression, PsiType functionalInterfaceType) {
|
||||||
|
PsiClass functionalInterface = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType);
|
||||||
|
if (functionalInterface == null || !functionalInterface.isInterface()) return true;
|
||||||
|
if (!ContainerUtil.exists(functionalInterface.getAllMethods(), m -> m.hasModifierProperty(PsiModifier.DEFAULT))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PsiType qualifierType = null;
|
||||||
|
if (CommonDataflow.getDfType(expression) instanceof DfReferenceType refType) {
|
||||||
|
qualifierType = refType.getConstraint().getPsiType(functionalInterface.getProject());
|
||||||
|
}
|
||||||
|
if (qualifierType == null) {
|
||||||
|
qualifierType = expression.getType();
|
||||||
|
}
|
||||||
|
PsiClass qualifierClass = PsiUtil.resolveClassInClassTypeOnly(qualifierType);
|
||||||
|
if (qualifierClass == null) return true;
|
||||||
|
if (qualifierClass.isEquivalentTo(functionalInterface)) return false;
|
||||||
|
for (PsiMethod method : qualifierClass.getAllMethods()) {
|
||||||
|
for (PsiMethod superMethod : method.findSuperMethods(functionalInterface)) {
|
||||||
|
if (superMethod.hasModifierProperty(PsiModifier.DEFAULT)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// "Fix all 'Functional expression can be folded' problems in file" "true"
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
interface LoggingPredicate extends Predicate<String> {
|
||||||
|
@Override
|
||||||
|
default Predicate<String> negate() {
|
||||||
|
System.out.println("negating!");
|
||||||
|
return Predicate.super.negate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SubPredicate extends Predicate<String> {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
LoggingPredicate predicate = s -> !s.isEmpty();
|
||||||
|
test(predicate::test);
|
||||||
|
Predicate<String> copy = predicate;
|
||||||
|
test(copy::test);
|
||||||
|
SubPredicate subPredicate = s -> !s.isEmpty();
|
||||||
|
test(subPredicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test(Predicate<String> test) {
|
||||||
|
System.out.println(test.negate().test("hello"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// "Fix all 'Functional expression can be folded' problems in file" "true"
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
interface LoggingPredicate extends Predicate<String> {
|
||||||
|
@Override
|
||||||
|
default Predicate<String> negate() {
|
||||||
|
System.out.println("negating!");
|
||||||
|
return Predicate.super.negate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SubPredicate extends Predicate<String> {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
LoggingPredicate predicate = s -> !s.isEmpty();
|
||||||
|
test(predicate::test);
|
||||||
|
Predicate<String> copy = predicate;
|
||||||
|
test(copy::test);
|
||||||
|
SubPredicate subPredicate = s -> !s.isEmpty();
|
||||||
|
test(subPredicate::<caret>test);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test(Predicate<String> test) {
|
||||||
|
System.out.println(test.negate().test("hello"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user