mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
method refs: check cyclic inference for method refs
This commit is contained in:
+6
@@ -977,6 +977,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (myRefCountHolder != null) {
|
||||
myRefCountHolder.registerReference(expression, result);
|
||||
}
|
||||
if (!myHolder.hasErrorResults()) {
|
||||
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
|
||||
if (LambdaUtil.dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression, null)) {
|
||||
myHolder.add(HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, "Cyclic inference")); //todo[ann] append not inferred type params info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -355,7 +355,7 @@ public class LambdaUtil {
|
||||
|
||||
public static boolean dependsOnTypeParams(PsiType type,
|
||||
PsiType functionalInterfaceType,
|
||||
PsiLambdaExpression lambdaExpression,
|
||||
PsiElement lambdaExpression,
|
||||
PsiTypeParameter param2Check) {
|
||||
return depends(type, param2Check, new TypeParamsChecker(lambdaExpression,
|
||||
PsiUtil.resolveClassInType(functionalInterfaceType)));
|
||||
@@ -750,11 +750,11 @@ public class LambdaUtil {
|
||||
myClass = aClass;
|
||||
}
|
||||
|
||||
public TypeParamsChecker(PsiLambdaExpression expression) {
|
||||
public TypeParamsChecker(PsiElement expression) {
|
||||
this(expression, PsiUtil.resolveGenericsClassInType(getFunctionalInterfaceType(expression, false)).getElement());
|
||||
}
|
||||
|
||||
public TypeParamsChecker(PsiLambdaExpression expression, PsiClass aClass) {
|
||||
public TypeParamsChecker(PsiElement expression, PsiClass aClass) {
|
||||
myClass = aClass;
|
||||
PsiElement parent = expression.getParent();
|
||||
while (parent instanceof PsiParenthesizedExpression) {
|
||||
@@ -763,7 +763,11 @@ public class LambdaUtil {
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
final PsiElement gParent = parent.getParent();
|
||||
if (gParent instanceof PsiCallExpression) {
|
||||
myMethod = ((PsiCallExpression)gParent).resolveMethod();
|
||||
final Map<PsiElement, PsiMethod> map = MethodCandidateInfo.CURRENT_CANDIDATE.get();
|
||||
myMethod = map != null ? map.get(parent) : null;
|
||||
if (myMethod == null) {
|
||||
myMethod = ((PsiCallExpression)gParent).resolveMethod();
|
||||
}
|
||||
if (myMethod != null && PsiTreeUtil.isAncestor(myMethod, expression, false)) {
|
||||
myMethod = null;
|
||||
}
|
||||
|
||||
+10
-6
@@ -594,7 +594,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(PsiTypeParameter typeParam,
|
||||
private static Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(final PsiTypeParameter typeParam,
|
||||
final PsiMethodReferenceExpression methodReferenceExpression,
|
||||
final PsiType functionalInterfaceType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
@@ -607,6 +607,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
methodParamTypes[i] = subst.substitute(methodParameters[i].getType());
|
||||
}
|
||||
|
||||
if (methodParamsDependOn(typeParam, methodReferenceExpression, functionalInterfaceType, methodParameters, subst)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiType[] args = new PsiType[methodParameters.length];
|
||||
final PsiElement resolved = methodReferenceExpression.resolve();
|
||||
if (resolved instanceof PsiMethod) {
|
||||
@@ -698,12 +702,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean methodParamsDependOn(PsiTypeParameter typeParam, PsiLambdaExpression lambdaExpression,
|
||||
private static boolean methodParamsDependOn(PsiTypeParameter typeParam, PsiElement psiElement,
|
||||
PsiType functionalInterfaceType,
|
||||
PsiParameter[] methodParameters,
|
||||
PsiSubstitutor subst) {
|
||||
for (PsiParameter parameter : methodParameters) {
|
||||
if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), functionalInterfaceType, lambdaExpression, typeParam)) {
|
||||
if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), functionalInterfaceType, psiElement, typeParam)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -948,15 +952,15 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
final PsiExpressionList argumentList = methodCall.getArgumentList();
|
||||
if (argumentList != null && PsiUtil.getLanguageLevel(argumentList).isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
for (PsiExpression expression : argumentList.getExpressions()) {
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType((PsiLambdaExpression)expression, false);
|
||||
if (expression instanceof PsiLambdaExpression || expression instanceof PsiMethodReferenceExpression) {
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false);
|
||||
if (functionalInterfaceType == null || PsiUtil.resolveClassInType(functionalInterfaceType) == typeParameter){
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
}
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
if (method == null || methodParamsDependOn(typeParameter, (PsiLambdaExpression)expression,
|
||||
if (method == null || methodParamsDependOn(typeParameter, expression,
|
||||
functionalInterfaceType, method.getParameterList().getParameters(),
|
||||
LambdaUtil.getSubstitutor(method, resolveResult))) {
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
class MyTest<E> {
|
||||
MyTest(E e) {
|
||||
}
|
||||
|
||||
interface I<T> {
|
||||
MyTest<T> _(T t);
|
||||
}
|
||||
|
||||
static <Y> void bar(Y arg, I<Y> i) {
|
||||
i._(arg);
|
||||
}
|
||||
|
||||
static <Y> void bar(I<Y> i, Y arg) {
|
||||
i._(arg);
|
||||
}
|
||||
|
||||
static <Y> void bar(I<Y> i) {
|
||||
i._(null);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
I<String> i = MyTest::new;
|
||||
|
||||
bar("", MyTest<String>::new);
|
||||
bar("", MyTest::new);
|
||||
|
||||
bar(MyTest<String>::new, "");
|
||||
bar(MyTest::new, "");
|
||||
|
||||
bar(<error descr="Cyclic inference">MyTest::new</error>);
|
||||
bar(<error descr="Cyclic inference">MyTest<String>::new</error>);
|
||||
}
|
||||
}
|
||||
+4
@@ -93,6 +93,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCyclicInference() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReturnTypeSpecific() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user