overload resolution: treat default methods as abstract; don't include static interface methods in conflict resolution when target expression type does not correspond to the containing interface (IDEA-146055)

This commit is contained in:
Anna Kozlova
2015-10-07 18:58:49 +02:00
parent 6902845ec5
commit c000624704
4 changed files with 62 additions and 11 deletions

View File

@@ -403,6 +403,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
else if (expression == null && !ImportsUtil.hasStaticImportOn(parent, method, true)) {
return PsiTreeUtil.getParentOfType(parent, PsiClass.class);
}
if (expression != null) {
return PsiUtil.resolveClassInType(expression.getType());
}
}
return null;
}
@@ -616,23 +620,16 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
if (applicable12 && !applicable21) return Specifics.SECOND;
if (applicable21 && !applicable12) return Specifics.FIRST;
final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT);
final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT);
//from 15.12.2.5 Choosing the Most Specific Method: concrete = nonabstract or default
final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT) || method1.hasModifierProperty(PsiModifier.DEFAULT);
final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT) || method2.hasModifierProperty(PsiModifier.DEFAULT);
if (abstract1 && !abstract2) {
return Specifics.SECOND;
}
if (abstract2 && !abstract1) {
return Specifics.FIRST;
}
if (method1.hasModifierProperty(PsiModifier.DEFAULT) && method2.hasModifierProperty(PsiModifier.STATIC)) {
return Specifics.FIRST;
}
if (method2.hasModifierProperty(PsiModifier.DEFAULT) && method1.hasModifierProperty(PsiModifier.STATIC)) {
return Specifics.SECOND;
}
}
}
else if (varargsPosition) {

View File

@@ -0,0 +1,23 @@
interface A<T> {
void foo(T x);
default void foo(String x) { }
}
class C implements A<String> {
@Override
public void foo(String x) {
A.super.foo<error descr="Ambiguous method call: both 'A.foo(String)' and 'A.foo(String)' match">(x)</error>;
}
}
interface A2<T> {
Object foo(T x);
default Integer foo(String <warning descr="Parameter 'x' is never used">x</warning>) { return null; }
}
abstract class C2 {
public void foo(A2<String> x) {
x.foo<error descr="Ambiguous method call: both 'A2.foo(String)' and 'A2.foo(String)' match">("")</error>;
}
}

View File

@@ -13,6 +13,33 @@ class Test {
public static void main(String[] args) {
new IJ(). f();
new JI(). f();
IJ.<error descr="Non-static method 'f()' cannot be referenced from a static context">f</error>();
JI.<error descr="Non-static method 'f()' cannot be referenced from a static context">f</error>();
J.f();
}
}
class Test2 {
interface I {
static void f(String <warning descr="Parameter 's' is never used">s</warning>) {}
}
interface J<T> {
default void f(T <warning descr="Parameter 't' is never used">t</warning>) {}
//another pair
default void j(T <warning descr="Parameter 't' is never used">t</warning>) {}
static void j(String <warning descr="Parameter 's' is never used">s</warning>) {};
}
static class IJ implements I, J<String> {}
public static void main(IJ s, J<String> j) {
s.f("");
<error descr="Static method may be invoked on containing interface class only">j.j("");</error>
}
}

View File

@@ -89,6 +89,10 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testDefaultAbstractConflictResolution() throws Exception {
doTest();
}
public void testLambdaValueCompatibleWithNestedTryWithResources() throws Exception {
doTest(false);
}