diff --git a/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java b/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java index 4a31d7b16555..530ac9c2128f 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java @@ -70,4 +70,8 @@ public class PsiLambdaExpressionType extends PsiType { public PsiType[] getSuperTypes() { return PsiType.EMPTY_ARRAY; } + + public PsiLambdaExpression getExpression() { + return myExpression; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/LambdaUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/LambdaUtil.java index b21b29f1c0ca..87743e188a4f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/LambdaUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/LambdaUtil.java @@ -99,6 +99,7 @@ public class LambdaUtil { @Nullable public static MethodSignature getFunction(PsiClass psiClass) { + if (psiClass == null) return null; final List 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]); } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 36a90378509d..a3d48972fbe6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -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 uniques = new THashSet(conflicts); if (uniques.size() == 1) return uniques.iterator().next(); return null; } + private void checkLambdaApplicable(List 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 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 conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) { final boolean applicable = applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/MethodApplicability.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/MethodApplicability.java new file mode 100644 index 000000000000..9c779b8081c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/params/MethodApplicability.java @@ -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((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); + }); + } +} + +class WithTypeParams { + interface I { + void m(T t); + } + + interface J { + void n(K k, V v); + } + + class Foo { + void foo(I i){} + void foo(J 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); + }); + + foo((int k) -> {System.out.println(k);}); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java index dabd86927b1c..6eba6532c120 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LambdaParamsTest.java @@ -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); }