process override equivalent methods when check for functional interface target (IDEA-153324)

This commit is contained in:
Anna.Kozlova
2016-03-21 11:11:42 +01:00
parent f89cc74e3d
commit 3a700a9bc9
6 changed files with 90 additions and 56 deletions

View File

@@ -35,7 +35,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.ReferencesSearch;
@@ -442,36 +441,7 @@ public class GenericsHighlightUtil {
static HighlightInfo checkUnrelatedDefaultMethods(@NotNull PsiClass aClass,
@NotNull PsiIdentifier classIdentifier) {
final Map<MethodSignature, Set<PsiMethod>> overrideEquivalent =
new THashMap<MethodSignature, Set<PsiMethod>>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
PsiClass[] supers = aClass.getSupers();
for (int i = 0; i < supers.length; i++) {
PsiClass superClass = supers[i];
boolean subType = false;
for (int j = 0; j < supers.length; j++) {
if (j == i) continue;
subType |= supers[j].isInheritor(supers[i], true);
}
if (subType) continue;
final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) {
final PsiMethod method = hms.getMethod();
if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null) continue;
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) continue;
final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY);
if (containingClassSubstitutor == null) continue;
final PsiSubstitutor finalSubstitutor =
PsiSuperMethodImplUtil.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false);
final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false);
Set<PsiMethod> methods = overrideEquivalent.get(signature);
if (methods == null) {
methods = new LinkedHashSet<PsiMethod>();
overrideEquivalent.put(signature, methods);
}
methods.add(method);
}
}
final Map<? extends MethodSignature, Set<PsiMethod>> overrideEquivalent = PsiSuperMethodUtil.collectOverrideEquivalents(aClass);
final boolean isInterface = aClass.isInterface();
for (Set<PsiMethod> overrideEquivalentMethods : overrideEquivalent.values()) {
@@ -550,7 +520,8 @@ public class GenericsHighlightUtil {
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) continue;
final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, psiClass, PsiSubstitutor.EMPTY);
final PsiSubstitutor finalSubstitutor = PsiSuperMethodImplUtil.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false);
final PsiSubstitutor finalSubstitutor = PsiSuperMethodUtil
.obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false);
final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false);
final PsiMethod foundMethod = overrideEquivalent.get(signature);
PsiClass foundMethodContainingClass;

View File

@@ -216,11 +216,23 @@ public class LambdaUtil {
public static List<HierarchicalMethodSignature> findFunctionCandidates(PsiClass psiClass) {
if (psiClass != null && psiClass.isInterface() && !psiClass.isAnnotationType()) {
final List<HierarchicalMethodSignature> methods = new ArrayList<HierarchicalMethodSignature>();
final Map<MethodSignature, Set<PsiMethod>> overrideEquivalents = PsiSuperMethodUtil.collectOverrideEquivalents(psiClass);
final Collection<HierarchicalMethodSignature> visibleSignatures = psiClass.getVisibleSignatures();
for (HierarchicalMethodSignature signature : visibleSignatures) {
final PsiMethod psiMethod = signature.getMethod();
if (!psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) continue;
if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) continue;
final Set<PsiMethod> equivalentMethods = overrideEquivalents.get(signature);
if (equivalentMethods != null && equivalentMethods.size() > 1) {
boolean hasNonAbstractOverrideEquivalent = false;
for (PsiMethod method : equivalentMethods) {
if (!method.hasModifierProperty(PsiModifier.ABSTRACT) && !MethodSignatureUtil.isSuperMethod(method, psiMethod)) {
hasNonAbstractOverrideEquivalent = true;
break;
}
}
if (hasNonAbstractOverrideEquivalent) continue;
}
if (!overridesPublicObjectMethod(signature)) {
methods.add(signature);
}

View File

@@ -17,10 +17,13 @@ package com.intellij.psi.util;
import com.intellij.psi.*;
import com.intellij.util.containers.HashSet;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PsiSuperMethodUtil {
@@ -80,4 +83,62 @@ public class PsiSuperMethodUtil {
return false;
}
@NotNull
public static PsiSubstitutor obtainFinalSubstitutor(@NotNull PsiClass superClass,
@NotNull PsiSubstitutor superSubstitutor,
@NotNull PsiSubstitutor derivedSubstitutor,
boolean inRawContext) {
if (inRawContext) {
Set<PsiTypeParameter> typeParams = superSubstitutor.getSubstitutionMap().keySet();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject());
superSubstitutor = factory.createRawSubstitutor(derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()]));
}
Map<PsiTypeParameter, PsiType> map = null;
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) {
PsiType type = superSubstitutor.substitute(typeParameter);
final PsiType t = derivedSubstitutor.substitute(type);
if (map == null) {
map = new THashMap<PsiTypeParameter, PsiType>();
}
map.put(typeParameter, t);
}
return map == null ? PsiSubstitutor.EMPTY : JavaPsiFacade.getInstance(superClass.getProject()).getElementFactory().createSubstitutor(map);
}
@NotNull
public static Map<MethodSignature, Set<PsiMethod>> collectOverrideEquivalents(@NotNull PsiClass aClass) {
final Map<MethodSignature, Set<PsiMethod>> overrideEquivalent =
new THashMap<MethodSignature, Set<PsiMethod>>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
PsiClass[] supers = aClass.getSupers();
for (int i = 0; i < supers.length; i++) {
PsiClass superClass = supers[i];
boolean subType = false;
for (int j = 0; j < supers.length; j++) {
if (j == i) continue;
subType |= supers[j].isInheritor(supers[i], true);
}
if (subType) continue;
final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
for (HierarchicalMethodSignature hms : superClass.getVisibleSignatures()) {
final PsiMethod method = hms.getMethod();
if (MethodSignatureUtil.findMethodBySignature(aClass, method.getSignature(superClassSubstitutor), false) != null) continue;
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) continue;
final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY);
if (containingClassSubstitutor == null) continue;
final PsiSubstitutor finalSubstitutor =
obtainFinalSubstitutor(containingClass, containingClassSubstitutor, hms.getSubstitutor(), false);
final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, finalSubstitutor, false);
Set<PsiMethod> methods = overrideEquivalent.get(signature);
if (methods == null) {
methods = new LinkedHashSet<PsiMethod>();
overrideEquivalent.put(signature, methods);
}
methods.add(method);
}
}
return overrideEquivalent;
}
}

