mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 21:41:24 +07:00
lambda conflict resolve: check lambdas on per-params basis
This commit is contained in:
@@ -70,4 +70,8 @@ public class PsiLambdaExpressionType extends PsiType {
|
||||
public PsiType[] getSuperTypes() {
|
||||
return PsiType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
public PsiLambdaExpression getExpression() {
|
||||
return myExpression;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ public class LambdaUtil {
|
||||
|
||||
@Nullable
|
||||
public static MethodSignature getFunction(PsiClass psiClass) {
|
||||
if (psiClass == null) return null;
|
||||
final List<MethodSignature> functions = findFunctionCandidates(psiClass);
|
||||
if (functions != null && functions.size() == 1) {
|
||||
return functions.get(0);
|
||||
@@ -123,12 +124,9 @@ public class LambdaUtil {
|
||||
}
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
|
||||
final PsiClass psiClass = resolveResult.getElement();
|
||||
if (psiClass != null) {
|
||||
final MethodSignature methodSignature = getFunction(psiClass);
|
||||
if (methodSignature != null) {
|
||||
return resolveResult.getSubstitutor().substitute(methodSignature.getParameterTypes()[parameterIndex]);
|
||||
}
|
||||
final MethodSignature methodSignature = getFunction(resolveResult.getElement());
|
||||
if (methodSignature != null) {
|
||||
return resolveResult.getSubstitutor().substitute(methodSignature.getParameterTypes()[parameterIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
|
||||
import com.intellij.psi.impl.source.tree.java.LambdaUtil;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.scope.PsiConflictResolver;
|
||||
@@ -86,11 +87,49 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
checkPrimitiveVarargs(conflicts, myActualParameterTypes.length);
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
checkLambdaApplicable(conflicts);
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
THashSet<CandidateInfo> uniques = new THashSet<CandidateInfo>(conflicts);
|
||||
if (uniques.size() == 1) return uniques.iterator().next();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkLambdaApplicable(List<CandidateInfo> conflicts) {
|
||||
for (int i = 0; i < myActualParameterTypes.length; i++) {
|
||||
PsiType parameterType = myActualParameterTypes[i];
|
||||
if (parameterType instanceof PsiLambdaExpressionType) {
|
||||
final PsiLambdaExpression lambdaExpression = ((PsiLambdaExpressionType)parameterType).getExpression();
|
||||
final int parametersCount = lambdaExpression.getParameterList().getParametersCount();
|
||||
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext(); ) {
|
||||
final CandidateInfo conflict = iterator.next();
|
||||
final PsiMethod method = (PsiMethod)conflict.getElement();
|
||||
if (method != null) {
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
final PsiParameter param = i < methodParameters.length ? methodParameters[i] : methodParameters[methodParameters.length - 1];
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(param.getType());
|
||||
final MethodSignature function = LambdaUtil.getFunction(resolveResult.getElement());
|
||||
if (function != null && function.getParameterTypes().length == parametersCount) {
|
||||
boolean correctArgs = true;
|
||||
final PsiParameter[] lambdaParameters = lambdaExpression.getParameterList().getParameters();
|
||||
for (int lambdaParamIdx = 0, length = lambdaParameters.length; lambdaParamIdx < length; lambdaParamIdx++) {
|
||||
PsiParameter parameter = lambdaParameters[lambdaParamIdx];
|
||||
final PsiTypeElement typeElement = parameter.getTypeElement();
|
||||
if (typeElement != null) {
|
||||
if (!typeElement.getType().equals(resolveResult.getSubstitutor().substitute(function.getParameterTypes()[lambdaParamIdx]))) {
|
||||
correctArgs = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (correctArgs) continue;
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSpecifics(List<CandidateInfo> conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) {
|
||||
final boolean applicable = applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
interface I {
|
||||
void m(int i);
|
||||
}
|
||||
interface J {
|
||||
void mm(int i, int j);
|
||||
}
|
||||
interface K {
|
||||
void k(String m);
|
||||
}
|
||||
|
||||
class Foo {
|
||||
void foo(I i){}
|
||||
void foo(J j){}
|
||||
void foo(K k){}
|
||||
|
||||
void bar() {
|
||||
foo<error descr="Ambiguous method call: both 'Foo.foo(I)' and 'Foo.foo(K)' match">((p) -> {
|
||||
System.out.println(p);
|
||||
})</error>;
|
||||
|
||||
foo((p, k) -> {
|
||||
System.out.println(p);
|
||||
});
|
||||
|
||||
foo((String s) ->{
|
||||
System.out.println(s);
|
||||
});
|
||||
|
||||
<error descr="Cannot resolve method 'foo(<lambda expression>)'">foo</error>((String p, String k) -> {
|
||||
System.out.println(p);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class WithTypeParams {
|
||||
interface I<T> {
|
||||
void m(T t);
|
||||
}
|
||||
|
||||
interface J<K, V> {
|
||||
void n(K k, V v);
|
||||
}
|
||||
|
||||
class Foo {
|
||||
void foo(I<String> i){}
|
||||
void foo(J<String, String> j){}
|
||||
|
||||
void bar() {
|
||||
foo((p) -> {
|
||||
System.out.println(p);
|
||||
});
|
||||
|
||||
foo((p, k) -> {
|
||||
System.out.println(p);
|
||||
});
|
||||
|
||||
foo((String s) ->{
|
||||
System.out.println(s);
|
||||
});
|
||||
|
||||
foo((String p, String k) -> {
|
||||
System.out.println(p);
|
||||
});
|
||||
|
||||
<error descr="Cannot resolve method 'foo(<lambda expression>)'">foo</error>((int k) -> {System.out.println(k);});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,10 @@ public class LambdaParamsTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testMethodApplicability() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user