mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
pertinent to applicability: reject nested lambdas if they target non proper type
This commit is contained in:
@@ -45,7 +45,7 @@ public class LambdaHighlightingUtil {
|
||||
if (signatures.size() == 1) {
|
||||
return null;
|
||||
}
|
||||
return "Multiple non-overriding abstract methods found";
|
||||
return "Multiple non-overriding abstract methods found in interface " + HighlightUtil.formatClass(psiClass);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -165,16 +165,20 @@ public class InferenceSession {
|
||||
7) A conditional expression (15.25) whose second or third operand is not pertinent to applicability.
|
||||
*/
|
||||
public static boolean isPertinentToApplicability(PsiExpression expr, PsiMethod method) {
|
||||
return isPertinentToApplicability(expr, method, null);
|
||||
}
|
||||
|
||||
private static boolean isPertinentToApplicability(PsiExpression expr, PsiMethod method, PsiType expectedReturnType) {
|
||||
if (expr instanceof PsiLambdaExpression && ((PsiLambdaExpression)expr).hasFormalParameterTypes() ||
|
||||
expr instanceof PsiMethodReferenceExpression && ((PsiMethodReferenceExpression)expr).isExact()) {
|
||||
if (method != null && method.getTypeParameters().length > 0) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expr.getParent());
|
||||
PsiType paramType = null;
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
final PsiElement gParent = parent.getParent();
|
||||
if (gParent instanceof PsiCallExpression && ((PsiCallExpression)gParent).getTypeArgumentList().getTypeParameterElements().length == 0) {
|
||||
final int idx = LambdaUtil.getLambdaIdx(((PsiExpressionList)parent), expr);
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
PsiType paramType;
|
||||
if (idx > parameters.length - 1) {
|
||||
final PsiType lastParamType = parameters[parameters.length - 1].getType();
|
||||
paramType = parameters[parameters.length - 1].isVarArgs() ? ((PsiEllipsisType)lastParamType).getComponentType() : lastParamType;
|
||||
@@ -182,20 +186,24 @@ public class InferenceSession {
|
||||
else {
|
||||
paramType = parameters[idx].getType();
|
||||
}
|
||||
final PsiClass psiClass = PsiUtil.resolveClassInType(paramType); //accept ellipsis here
|
||||
if (psiClass instanceof PsiTypeParameter && ((PsiTypeParameter)psiClass).getOwner() == method) return false;
|
||||
if (isTypeParameterType(method, paramType)) return false;
|
||||
}
|
||||
}
|
||||
else if (expectedReturnType != null && parent instanceof PsiLambdaExpression) {
|
||||
if (isTypeParameterType(method, expectedReturnType)) return false;
|
||||
paramType = expectedReturnType;
|
||||
}
|
||||
|
||||
if (expr instanceof PsiLambdaExpression) {
|
||||
for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)expr)) {
|
||||
if (!isPertinentToApplicability(expression, method, LambdaUtil.getFunctionalInterfaceReturnType(paramType))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expr instanceof PsiLambdaExpression) {
|
||||
if (!((PsiLambdaExpression)expr).hasFormalParameterTypes()) {
|
||||
return false;
|
||||
}
|
||||
for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)expr)) {
|
||||
if (!isPertinentToApplicability(expression, method)) return false;
|
||||
}
|
||||
return true;
|
||||
return ((PsiLambdaExpression)expr).hasFormalParameterTypes();
|
||||
}
|
||||
if (expr instanceof PsiMethodReferenceExpression) {
|
||||
return ((PsiMethodReferenceExpression)expr).isExact();
|
||||
@@ -212,6 +220,12 @@ public class InferenceSession {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isTypeParameterType(PsiMethod method, PsiType paramType) {
|
||||
final PsiClass psiClass = PsiUtil.resolveClassInType(paramType); //accept ellipsis here
|
||||
if (psiClass instanceof PsiTypeParameter && ((PsiTypeParameter)psiClass).getOwner() == method) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static PsiType getParameterType(PsiParameter[] parameters, int i, @Nullable PsiSubstitutor substitutor, boolean varargs) {
|
||||
if (substitutor == null) return null;
|
||||
PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType());
|
||||
|
||||
@@ -22,9 +22,6 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
|
||||
|
||||
@Override
|
||||
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
|
||||
if (session.getInferenceVariable(myT) != null) {
|
||||
return true;
|
||||
}
|
||||
if (!LambdaUtil.isFunctionalType(myT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<error descr="Multiple non-overriding abstract methods found">@FunctionalInterface</error>
|
||||
<error descr="Multiple non-overriding abstract methods found in interface Test">@FunctionalInterface</error>
|
||||
interface Test {
|
||||
void foo();
|
||||
void bar();
|
||||
|
||||
@@ -36,7 +36,7 @@ class Test2 {
|
||||
}
|
||||
|
||||
{
|
||||
F f = <error descr="Multiple non-overriding abstract methods found">() -> g()</error>;
|
||||
F f = <error descr="Multiple non-overriding abstract methods found in interface Test2.F">() -> g()</error>;
|
||||
}
|
||||
|
||||
void g() {}
|
||||
|
||||
@@ -8,7 +8,7 @@ public class NotAFIT {
|
||||
}
|
||||
|
||||
void bar() {
|
||||
foo(<error descr="Multiple non-overriding abstract methods found">() ->{}</error>);
|
||||
foo(<error descr="Multiple non-overriding abstract methods found in interface NotAFIT.First.A">() ->{}</error>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public class NotAFIT {
|
||||
}
|
||||
|
||||
void bar() {
|
||||
foo(<error descr="Multiple non-overriding abstract methods found">()->{}</error>);
|
||||
foo(<error descr="Multiple non-overriding abstract methods found in interface NotAFIT.WithInheritance.B">()->{}</error>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,3 +9,13 @@ class Test {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class Test1 {
|
||||
{
|
||||
Supplier<Runnable> x = foo(() -> <error descr="Multiple non-overriding abstract methods found in interface java.util.List">() -> null</error>);
|
||||
}
|
||||
|
||||
static <T> Supplier<T> foo(Supplier<java.util.List<T>> delegate) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class FunctionalInterfaceTest extends LightDaemonAnalyzerTestCase {
|
||||
}
|
||||
|
||||
public void testClone() throws Exception {
|
||||
doTestFunctionalInterface("Multiple non-overriding abstract methods found");
|
||||
doTestFunctionalInterface("Multiple non-overriding abstract methods found in interface Foo");
|
||||
}
|
||||
|
||||
public void testTwoMethodsSameSignature() throws Exception {
|
||||
@@ -64,11 +64,11 @@ public class FunctionalInterfaceTest extends LightDaemonAnalyzerTestCase {
|
||||
}
|
||||
|
||||
public void testTwoMethodsNoSubSignature() throws Exception {
|
||||
doTestFunctionalInterface("Multiple non-overriding abstract methods found");
|
||||
doTestFunctionalInterface("Multiple non-overriding abstract methods found in interface Foo");
|
||||
}
|
||||
|
||||
public void testTwoMethodsNoSubSignature1() throws Exception {
|
||||
doTestFunctionalInterface("Multiple non-overriding abstract methods found");
|
||||
doTestFunctionalInterface("Multiple non-overriding abstract methods found in interface Foo");
|
||||
}
|
||||
|
||||
public void testTwoMethodsSameSubstSignature() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user