View File

@@ -229,7 +229,7 @@ public class PsiSuperMethodImplUtil {
if (superClass == null) continue;
if (!visited.add(superClass)) continue; // cyclic inheritance
final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor();
PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext);
PsiSubstitutor finalSubstitutor = PsiSuperMethodUtil.obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext);
final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0;
Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, nameHint, finalSubstitutor, false, visited, isInRawContextSuper, resolveScope);
@@ -373,29 +373,6 @@ public class PsiSuperMethodImplUtil {
return hierarchicalMethodSignature;
}
@NotNull
public static PsiSubstitutor obtainFinalSubstitutor(@NotNull PsiClass superClass,
@NotNull PsiSubstitutor superSubstitutor,
@NotNull PsiSubstitutor derivedSubstitutor,
boolean inRawContext) {
if (inRawContext) {
Set<PsiTypeParameter> typeParams = superSubstitutor.getSubstitutionMap().keySet();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject());
superSubstitutor = factory.createRawSubstitutor(derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()]));
}
Map<PsiTypeParameter, PsiType> map = null;
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) {
PsiType type = superSubstitutor.substitute(typeParameter);
final PsiType t = derivedSubstitutor.substitute(type);
if (map == null) {
map = new THashMap<PsiTypeParameter, PsiType>();
}
map.put(typeParameter, t);
}
return map == null ? PsiSubstitutor.EMPTY : JavaPsiFacade.getInstance(superClass.getProject()).getElementFactory().createSubstitutor(map);
}
@NotNull
public static Collection<HierarchicalMethodSignature> getVisibleSignatures(@NotNull PsiClass aClass) {
Map<MethodSignature, HierarchicalMethodSignature> map = getSignaturesMap(aClass);

View File

@@ -0,0 +1,12 @@
import java.util.*;
@FunctionalInterface
interface InfiniteIntIterator extends InfiniteIterator<Integer>, PrimitiveIterator.OfInt {}
@FunctionalInterface
interface InfiniteIterator<T> extends Iterator<T> {
@Override
default boolean hasNext() {
return true;
}
}

View File

@@ -30,6 +30,7 @@ public class Interface8MethodsHighlightingTest extends LightCodeInsightFixtureTe
public void testInheritUnrelatedDefaults() { doTest(true, false); }
public void testExtensionMethods() { doTest(false, false); }
public void testInheritDefaultMethodInInterface() { doTest(false, false); }
public void testCheckForFunctionalInterfaceCandidatesWhenOverrideEquivalentMethodsAreFoundInSuperInterfaces() { doTest(false, false);}
public void testStaticMethodsInFunctionalInterface() { doTest(false, false); }
public void testCyclicSubstitutor() { doTest(false, false); }
public void testThisAccessibility() { doTest(false, false); }