inherit unrelated abstract/default through hierarchy: don't merge methods with not override equivalent signatures (IDEA-146135)

This commit is contained in:
Anna Kozlova
2016-01-07 16:06:39 +01:00
parent df3e5be8cb
commit 99e4c75ee7
3 changed files with 96 additions and 3 deletions
@@ -457,8 +457,8 @@ public class GenericsHighlightUtil {
if (aClass.findMethodsBySignature(method, false).length > 0) continue;
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) continue;
final PsiSubstitutor containingClassSubstitutor =
TypeConversionUtil.getSuperClassSubstitutor(containingClass, aClass, PsiSubstitutor.EMPTY);
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);
@@ -499,7 +499,11 @@ public class GenericsHighlightUtil {
final PsiClass unrelatedMethodContainingClass = unrelatedMethod.getContainingClass();
if (unrelatedMethodContainingClass == null) continue;
if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT) && astracts != null && unrelatedMethodContainingClass.isInterface()) {
if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true)) continue;
if (defaultMethodContainingClass.isInheritor(unrelatedMethodContainingClass, true) &&
MethodSignatureUtil.isSubsignature(unrelatedMethod.getSignature(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)),
HighlightUtil.formatClass(unrelatedMethodContainingClass, false));
@@ -0,0 +1,85 @@
class Test1 {
interface A {
void foo(String x);
}
interface C<T> extends A {
default void foo(T x) { }
}
class <error descr="Class 'D' must either be declared abstract or implement abstract method 'foo(String)' in 'A'">D</error> implements C<String> { }
interface E extends C<String> { }
}
class Test2 {
interface A {
default void foo(String x) {}
}
interface C<T> extends A {
void foo(T x);
}
<error descr="Class 'D' must either be declared abstract or implement abstract method 'foo(T)' in 'C'">class <error descr="Class 'D' must either be declared abstract or implement abstract method 'foo(T)' in 'C'">D</error> implements C<String></error> {}
interface E extends C<String> {}
}
class Test3 {
interface A {
default void foo(String x) {}
}
interface C<T> extends A {
default void foo(T x) {}
}
class D implements C<String> { }
interface E extends C<String> { }
}
class Test4 {
interface A {
void foo(String x);
}
interface C<T> extends A {
void foo(T x);
}
abstract class D implements C<String>, A { }
interface E extends C<String>, A {}
}
class Test5 {
interface A {
void foo(String x);
}
abstract class B implements A { }
interface C<T> extends A {
default void foo(T x) { }
}
class <error descr="Class 'D' must either be declared abstract or implement abstract method 'foo(String)' in 'A'">D</error> extends B implements C<String> { }
}
class Test6 {
interface A {
default void foo(String s) { }
}
interface B extends A {}
interface C<T> extends A {
default void foo(T t) {}
}
abstract static class D implements C<String>, B { }
static class E extends D {}
}
@@ -93,6 +93,10 @@ public class Interface8MethodsHighlightingTest extends LightCodeInsightFixtureTe
doTest();
}
public void testSubsignatureCheckWhen2DifferentMethodsBecomeOverrideEquivalent() throws Exception {
doTest();
}
private void doTest() {
doTest(false, false);
}