mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 05:21:29 +07:00
process override equivalent methods when check for functional interface target (IDEA-153324)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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); }
|
||||
|
||||
Reference in New Issue
Block a user