lambda: do not skip generic method when non-generic method exist in the same class

This commit is contained in:
Anna Kozlova
2014-04-22 20:02:52 +02:00
parent 7d74b9dcf1
commit 8bad8079f6
4 changed files with 50 additions and 13 deletions
@@ -36,7 +36,7 @@ public class LambdaHighlightingUtil {
@Nullable
public static String checkInterfaceFunctional(@NotNull PsiClass psiClass, String interfaceNonFunctionalMessage) {
if (psiClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
final List<MethodSignature> signatures = LambdaUtil.findFunctionCandidates(psiClass);
final List<HierarchicalMethodSignature> signatures = LambdaUtil.findFunctionCandidates(psiClass);
if (signatures == null) return interfaceNonFunctionalMessage;
if (signatures.isEmpty()) return "No target method found";
if (signatures.size() == 1) {
@@ -113,7 +113,7 @@ public class LambdaHighlightingUtil {
final PsiClass aClass = resolveResult.getElement();
if (aClass != null) {
if (aClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
final List<MethodSignature> signatures = LambdaUtil.findFunctionCandidates(aClass);
final List<HierarchicalMethodSignature> signatures = LambdaUtil.findFunctionCandidates(aClass);
if (signatures != null && signatures.size() == 1) {
final MethodSignature functionalMethod = signatures.get(0);
if (functionalMethod.getTypeParameters().length > 0) return "Target method is generic";
@@ -112,7 +112,7 @@ public class LambdaUtil {
public static boolean isFunctionalClass(PsiClass aClass) {
if (aClass != null) {
if (aClass instanceof PsiTypeParameter) return false;
final List<MethodSignature> signatures = findFunctionCandidates(aClass);
final List<HierarchicalMethodSignature> signatures = findFunctionCandidates(aClass);
return signatures != null && signatures.size() == 1;
}
return false;
@@ -142,7 +142,7 @@ public class LambdaUtil {
@Nullable
static MethodSignature getFunction(PsiClass psiClass) {
if (psiClass == null) return null;
final List<MethodSignature> functions = findFunctionCandidates(psiClass);
final List<HierarchicalMethodSignature> functions = findFunctionCandidates(psiClass);
if (functions != null && functions.size() == 1) {
return functions.get(0);
}
@@ -176,13 +176,13 @@ public class LambdaUtil {
}
@Nullable
private static List<MethodSignature> hasSubsignature(List<MethodSignature> signatures) {
for (MethodSignature signature : signatures) {
private static List<HierarchicalMethodSignature> hasSubsignature(List<HierarchicalMethodSignature> signatures) {
for (HierarchicalMethodSignature signature : signatures) {
boolean subsignature = true;
for (MethodSignature methodSignature : signatures) {
for (HierarchicalMethodSignature methodSignature : signatures) {
if (!signature.equals(methodSignature)) {
if (!MethodSignatureUtil.isSubsignature(signature, methodSignature) &&
methodSignature.getTypeParameters().length == 0) {
if (!MethodSignatureUtil.isSubsignature(signature, methodSignature) &&
!skipMethod(signature, methodSignature)) {
subsignature = false;
break;
}
@@ -193,10 +193,20 @@ public class LambdaUtil {
return signatures;
}
private static boolean skipMethod(HierarchicalMethodSignature signature,
HierarchicalMethodSignature methodSignature) {
//not generic
if (methodSignature.getTypeParameters().length == 0) {
return false;
}
//foreign class
return signature.getMethod().getContainingClass() != methodSignature.getMethod().getContainingClass();
}
@Nullable
public static List<MethodSignature> findFunctionCandidates(PsiClass psiClass) {
public static List<HierarchicalMethodSignature> findFunctionCandidates(PsiClass psiClass) {
if (psiClass != null && psiClass.isInterface() && !psiClass.isAnnotationType()) {
final List<MethodSignature> methods = new ArrayList<MethodSignature>();
final List<HierarchicalMethodSignature> methods = new ArrayList<HierarchicalMethodSignature>();
final Collection<HierarchicalMethodSignature> visibleSignatures = psiClass.getVisibleSignatures();
for (HierarchicalMethodSignature signature : visibleSignatures) {
final PsiMethod psiMethod = signature.getMethod();
@@ -364,7 +374,7 @@ public class LambdaUtil {
@Nullable
private static PsiType extractFunctionalConjunct(PsiIntersectionType type) {
PsiType conjunct = null;
for (PsiType conjunctType : ((PsiIntersectionType)type).getConjuncts()) {
for (PsiType conjunctType : type.getConjuncts()) {
final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(conjunctType);
if (interfaceMethod != null) {
if (conjunct != null && !conjunct.equals(conjunctType)) return null;
@@ -14,3 +14,30 @@ class Test {
C c = ()-> {};
}
}
class Test1 {
interface F {
<X> void m();
}
{
F f = this::g;
}
void g() {}
}
class Test2 {
interface F {
<X> void m();
void a();
}
{
F f = <error descr="Multiple non-overriding abstract methods found">() -> g()</error>;
}
void g() {}
}
@@ -75,7 +75,7 @@ public class InterfaceMayBeAnnotatedFunctionalInspection extends BaseInspection
if (LambdaHighlightingUtil.checkInterfaceFunctional(aClass) != null) {
return;
}
final List<MethodSignature> candidates = LambdaUtil.findFunctionCandidates(aClass);
final List<HierarchicalMethodSignature> candidates = LambdaUtil.findFunctionCandidates(aClass);
if (candidates == null || candidates.size() != 1) {
return;
}