mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-22 06:21:25 +07:00
fix inheritance of abstract and default methods when multiple defaults are present
This commit is contained in:
@@ -446,7 +446,7 @@ public class GenericsHighlightUtil {
|
||||
for (Set<PsiMethod> overrideEquivalentMethods : overrideEquivalent.values()) {
|
||||
if (overrideEquivalentMethods.size() <= 1) continue;
|
||||
List<PsiMethod> defaults = null;
|
||||
List<PsiMethod> astracts = null;
|
||||
List<PsiMethod> abstracts = null;
|
||||
boolean hasConcrete = false;
|
||||
for (PsiMethod method : overrideEquivalentMethods) {
|
||||
final boolean isDefault = method.hasModifierProperty(PsiModifier.DEFAULT);
|
||||
@@ -456,8 +456,8 @@ public class GenericsHighlightUtil {
|
||||
defaults.add(method);
|
||||
}
|
||||
if (isAbstract) {
|
||||
if (astracts == null) astracts = new ArrayList<>(2);
|
||||
astracts.add(method);
|
||||
if (abstracts == null) abstracts = new ArrayList<>(2);
|
||||
abstracts.add(method);
|
||||
}
|
||||
hasConcrete |= !isDefault && !isAbstract;
|
||||
}
|
||||
@@ -466,37 +466,38 @@ public class GenericsHighlightUtil {
|
||||
final PsiMethod defaultMethod = defaults.get(0);
|
||||
final PsiClass defaultMethodContainingClass = defaultMethod.getContainingClass();
|
||||
if (defaultMethodContainingClass == null) continue;
|
||||
final PsiMethod unrelatedMethod = astracts != null ? astracts.get(0) : defaults.get(1);
|
||||
final PsiMethod unrelatedMethod = abstracts != null ? abstracts.get(0) : defaults.get(1);
|
||||
final PsiClass unrelatedMethodContainingClass = unrelatedMethod.getContainingClass();
|
||||
if (unrelatedMethodContainingClass == null) continue;
|
||||
if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !(aClass instanceof PsiTypeParameter)
|
||||
&& astracts != null && unrelatedMethodContainingClass.isInterface()) {
|
||||
&& abstracts != null && unrelatedMethodContainingClass.isInterface()) {
|
||||
if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) &&
|
||||
MethodSignatureUtil.isSubsignature(unrelatedMethod.getSignature(TypeConversionUtil.getSuperClassSubstitutor(unrelatedMethodContainingClass, defaultMethodContainingClass, PsiSubstitutor.EMPTY)),
|
||||
defaultMethod.getSignature(PsiSubstitutor.EMPTY))) {
|
||||
continue;
|
||||
}
|
||||
final String key = aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract";
|
||||
final String message = JavaErrorMessages.message(key, HighlightUtil.formatClass(aClass, false), JavaHighlightUtil.formatMethod(astracts.get(0)),
|
||||
final String message = JavaErrorMessages.message(key, HighlightUtil.formatClass(aClass, false), JavaHighlightUtil.formatMethod(abstracts.get(0)),
|
||||
HighlightUtil.formatClass(unrelatedMethodContainingClass, false));
|
||||
final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(message).create();
|
||||
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
|
||||
return info;
|
||||
}
|
||||
if (isInterface || astracts == null || unrelatedMethodContainingClass.isInterface()) {
|
||||
if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) ||
|
||||
unrelatedMethodContainingClass.isInheritor(defaultMethodContainingClass, true)) {
|
||||
if (isInterface || abstracts == null || unrelatedMethodContainingClass.isInterface()) {
|
||||
final List<PsiClass> defaultContainingClasses = ContainerUtil.mapNotNull(defaults, PsiMethod::getContainingClass);
|
||||
final String unrelatedDefaults = hasUnrelatedDefaults(defaultContainingClasses);
|
||||
if (unrelatedDefaults == null &&
|
||||
(abstracts == null || !hasNotOverriddenAbstract(defaultContainingClasses, unrelatedMethodContainingClass))) {
|
||||
continue;
|
||||
}
|
||||
final String message = astracts != null ? " inherits abstract and default for " : " inherits unrelated defaults for ";
|
||||
|
||||
final String message = unrelatedDefaults != null ? " inherits unrelated defaults for " : " inherits abstract and default for ";
|
||||
final HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(
|
||||
HighlightUtil.formatClass(aClass) +
|
||||
message +
|
||||
JavaHighlightUtil.formatMethod(defaultMethod) +
|
||||
" from types " +
|
||||
HighlightUtil.formatClass(defaultMethodContainingClass) +
|
||||
" and " +
|
||||
HighlightUtil.formatClass(unrelatedMethodContainingClass))
|
||||
JavaHighlightUtil.formatMethod(defaultMethod) + " from types " +
|
||||
(unrelatedDefaults != null ? unrelatedDefaults
|
||||
: HighlightUtil.formatClass(defaultMethodContainingClass) + " and " + HighlightUtil.formatClass(unrelatedMethodContainingClass)))
|
||||
.create();
|
||||
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createImplementMethodsFix(aClass));
|
||||
return info;
|
||||
@@ -506,6 +507,31 @@ public class GenericsHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean belongToOneHierarchy(@NotNull PsiClass defaultMethodContainingClass, @NotNull PsiClass unrelatedMethodContainingClass) {
|
||||
return defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) ||
|
||||
unrelatedMethodContainingClass.isInheritor(defaultMethodContainingClass, true);
|
||||
}
|
||||
|
||||
private static boolean hasNotOverriddenAbstract(List<PsiClass> defaultContainingClasses, @NotNull PsiClass abstractMethodContainingClass) {
|
||||
return !defaultContainingClasses.stream().anyMatch(containingClass -> belongToOneHierarchy(containingClass, abstractMethodContainingClass));
|
||||
}
|
||||
|
||||
private static String hasUnrelatedDefaults(List<PsiClass> defaults) {
|
||||
if (defaults.size() > 1) {
|
||||
for (int i = 0; i < defaults.size(); i++) {
|
||||
final PsiClass aClass1 = defaults.get(i);
|
||||
for (int j = i + 1; j < defaults.size(); j++) {
|
||||
final PsiClass aClass2 = defaults.get(j);
|
||||
if (aClass2 != null && !belongToOneHierarchy(aClass1, aClass2)) {
|
||||
return HighlightUtil.formatClass(aClass1) + " and " + HighlightUtil.formatClass(aClass2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo checkUnrelatedConcrete(@NotNull PsiClass psiClass,
|
||||
@NotNull PsiIdentifier classIdentifier) {
|
||||
final PsiClass superClass = psiClass.getSuperClass();
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
interface I {
|
||||
void foo();
|
||||
}
|
||||
|
||||
interface I1 extends I {
|
||||
//void foo();
|
||||
}
|
||||
|
||||
interface J {
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface A extends J, I {
|
||||
@Override
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface O extends J {
|
||||
}
|
||||
|
||||
interface R extends O, A, I1{}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
interface I {
|
||||
void foo();
|
||||
}
|
||||
|
||||
interface I1 extends I {
|
||||
}
|
||||
|
||||
interface J {
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface A extends J, I {
|
||||
@Override
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface O extends J {
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface <error descr="R inherits unrelated defaults for foo() from types O and A">R</error> extends O, A, I1{}
|
||||
@@ -107,6 +107,14 @@ public class Interface8MethodsHighlightingTest extends LightCodeInsightFixtureTe
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUnrelatedDefaultsWhenAbstractIsOverridden() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAbstractOverriddenBySecondDefault() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user