method refs: check more specific by return type; check used method in test via unused symbol inspection

This commit is contained in:
anna
2012-10-02 21:15:29 +02:00
parent 55c8b4db6c
commit cf0e5a1051
3 changed files with 146 additions and 8 deletions
@@ -679,10 +679,12 @@ public class LambdaUtil {
assert conflict != method;
final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict);
if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) {
if (TypeConversionUtil.isAssignable(interfaceReturnType, interfaceReturnType1)) {
int moreSpecific = isMoreSpecific(interfaceReturnType, interfaceReturnType1);
if (moreSpecific > 0) {
conflicts.remove(method);
break;
} else if (TypeConversionUtil.isAssignable(interfaceReturnType1, interfaceReturnType)) {
}
else if (moreSpecific < 0) {
conflicts.remove(conflict);
}
}
@@ -690,6 +692,46 @@ public class LambdaUtil {
}
}
private static int isMoreSpecific(PsiType returnType, PsiType returnType1) {
final PsiClassType.ClassResolveResult r = PsiUtil.resolveGenericsClassInType(returnType);
final PsiClass rClass = r.getElement();
final PsiClassType.ClassResolveResult r1 = PsiUtil.resolveGenericsClassInType(returnType1);
final PsiClass rClass1 = r1.getElement();
if (rClass != null && rClass1 != null) {
if (rClass == rClass1) {
int moreSpecific = 0;
for (PsiTypeParameter parameter : rClass.getTypeParameters()) {
final PsiType t = r.getSubstitutor().substituteWithBoundsPromotion(parameter);
final PsiType t1 = r1.getSubstitutor().substituteWithBoundsPromotion(parameter);
if (t == null || t1 == null) continue;
if (t1.isAssignableFrom(t) && !GenericsUtil.eliminateWildcards(t1).equals(t)) {
if (moreSpecific == 1) {
return 0;
}
moreSpecific = -1;
}
else if (t.isAssignableFrom(t1) && !GenericsUtil.eliminateWildcards(t).equals(t1)) {
if (moreSpecific == -1) {
return 0;
}
moreSpecific = 1;
}
else {
return 0;
}
}
return moreSpecific;
}
else if (rClass1.isInheritor(rClass, true)) {
return 1;
}
else if (rClass.isInheritor(rClass1, true)) {
return -1;
}
}
return 0;
}
@Nullable
private static PsiType getReturnType(int functionalTypeIdx, CandidateInfo method) {
final PsiParameter[] methodParameters = ((PsiMethod)method.getElement()).getParameterList().getParameters();
@@ -16,11 +16,94 @@ class MyTest {
Object m(Foo<Integer> f);
}
static void foo(I1 i) {}
static void foo(I2 i) {}
static void foo(I3 i) {}
private static void <warning descr="Private method 'foo(MyTest.I1)' is never used">foo</warning>(I1 i) {
System.out.println(i);
}
static {
private static void foo(I2 i) {
System.out.println(i);
}
private static void <warning descr="Private method 'foo(MyTest.I3)' is never used">foo</warning>(I3 i) {
System.out.println(i);
}
public static void main(String[] args) {
foo(Foo::m);
}
}
class MyTest1 {
interface I1 {
Foo<?> m(String s);
}
interface I2 {
Foo<?> m(Integer i);
}
interface I3 {
Foo<Number> m(Integer i);
}
static class Foo<T extends Number> {
Foo(T t) {
System.out.println(t);
}
}
private static void <warning descr="Private method 'm(MyTest1.I1)' is never used">m</warning>(I1 i) {
System.out.println(i);
}
private static void m(I2 i) {
System.out.println(i);
}
private static void <warning descr="Private method 'm(MyTest1.I3)' is never used">m</warning>(I3 i) {
System.out.println(i);
}
public static void main(String[] args) {
m(Foo::new);
}
}
class MyTest2 {
interface I1 {
Foo<?> m(String s);
}
interface I2 {
Foo<Integer> m(Integer i);
}
interface I3 {
Foo<Number> m(Integer i);
}
static class Foo<T extends Number> {
Foo(T t) {
System.out.println(t);
}
}
private static void <warning descr="Private method 'm(MyTest2.I1)' is never used">m</warning>(I1 i) {
System.out.println(i);
}
private static void m(I2 i) {
System.out.println(i);
}
private static void <warning descr="Private method 'm(MyTest2.I3)' is never used">m</warning>(I3 i) {
System.out.println(i);
}
public static void main(String[] args) {
m(Foo::new);
}
}
@@ -16,11 +16,20 @@
package com.intellij.codeInsight.daemon.lambda;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
import org.jetbrains.annotations.NonNls;
public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
@NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/methodRef";
@Override
protected LocalInspectionTool[] configureLocalInspectionTools() {
return new LocalInspectionTool[]{
new UnusedSymbolLocalInspection(),
};
}
public void testValidContext() throws Exception {
doTest();
}
@@ -82,10 +91,14 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
}
public void testReturnTypeSpecific() throws Exception {
doTest();
doTest(true);
}
private void doTest() throws Exception {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
doTest(false);
}
private void doTest(final boolean warnings) throws Exception {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
}
}